Merge remote-tracking branch 'asoc/topic/wm0010' into asoc-next
authorMark Brown <broonie@linaro.org>
Thu, 22 Aug 2013 13:28:57 +0000 (14:28 +0100)
committerMark Brown <broonie@linaro.org>
Thu, 22 Aug 2013 13:28:57 +0000 (14:28 +0100)
888 files changed:
.gitignore
Documentation/DocBook/device-drivers.tmpl
Documentation/DocBook/media_api.tmpl
Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
Documentation/devicetree/bindings/misc/atmel-ssc.txt
Documentation/devicetree/bindings/regulator/palmas-pmic.txt
Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ak4554.c [new file with mode: 0644]
Documentation/devicetree/bindings/sound/alc5632.txt
Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/atmel-wm8904.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,spdif.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,ssi.txt [moved from Documentation/devicetree/bindings/powerpc/fsl/ssi.txt with 87% similarity]
Documentation/devicetree/bindings/sound/imx-audmux.txt
Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt
Documentation/devicetree/bindings/sound/pcm1792a.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/rt5640.txt
Documentation/devicetree/bindings/sound/samsung-i2s.txt
Documentation/devicetree/bindings/sound/soc-ac97link.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/ti,pcm1681.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/wm8731.txt
Documentation/devicetree/bindings/sound/wm8903.txt
Documentation/sysctl/net.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/arc/include/asm/entry.h
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/msm8960-cdp.dts
arch/arm/boot/dts/omap5-uevm.dts
arch/arm/boot/dts/stih41x.dtsi
arch/arm/boot/dts/tegra20-colibri-512.dtsi
arch/arm/include/asm/a.out-core.h [deleted file]
arch/arm/include/asm/cputype.h
arch/arm/include/asm/elf.h
arch/arm/include/asm/mmu.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/page.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/smp_plat.h
arch/arm/include/asm/spinlock.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlb.h
arch/arm/include/asm/tlbflush.h
arch/arm/include/asm/virt.h
arch/arm/include/uapi/asm/Kbuild
arch/arm/include/uapi/asm/a.out.h [deleted file]
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-v7m.S
arch/arm/kernel/fiq.c
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/hyp-stub.S
arch/arm/kernel/machine_kexec.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/process.c
arch/arm/kernel/setup.c
arch/arm/kernel/signal.c
arch/arm/kernel/signal.h [deleted file]
arch/arm/kernel/smp.c
arch/arm/kernel/smp_tlb.c
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-dove/common.c
arch/arm/mach-kirkwood/common.c
arch/arm/mach-msm/Kconfig
arch/arm/mach-msm/gpiomux-v1.c [deleted file]
arch/arm/mach-msm/gpiomux.h
arch/arm/mach-omap2/dss-common.c
arch/arm/mach-omap2/omap_device.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_2xxx_ipblock_data.c
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_hwmod_54xx_data.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-bockw.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-sti/headsmp.S
arch/arm/mm/Kconfig
arch/arm/mm/context.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-2level.S
arch/arm/mm/proc-v7-3level.S
arch/arm/mm/proc-v7.S
arch/arm/plat-pxa/ssp.c
arch/arm/xen/enlighten.c
arch/arm64/include/asm/tlb.h
arch/avr32/boards/atngw100/mrmt.c
arch/hexagon/Kconfig
arch/ia64/configs/generic_defconfig
arch/ia64/configs/gensparse_defconfig
arch/ia64/configs/tiger_defconfig
arch/ia64/configs/xen_domu_defconfig
arch/ia64/include/asm/tlb.h
arch/m68k/emu/natfeat.c
arch/m68k/include/asm/div64.h
arch/microblaze/Kconfig
arch/mips/Kconfig
arch/mips/bcm47xx/Kconfig
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/mach-generic/spaces.h
arch/mips/include/uapi/asm/siginfo.h
arch/mips/kernel/bmips_vec.S
arch/mips/kernel/smp-bmips.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pnx833x/common/platform.c
arch/mips/powertv/asic/asic_devices.c
arch/openrisc/Kconfig
arch/parisc/configs/c8000_defconfig [new file with mode: 0644]
arch/parisc/include/asm/parisc-device.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/inventory.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/signal32.c
arch/parisc/kernel/sys32.h [deleted file]
arch/parisc/kernel/sys_parisc32.c
arch/powerpc/Kconfig
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/ppc64e_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/perf_event_server.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/switch_to.h
arch/powerpc/include/uapi/asm/Kbuild
arch/powerpc/include/uapi/asm/perf_event.h [new file with mode: 0644]
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/tm.S
arch/powerpc/kernel/traps.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/mm/numa.c
arch/powerpc/perf/core-book3s.c
arch/powerpc/perf/power8-pmu.c
arch/powerpc/platforms/pseries/nvram.c
arch/s390/Kconfig
arch/s390/boot/compressed/Makefile
arch/s390/boot/compressed/misc.c
arch/s390/include/asm/bitops.h
arch/s390/include/asm/tlb.h
arch/s390/kernel/perf_event.c
arch/s390/kernel/setup.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/mm/init.c
arch/s390/oprofile/init.c
arch/score/Kconfig
arch/sh/configs/sh03_defconfig
arch/sh/include/asm/tlb.h
arch/um/include/asm/tlb.h
arch/x86/boot/compressed/eboot.c
arch/x86/include/asm/pgtable-2level.h
arch/x86/include/asm/pgtable-3level.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/spinlock.h
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/i387.c
arch/x86/kernel/microcode_amd.c
arch/x86/kernel/sys_x86_64.c
arch/x86/mm/mmap.c
arch/x86/platform/ce4100/ce4100.c
drivers/accessibility/braille/braille_console.c
drivers/acpi/acpi_processor.c
drivers/acpi/battery.c
drivers/acpi/glue.c
drivers/acpi/proc.c
drivers/acpi/video.c
drivers/ata/pata_imx.c
drivers/base/regmap/regcache.c
drivers/block/aoe/aoecmd.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/char/agp/parisc-agp.c
drivers/char/virtio_console.c
drivers/clk/samsung/clk-exynos4.c
drivers/clk/zynq/clkc.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/cpufreq_governor.c
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_ondemand.c
drivers/cpufreq/loongson2_cpufreq.c
drivers/cpuidle/governors/menu.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/sh/shdma.c
drivers/firewire/core-cdev.c
drivers/firewire/ohci.c
drivers/firmware/dmi_scan.c
drivers/gpio/gpio-msm-v1.c
drivers/gpio/gpio-omap.c
drivers/gpu/drm/ast/ast_ttm.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/exynos/exynos_ddc.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.c
drivers/gpu/drm/exynos/exynos_drm_ipp.c
drivers/gpu/drm/exynos/exynos_drm_rotator.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_hdmiphy.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
drivers/gpu/drm/nouveau/core/engine/xtensa.c
drivers/gpu/drm/nouveau/core/include/subdev/vm.h
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
drivers/gpu/drm/nouveau/core/subdev/vm/base.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nv17_fence.c
drivers/gpu/drm/nouveau/nv50_fence.c
drivers/gpu/drm/radeon/atom.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cypress_dpm.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_hdmi.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-dj.h
drivers/hid/hid-sony.c
drivers/hid/hidraw.c
drivers/hwmon/adt7470.c
drivers/hwmon/max6697.c
drivers/i2c/busses/i2c-kempld.c
drivers/i2c/busses/i2c-mxs.c
drivers/iio/adc/ti_am335x_adc.c
drivers/iio/industrialio-trigger.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/mad.c
drivers/infiniband/hw/cxgb3/iwch_provider.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_verbs.c
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_sdma.c
drivers/infiniband/ulp/ipoib/ipoib_ib.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_netlink.c
drivers/macintosh/windfarm_rm31.c
drivers/media/i2c/ml86v7667.c
drivers/media/platform/coda.c
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/usb/em28xx/em28xx-i2c.c
drivers/media/usb/hdpvr/hdpvr-core.c
drivers/media/usb/usbtv/Kconfig
drivers/media/usb/usbtv/usbtv.c
drivers/net/arcnet/arcnet.c
drivers/net/bonding/bond_main.c
drivers/net/can/usb/esd_usb2.c
drivers/net/can/usb/peak_usb/pcan_usb.c
drivers/net/can/usb/usb_8dev.c
drivers/net/ethernet/allwinner/Kconfig
drivers/net/ethernet/arc/emac_main.c
drivers/net/ethernet/atheros/atl1c/atl1c.h
drivers/net/ethernet/atheros/atl1c/atl1c_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/chelsio/cxgb3/sge.c
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_82598.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/fw.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/fw.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c
drivers/net/ethernet/mellanox/mlx5/core/uar.c
drivers/net/ethernet/oki-semi/pch_gbe/Kconfig
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
drivers/net/ethernet/realtek/8139cp.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/filter.c
drivers/net/ethernet/sis/sis900.c
drivers/net/ethernet/stmicro/stmmac/ring_mode.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/via/via-velocity.c
drivers/net/macvlan.c
drivers/net/macvtap.c
drivers/net/phy/mdio-sun4i.c
drivers/net/tun.c
drivers/net/usb/ax88179_178a.c
drivers/net/usb/r8152.c
drivers/net/usb/r815x.c
drivers/net/usb/smsc75xx.c
drivers/net/veth.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath10k/Kconfig
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wil6210/debugfs.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/cw1200/sta.c
drivers/net/wireless/cw1200/txrx.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cfp.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/Makefile
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/base.h
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/debug.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/ps.h
drivers/net/wireless/rtlwifi/usb.c
drivers/parisc/iosapic.c
drivers/pci/host/pci-mvebu.c
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/pciehp_pci.c
drivers/pci/pci-acpi.c
drivers/pci/pcie/Kconfig
drivers/pci/setup-bus.c
drivers/rapidio/rio.c
drivers/rtc/rtc-stmp3xxx.c
drivers/rtc/rtc-twl.c
drivers/s390/block/dasd.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_main.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/scsi.c
drivers/scsi/virtio_scsi.c
drivers/spi/spi-davinci.c
drivers/staging/zcache/zcache-main.c
drivers/tty/serial/8250/8250_gsc.c
drivers/tty/serial/arc_uart.c
drivers/tty/serial/mxs-auart.c
drivers/tty/tty_port.c
drivers/usb/chipidea/Kconfig
drivers/usb/chipidea/bits.h
drivers/usb/class/usbtmc.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/multi.c
drivers/usb/gadget/udc-core.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci.c
drivers/usb/misc/adutux.c
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/keyspan.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/suunto.c [new file with mode: 0644]
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb_wwan.c
drivers/usb/wusbcore/wa-xfer.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio.c
drivers/video/aty/atyfb_base.c
drivers/video/mxsfb.c
drivers/video/nuc900fb.c
drivers/video/omap2/displays-new/connector-analog-tv.c
drivers/video/sgivwfb.c
drivers/video/sh7760fb.c
drivers/video/vga16fb.c
drivers/video/xilinxfb.c
drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/evtchn.c
drivers/xen/xenbus/xenbus_probe_frontend.c
fs/btrfs/backref.c
fs/btrfs/ctree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/file.c
fs/cifs/link.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2transport.c
fs/debugfs/inode.c
fs/dlm/user.c
fs/exec.c
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/super.c
fs/fcntl.c
fs/hugetlbfs/inode.c
fs/lockd/clntlock.c
fs/lockd/clntproc.c
fs/namei.c
fs/nfs/inode.c
fs/nfs/nfs4proc.c
fs/nfs/super.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/ocfs2/aops.c
fs/ocfs2/dir.c
fs/ocfs2/file.c
fs/ocfs2/journal.h
fs/ocfs2/move_extents.c
fs/ocfs2/refcounttree.c
fs/ocfs2/refcounttree.h
fs/open.c
fs/proc/task_mmu.c
fs/reiserfs/procfs.c
fs/reiserfs/super.c
include/acpi/acpi_bus.h
include/asm-generic/pgtable.h
include/asm-generic/tlb.h
include/drm/drm_fixed.h
include/dt-bindings/sound/fsl-imx-audmux.h [new file with mode: 0644]
include/linux/atmel-ssc.h
include/linux/firewire.h
include/linux/ftrace_event.h
include/linux/iio/trigger.h
include/linux/kernel.h
include/linux/mfd/arizona/gpio.h [new file with mode: 0644]
include/linux/mfd/ti_am335x_tscadc.h
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/mod_devicetable.h
include/linux/netdevice.h
include/linux/platform_data/asoc-s3c.h
include/linux/platform_data/omap-abe-twl6040.h [deleted file]
include/linux/pxa2xx_ssp.h
include/linux/regmap.h
include/linux/sched.h
include/linux/skbuff.h
include/linux/spinlock.h
include/linux/sunrpc/sched.h
include/linux/swapops.h
include/linux/syscalls.h
include/linux/tick.h
include/linux/user_namespace.h
include/linux/vmpressure.h
include/media/v4l2-ctrls.h
include/net/busy_poll.h
include/net/ip6_fib.h
include/net/ip_tunnels.h
include/net/ndisc.h
include/net/nfc/hci.h
include/net/nfc/nfc.h
include/net/sch_generic.h
include/net/sock.h
include/sound/pxa2xx-lib.h
include/sound/rcar_snd.h [new file with mode: 0644]
include/sound/soc-dapm.h
include/sound/soc-dpcm.h
include/sound/soc.h
include/uapi/linux/firewire-cdev.h
include/uapi/linux/nfc.h
include/uapi/linux/pkt_sched.h
include/uapi/linux/snmp.h
kernel/Makefile
kernel/cgroup.c
kernel/cpuset.c
kernel/fork.c
kernel/freezer.c
kernel/mutex.c
kernel/power/process.c
kernel/power/qos.c
kernel/printk/Makefile [new file with mode: 0644]
kernel/printk/braille.c [new file with mode: 0644]
kernel/printk/braille.h [new file with mode: 0644]
kernel/printk/console_cmdline.h [new file with mode: 0644]
kernel/printk/printk.c [moved from kernel/printk.c with 95% similarity]
kernel/ptrace.c
kernel/sched/core.c
kernel/sched/cpupri.c
kernel/sched/fair.c
kernel/sysctl.c
kernel/time/tick-sched.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_events_filter.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_uprobe.c
kernel/user_namespace.c
kernel/workqueue.c
mm/fremap.c
mm/huge_memory.c
mm/hugetlb.c
mm/memcontrol.c
mm/memory.c
mm/mempolicy.c
mm/mmap.c
mm/rmap.c
mm/shmem.c
mm/slub.c
mm/swap.c
mm/swapfile.c
mm/vmpressure.c
mm/zbud.c
net/8021q/vlan_core.c
net/Kconfig
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/gateway_client.c
net/batman-adv/gateway_client.h
net/batman-adv/soft-interface.c
net/batman-adv/unicast.c
net/bluetooth/hci_core.c
net/bridge/br_device.c
net/bridge/br_input.c
net/bridge/br_multicast.c
net/bridge/br_private.h
net/bridge/br_sysfs_br.c
net/core/flow_dissector.c
net/core/neighbour.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/ipv4/devinet.c
net/ipv4/esp4.c
net/ipv4/fib_trie.c
net/ipv4/ip_gre.c
net/ipv4/ip_tunnel_core.c
net/ipv4/proc.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_cubic.c
net/ipv6/addrconf.c
net/ipv6/esp6.c
net/ipv6/ip6_fib.c
net/ipv6/ip6mr.c
net/ipv6/ndisc.c
net/ipv6/route.c
net/key/af_key.c
net/mac80211/cfg.c
net/mac80211/mesh_ps.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rx.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nfnetlink_log.c
net/netfilter/nfnetlink_queue_core.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_TCPOPTSTRIP.c
net/netfilter/xt_socket.c
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_unlabeled.c
net/netlink/genetlink.c
net/nfc/core.c
net/nfc/hci/core.c
net/nfc/nci/Kconfig
net/nfc/netlink.c
net/nfc/nfc.h
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/openvswitch/flow.c
net/sched/sch_api.c
net/sched/sch_atm.c
net/sched/sch_cbq.c
net/sched/sch_generic.c
net/sched/sch_htb.c
net/sctp/associola.c
net/sctp/transport.c
net/socket.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/clnt.c
net/sunrpc/netns.h
net/sunrpc/rpcb_clnt.c
net/sunrpc/svcsock.c
net/tipc/bearer.c
net/tipc/server.c
net/vmw_vsock/af_vsock.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/sme.c
security/smack/smack_lsm.c
sound/arm/pxa2xx-ac97.c
sound/arm/pxa2xx-pcm-lib.c
sound/arm/pxa2xx-pcm.c
sound/arm/pxa2xx-pcm.h
sound/core/Kconfig
sound/core/Makefile
sound/core/compress_offload.c
sound/core/pcm_dmaengine.c [moved from sound/soc/soc-dmaengine-pcm.c with 100% similarity]
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_generic.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/soc/Kconfig
sound/soc/Makefile
sound/soc/atmel/Kconfig
sound/soc/atmel/Makefile
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/atmel_wm8904.c [new file with mode: 0644]
sound/soc/atmel/sam9x5_wm8731.c [new file with mode: 0644]
sound/soc/au1x/ac97c.c
sound/soc/au1x/db1200.c
sound/soc/au1x/psc-ac97.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-ac97.h
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/ac97.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/ad73311.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/adav80x.c
sound/soc/codecs/ads117x.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak4554.c [new file with mode: 0644]
sound/soc/codecs/ak5386.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/bt-sco.c
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/hdmi.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/max9768.c
sound/soc/codecs/max98090.c
sound/soc/codecs/max9877.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/pcm1681.c [new file with mode: 0644]
sound/soc/codecs/pcm1792a.c [new file with mode: 0644]
sound/soc/codecs/pcm1792a.h [new file with mode: 0644]
sound/soc/codecs/pcm3008.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/si476x.c
sound/soc/codecs/spdif_receiver.c
sound/soc/codecs/spdif_transmitter.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/tlv320aic26.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/uda134x.c
sound/soc/codecs/wl1273.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8997.c [new file with mode: 0644]
sound/soc/codecs/wm8997.h [new file with mode: 0644]
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wm_hubs.c
sound/soc/fsl/Kconfig
sound/soc/fsl/Makefile
sound/soc/fsl/fsl_spdif.c [new file with mode: 0644]
sound/soc/fsl/fsl_spdif.h [new file with mode: 0644]
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.c
sound/soc/fsl/imx-audmux.h
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-pcm-dma.c
sound/soc/fsl/imx-pcm-fiq.c
sound/soc/fsl/imx-pcm.h
sound/soc/fsl/imx-sgtl5000.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-ssi.h
sound/soc/fsl/imx-wm8962.c
sound/soc/kirkwood/Kconfig
sound/soc/kirkwood/Makefile
sound/soc/kirkwood/kirkwood-dma.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/kirkwood/kirkwood-openrd.c
sound/soc/kirkwood/kirkwood-t5325.c
sound/soc/kirkwood/kirkwood.h
sound/soc/mxs/Kconfig
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/omap/Kconfig
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c
sound/soc/pxa/Kconfig
sound/soc/pxa/brownstone.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/mmp-pcm.c
sound/soc/pxa/mmp-sspa.c
sound/soc/pxa/pxa-ssp.c
sound/soc/pxa/pxa2xx-ac97.c
sound/soc/pxa/pxa2xx-i2s.c
sound/soc/pxa/pxa2xx-pcm.c
sound/soc/pxa/ttc-dkb.c
sound/soc/s6000/s6105-ipcam.c
sound/soc/samsung/ac97.c
sound/soc/samsung/dma.c
sound/soc/samsung/dma.h
sound/soc/samsung/i2s-regs.h
sound/soc/samsung/i2s.c
sound/soc/samsung/pcm.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/smdk_wm8994.c
sound/soc/samsung/spdif.c
sound/soc/sh/Kconfig
sound/soc/sh/Makefile
sound/soc/sh/rcar/Makefile [new file with mode: 0644]
sound/soc/sh/rcar/adg.c [new file with mode: 0644]
sound/soc/sh/rcar/core.c [new file with mode: 0644]
sound/soc/sh/rcar/gen.c [new file with mode: 0644]
sound/soc/sh/rcar/rsnd.h [new file with mode: 0644]
sound/soc/sh/rcar/scu.c [new file with mode: 0644]
sound/soc/sh/rcar/ssi.c [new file with mode: 0644]
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-jack.c
sound/soc/soc-pcm.c
sound/soc/spear/Kconfig
sound/soc/tegra/Kconfig
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_rt5640.c
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/trimslice.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/ux500/mop500.c
sound/usb/6fire/comm.c
sound/usb/6fire/comm.h
sound/usb/6fire/midi.c
sound/usb/6fire/midi.h
sound/usb/6fire/pcm.c
sound/usb/6fire/pcm.h
sound/usb/endpoint.c
sound/usb/mixer.c
sound/usb/quirks.c

index 3b8b9b3..7e9932e 100644 (file)
@@ -29,6 +29,7 @@ modules.builtin
 *.bz2
 *.lzma
 *.xz
+*.lz4
 *.lzo
 *.patch
 *.gcno
index cbfdf54..fe397f9 100644 (file)
@@ -84,7 +84,7 @@ X!Iinclude/linux/kobject.h
 
      <sect1><title>Kernel utility functions</title>
 !Iinclude/linux/kernel.h
-!Ekernel/printk.c
+!Ekernel/printk/printk.c
 !Ekernel/panic.c
 !Ekernel/sys.c
 !Ekernel/rcupdate.c
index 6a8b715..9c92bb8 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
-       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % media-entities SYSTEM "./media-entities.tmpl"> %media-entities;
 <!ENTITY media-indices SYSTEM "./media-indices.tmpl">
 
index a1ee681..6113f92 100644 (file)
@@ -4,7 +4,7 @@
 Required properties :
 
  - reg             : Offset and length of the register set for the device
- - compatible      : Should be "marvell,mv64xxx-i2c"
+ - compatible      : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c"
  - interrupts      : The interrupt number
 
 Optional properties :
index 38e51ad..a45ae08 100644 (file)
@@ -7,9 +7,30 @@ Required properties:
 - reg: Should contain SSC registers location and length
 - interrupts: Should contain SSC interrupt
 
-Example:
+
+Required properties for devices compatible with "atmel,at91sam9g45-ssc":
+- dmas: DMA specifier, consisting of a phandle to DMA controller node,
+  the memory interface and SSC DMA channel ID (for tx and rx).
+  See Documentation/devicetree/bindings/dma/atmel-dma.txt for details.
+- dma-names: Must be "tx", "rx".
+
+Examples:
+- PDC transfer:
 ssc0: ssc@fffbc000 {
        compatible = "atmel,at91rm9200-ssc";
        reg = <0xfffbc000 0x4000>;
        interrupts = <14 4 5>;
 };
+
+- DMA transfer:
+ssc0: ssc@f0010000 {
+      compatible = "atmel,at91sam9g45-ssc";
+      reg = <0xf0010000 0x4000>;
+      interrupts = <28 4 5>;
+      dmas = <&dma0 1 13>,
+            <&dma0 1 14>;
+      dma-names = "tx", "rx";
+      pinctrl-names = "default";
+      pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
+      status = "disabled";
+};
index d5a3086..30b0581 100644 (file)
@@ -31,9 +31,8 @@ Optional nodes:
               Optional sub-node properties:
               ti,warm-reset - maintain voltage during warm reset(boolean)
               ti,roof-floor - control voltage selection by pin(boolean)
-              ti,sleep-mode - mode to adopt in pmic sleep 0 - off, 1 - auto,
+              ti,mode-sleep - mode to adopt in pmic sleep 0 - off, 1 - auto,
               2 - eco, 3 - forced pwm
-              ti,tstep - slope control 0 - Jump, 1 10mV/us, 2 5mV/us, 3 2.5mV/us
               ti,smps-range - OTP has the wrong range set for the hardware so override
               0 - low range, 1 - high range.
 
@@ -59,7 +58,6 @@ pmic {
                        ti,warm-reset;
                        ti,roof-floor;
                        ti,mode-sleep = <0>;
-                       ti,tstep = <0>;
                        ti,smps-range = <1>;
                };
 
diff --git a/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt b/Documentation/devicetree/bindings/serial/mrvl,pxa-ssp.txt
new file mode 100644 (file)
index 0000000..669b814
--- /dev/null
@@ -0,0 +1,65 @@
+Device tree bindings for Marvell PXA SSP ports
+
+Required properties:
+
+       - compatible:   Must be one of
+                               mrvl,pxa25x-ssp
+                               mvrl,pxa25x-nssp
+                               mrvl,pxa27x-ssp
+                               mrvl,pxa3xx-ssp
+                               mvrl,pxa168-ssp
+                               mrvl,pxa910-ssp
+                               mrvl,ce4100-ssp
+                               mrvl,lpss-ssp
+
+       - reg:          The memory base
+       - dmas:         Two dma phandles, one for rx, one for tx
+       - dma-names:    Must be "rx", "tx"
+
+
+Example for PXA3xx:
+
+       ssp0: ssp@41000000 {
+               compatible = "mrvl,pxa3xx-ssp";
+               reg = <0x41000000 0x40>;
+               ssp-id = <1>;
+               interrupts = <24>;
+               clock-names = "pxa27x-ssp.0";
+               dmas = <&dma 13
+                       &dma 14>;
+               dma-names = "rx", "tx";
+       };
+
+       ssp1: ssp@41700000 {
+               compatible = "mrvl,pxa3xx-ssp";
+               reg = <0x41700000 0x40>;
+               ssp-id = <2>;
+               interrupts = <16>;
+               clock-names = "pxa27x-ssp.1";
+               dmas = <&dma 15
+                       &dma 16>;
+               dma-names = "rx", "tx";
+       };
+
+       ssp2: ssp@41900000 {
+               compatibl3 = "mrvl,pxa3xx-ssp";
+               reg = <0x41900000 0x40>;
+               ssp-id = <3>;
+               interrupts = <0>;
+               clock-names = "pxa27x-ssp.2";
+               dmas = <&dma 66
+                       &dma 67>;
+               dma-names = "rx", "tx";
+       };
+
+       ssp3: ssp@41a00000 {
+               compatible = "mrvl,pxa3xx-ssp";
+               reg = <0x41a00000 0x40>;
+               ssp-id = <4>;
+               interrupts = <13>;
+               clock-names = "pxa27x-ssp.3";
+               dmas = <&dma 2
+                       &dma 3>;
+               dma-names = "rx", "tx";
+       };
+
diff --git a/Documentation/devicetree/bindings/sound/ak4554.c b/Documentation/devicetree/bindings/sound/ak4554.c
new file mode 100644 (file)
index 0000000..934fa02
--- /dev/null
@@ -0,0 +1,11 @@
+AK4554 ADC/DAC
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak4554"
+
+Example:
+
+ak4554-adc-dac {
+       compatible = "asahi-kasei,ak4554";
+};
index 8608f74..ffd886d 100644 (file)
@@ -13,6 +13,25 @@ Required properties:
   - #gpio-cells : Should be two. The first cell is the pin number and the
     second cell is used to specify optional parameters (currently unused).
 
+Pins on the device (for linking into audio routes):
+
+  * SPK_OUTP
+  * SPK_OUTN
+  * HP_OUT_L
+  * HP_OUT_R
+  * AUX_OUT_P
+  * AUX_OUT_N
+  * LINE_IN_L
+  * LINE_IN_R
+  * PHONE_P
+  * PHONE_N
+  * MIC1_P
+  * MIC1_N
+  * MIC2_P
+  * MIC2_N
+  * MICBIAS1
+  * DMICDAT
+
 Example:
 
 alc5632: alc5632@1e {
diff --git a/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt b/Documentation/devicetree/bindings/sound/atmel-sam9x5-wm8731-audio.txt
new file mode 100644 (file)
index 0000000..0720857
--- /dev/null
@@ -0,0 +1,35 @@
+* Atmel at91sam9x5ek wm8731 audio complex
+
+Required properties:
+  - compatible: "atmel,sam9x5-wm8731-audio"
+  - atmel,model: The user-visible name of this sound complex.
+  - atmel,ssc-controller: The phandle of the SSC controller
+  - atmel,audio-codec: The phandle of the WM8731 audio codec
+  - atmel,audio-routing: A list of the connections between audio components.
+    Each entry is a pair of strings, the first being the connection's sink,
+    the second being the connection's source.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headphone Jack
+ * Line In Jack
+
+wm8731 pins:
+cf Documentation/devicetree/bindings/sound/wm8731.txt
+
+Example:
+sound {
+       compatible = "atmel,sam9x5-wm8731-audio";
+
+       atmel,model = "wm8731 @ AT91SAM9X5EK";
+
+       atmel,audio-routing =
+               "Headphone Jack", "RHPOUT",
+               "Headphone Jack", "LHPOUT",
+               "LLINEIN", "Line In Jack",
+               "RLINEIN", "Line In Jack";
+
+       atmel,ssc-controller = <&ssc0>;
+       atmel,audio-codec = <&wm8731>;
+};
diff --git a/Documentation/devicetree/bindings/sound/atmel-wm8904.txt b/Documentation/devicetree/bindings/sound/atmel-wm8904.txt
new file mode 100644 (file)
index 0000000..8bbe50c
--- /dev/null
@@ -0,0 +1,55 @@
+Atmel ASoC driver with wm8904 audio codec complex
+
+Required properties:
+  - compatible: "atmel,asoc-wm8904"
+  - atmel,model: The user-visible name of this sound complex.
+  - atmel,audio-routing: A list of the connections between audio components.
+    Each entry is a pair of strings, the first being the connection's sink,
+    the second being the connection's source. Valid names for sources and
+    sinks are the WM8904's pins, and the jacks on the board:
+
+    WM8904 pins:
+
+    * IN1L
+    * IN1R
+    * IN2L
+    * IN2R
+    * IN3L
+    * IN3R
+    * HPOUTL
+    * HPOUTR
+    * LINEOUTL
+    * LINEOUTR
+    * MICBIAS
+
+    Board connectors:
+
+    * Headphone Jack
+    * Line In Jack
+    * Mic
+
+  - atmel,ssc-controller: The phandle of the SSC controller
+  - atmel,audio-codec: The phandle of the WM8904 audio codec
+
+Optional properties:
+  - pinctrl-names, pinctrl-0: Please refer to pinctrl-bindings.txt
+
+Example:
+sound {
+       compatible = "atmel,asoc-wm8904";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_pck0_as_mck>;
+
+       atmel,model = "wm8904 @ AT91SAM9N12EK";
+
+       atmel,audio-routing =
+               "Headphone Jack", "HPOUTL",
+               "Headphone Jack", "HPOUTR",
+               "IN2L", "Line In Jack",
+               "IN2R", "Line In Jack",
+               "Mic", "MICBIAS",
+               "IN1L", "Mic";
+
+       atmel,ssc-controller = <&ssc0>;
+       atmel,audio-codec = <&wm8904>;
+};
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
new file mode 100644 (file)
index 0000000..f2ae335
--- /dev/null
@@ -0,0 +1,54 @@
+Freescale Sony/Philips Digital Interface Format (S/PDIF) Controller
+
+The Freescale S/PDIF audio block is a stereo transceiver that allows the
+processor to receive and transmit digital audio via an coaxial cable or
+a fibre cable.
+
+Required properties:
+
+  - compatible : Compatible list, must contain "fsl,imx35-spdif".
+
+  - reg : Offset and length of the register set for the device.
+
+  - interrupts : Contains the spdif interrupt.
+
+  - dmas : Generic dma devicetree binding as described in
+  Documentation/devicetree/bindings/dma/dma.txt.
+
+  - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+  - clocks : Contains an entry for each entry in clock-names.
+
+  - clock-names : Includes the following entries:
+       "core"          The core clock of spdif controller
+       "rxtx<0-7>"     Clock source list for tx and rx clock.
+                       This clock list should be identical to
+                       the source list connecting to the spdif
+                       clock mux in "SPDIF Transceiver Clock
+                       Diagram" of SoC reference manual. It
+                       can also be referred to TxClk_Source
+                       bit of register SPDIF_STC.
+
+Example:
+
+spdif: spdif@02004000 {
+       compatible = "fsl,imx35-spdif";
+       reg = <0x02004000 0x4000>;
+       interrupts = <0 52 0x04>;
+       dmas = <&sdma 14 18 0>,
+              <&sdma 15 18 0>;
+       dma-names = "rx", "tx";
+
+       clocks = <&clks 197>, <&clks 3>,
+              <&clks 197>, <&clks 107>,
+              <&clks 0>, <&clks 118>,
+              <&clks 62>, <&clks 139>,
+              <&clks 0>;
+       clock-names = "core", "rxtx0",
+               "rxtx1", "rxtx2",
+               "rxtx3", "rxtx4",
+               "rxtx5", "rxtx6",
+               "rxtx7";
+
+       status = "okay";
+};
@@ -43,10 +43,22 @@ Required properties:
                     together.  This would still allow different sample sizes,
                     but not different sample rates.
 
+Required are also ac97 link bindings if ac97 is used. See
+Documentation/devicetree/bindings/sound/soc-ac97link.txt for the necessary
+bindings.
+
 Optional properties:
 - codec-handle:     Phandle to a 'codec' node that defines an audio
                     codec connected to this SSI.  This node is typically
                     a child of an I2C or other control node.
+- fsl,fiq-stream-filter: Bool property. Disabled DMA and use FIQ instead to
+                   filter the codec stream. This is necessary for some boards
+                   where an incompatible codec is connected to this SSI, e.g.
+                   on pca100 and pcm043.
+- dmas:                    Generic dma devicetree binding as described in
+                   Documentation/devicetree/bindings/dma/dma.txt.
+- dma-names:       Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
+                   is not defined.
 
 Child 'codec' node required properties:
 - compatible:       Compatible list, contains the name of the codec
index 215aa98..f88a00e 100644 (file)
@@ -5,6 +5,15 @@ Required properties:
   or "fsl,imx31-audmux" for the version firstly used on i.MX31.
 - reg : Should contain AUDMUX registers location and length
 
+An initial configuration can be setup using child nodes.
+
+Required properties of optional child nodes:
+- fsl,audmux-port : Integer of the audmux port that is configured by this
+  child node.
+- fsl,port-config : List of configuration options for the specific port. For
+  imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For
+  imx21-audmux it is a list of pcr values.
+
 Example:
 
 audmux@021d8000 {
diff --git a/Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt b/Documentation/devicetree/bindings/sound/mrvl,pxa-ssp.txt
new file mode 100644 (file)
index 0000000..74c9ba6
--- /dev/null
@@ -0,0 +1,28 @@
+Marvell PXA SSP CPU DAI bindings
+
+Required properties:
+
+       compatible      Must be "mrvl,pxa-ssp-dai"
+       port            A phandle reference to a PXA ssp upstream device
+
+Example:
+
+       /* upstream device */
+
+       ssp0: ssp@41000000 {
+               compatible = "mrvl,pxa3xx-ssp";
+               reg = <0x41000000 0x40>;
+               interrupts = <24>;
+               clock-names = "pxa27x-ssp.0";
+               dmas = <&dma 13
+                       &dma 14>;
+               dma-names = "rx", "tx";
+       };
+
+       /* DAI as user */
+
+       ssp_dai0: ssp_dai@0 {
+               compatible = "mrvl,pxa-ssp-dai";
+               port = <&ssp0>;
+       };
+
diff --git a/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt b/Documentation/devicetree/bindings/sound/mrvl,pxa2xx-pcm.txt
new file mode 100644 (file)
index 0000000..551fbb8
--- /dev/null
@@ -0,0 +1,15 @@
+DT bindings for ARM PXA2xx PCM platform driver
+
+This is just a dummy driver that registers the PXA ASoC platform driver.
+It does not have any resources assigned.
+
+Required properties:
+
+       - compatible            'mrvl,pxa-pcm-audio'
+
+Example:
+
+       pxa_pcm_audio: snd_soc_pxa_audio {
+               compatible = "mrvl,pxa-pcm-audio";
+       };
+
index 05ffecb..8b8903e 100644 (file)
@@ -11,28 +11,8 @@ Required properties:
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the ALC5632's pins:
-
-  ALC5632 pins:
-
-  * SPK_OUTP
-  * SPK_OUTN
-  * HP_OUT_L
-  * HP_OUT_R
-  * AUX_OUT_P
-  * AUX_OUT_N
-  * LINE_IN_L
-  * LINE_IN_R
-  * PHONE_P
-  * PHONE_N
-  * MIC1_P
-  * MIC1_N
-  * MIC2_P
-  * MIC2_N
-  * MICBIAS1
-  * DMICDAT
-
-  Board connectors:
+  sinks are the ALC5632's pins as documented in the binding for the device
+  and:
 
   * Headset Stereophone
   * Int Spk
index d130818..dc62249 100644 (file)
@@ -11,32 +11,12 @@ Required properties:
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the RT5640's pins, and the jacks on the board:
-
-  RT5640 pins:
-
-  * DMIC1
-  * DMIC2
-  * MICBIAS1
-  * IN1P
-  * IN1R
-  * IN2P
-  * IN2R
-  * HPOL
-  * HPOR
-  * LOUTL
-  * LOUTR
-  * MONOP
-  * MONON
-  * SPOLP
-  * SPOLN
-  * SPORP
-  * SPORN
-
-  Board connectors:
+  sinks are the RT5640's pins (as documented in its binding), and the jacks
+  on the board:
 
   * Headphones
   * Speakers
+  * Mic Jack
 
 - nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
   connected to the CODEC.
index 3bf722d..4b44dfb 100644 (file)
@@ -11,28 +11,8 @@ Required properties:
 - nvidia,audio-routing : A list of the connections between audio components.
   Each entry is a pair of strings, the first being the connection's sink,
   the second being the connection's source. Valid names for sources and
-  sinks are the WM8903's pins, and the jacks on the board:
-
-  WM8903 pins:
-
-  * IN1L
-  * IN1R
-  * IN2L
-  * IN2R
-  * IN3L
-  * IN3R
-  * DMICDAT
-  * HPOUTL
-  * HPOUTR
-  * LINEOUTL
-  * LINEOUTR
-  * LOP
-  * LON
-  * ROP
-  * RON
-  * MICBIAS
-
-  Board connectors:
+  sinks are the WM8903's pins (documented in the WM8903 binding document),
+  and the jacks on the board:
 
   * Headphone Jack
   * Int Spk
diff --git a/Documentation/devicetree/bindings/sound/pcm1792a.txt b/Documentation/devicetree/bindings/sound/pcm1792a.txt
new file mode 100644 (file)
index 0000000..970ba1e
--- /dev/null
@@ -0,0 +1,18 @@
+Texas Instruments pcm1792a DT bindings
+
+This driver supports the SPI bus.
+
+Required properties:
+
+ - compatible: "ti,pcm1792a"
+
+For required properties on SPI, please consult
+Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Examples:
+
+       codec_spi: 1792a@0 {
+               compatible = "ti,pcm1792a";
+               spi-max-frequency = <600000>;
+       };
+
index 005bcb2..068a114 100644 (file)
@@ -18,6 +18,26 @@ Optional properties:
 
 - realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin.
 
+Pins on the device (for linking into audio routes):
+
+  * DMIC1
+  * DMIC2
+  * MICBIAS1
+  * IN1P
+  * IN1R
+  * IN2P
+  * IN2R
+  * HPOL
+  * HPOR
+  * LOUTL
+  * LOUTR
+  * MONOP
+  * MONON
+  * SPOLP
+  * SPOLN
+  * SPORP
+  * SPORN
+
 Example:
 
 rt5640 {
index 025e66b..7386d44 100644 (file)
@@ -2,7 +2,15 @@
 
 Required SoC Specific Properties:
 
-- compatible : "samsung,i2s-v5"
+- compatible : should be one of the following.
+   - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
+   - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
+     secondary fifo, s/w reset control and internal mux for root clk src.
+   - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
+     secondary fifo, s/w reset control, internal mux for root clk src and
+     TDM support. TDM (Time division multiplexing) is to allow transfer of
+     multiple channel audio data on single data line.
+
 - reg: physical base address of the controller and length of memory mapped
   region.
 - dmas: list of DMA controller phandle and DMA request line ordered pairs.
@@ -21,13 +29,6 @@ Required SoC Specific Properties:
 
 Optional SoC Specific Properties:
 
-- samsung,supports-6ch: If the I2S Primary sound source has 5.1 Channel
-  support, this flag is enabled.
-- samsung,supports-rstclr: This flag should be set if I2S software reset bit
-  control is required. When this flag is set I2S software reset bit will be
-  enabled or disabled based on need.
-- samsung,supports-secdai:If I2S block has a secondary FIFO and internal DMA,
-  then this flag is enabled.
 - samsung,idma-addr: Internal DMA register base address of the audio
   sub system(used in secondary sound source).
 - pinctrl-0: Should specify pin control groups used for this controller.
@@ -36,7 +37,7 @@ Optional SoC Specific Properties:
 Example:
 
 i2s0: i2s@03830000 {
-       compatible = "samsung,i2s-v5";
+       compatible = "samsung,s5pv210-i2s";
        reg = <0x03830000 0x100>;
        dmas = <&pdma0 10
                &pdma0 9
@@ -46,9 +47,6 @@ i2s0: i2s@03830000 {
                <&clock_audss EXYNOS_I2S_BUS>,
                <&clock_audss EXYNOS_SCLK_I2S>;
        clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
-       samsung,supports-6ch;
-       samsung,supports-rstclr;
-       samsung,supports-secdai;
        samsung,idma-addr = <0x03000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2s0_bus>;
diff --git a/Documentation/devicetree/bindings/sound/soc-ac97link.txt b/Documentation/devicetree/bindings/sound/soc-ac97link.txt
new file mode 100644 (file)
index 0000000..80152a8
--- /dev/null
@@ -0,0 +1,28 @@
+AC97 link bindings
+
+These bindings can be included within any other device node.
+
+Required properties:
+ - pinctrl-names: Has to contain following states to setup the correct
+   pinmuxing for the used gpios:
+       "ac97-running": AC97-link is active
+       "ac97-reset": AC97-link reset state
+       "ac97-warm-reset": AC97-link warm reset state
+ - ac97-gpios: List of gpio phandles with args in the order ac97-sync,
+   ac97-sdata, ac97-reset
+
+
+Example:
+
+ssi {
+       ...
+
+       pinctrl-names = "default", "ac97-running", "ac97-reset", "ac97-warm-reset";
+       pinctrl-0 = <&ac97link_running>;
+       pinctrl-1 = <&ac97link_running>;
+       pinctrl-2 = <&ac97link_reset>;
+       pinctrl-3 = <&ac97link_warm_reset>;
+       ac97-gpios = <&gpio3 20 0 &gpio3 22 0 &gpio3 28 0>;
+
+       ...
+};
diff --git a/Documentation/devicetree/bindings/sound/ti,pcm1681.txt b/Documentation/devicetree/bindings/sound/ti,pcm1681.txt
new file mode 100644 (file)
index 0000000..4df1718
--- /dev/null
@@ -0,0 +1,15 @@
+Texas Instruments PCM1681 8-channel PWM Processor
+
+Required properties:
+
+ - compatible:         Should contain "ti,pcm1681".
+ - reg:                        The i2c address. Should contain <0x4c>.
+
+Examples:
+
+       i2c_bus {
+               pcm1681@4c {
+                       compatible = "ti,pcm1681";
+                       reg = <0x4c>;
+               };
+       };
index f47c3f5..705a6b1 100644 (file)
@@ -3,7 +3,14 @@ Texas Instruments - tlv320aic3x Codec module
 The tlv320aic3x serial control bus communicates through I2C protocols
 
 Required properties:
-- compatible - "string" -  "ti,tlv320aic3x"
+
+- compatible - "string" - One of:
+    "ti,tlv320aic3x" - Generic TLV320AIC3x device
+    "ti,tlv320aic33" - TLV320AIC33
+    "ti,tlv320aic3007" - TLV320AIC3007
+    "ti,tlv320aic3106" - TLV320AIC3106
+
+
 - reg - <int> -  I2C slave address
 
 
index 15f7004..236690e 100644 (file)
@@ -16,3 +16,12 @@ codec: wm8731@1a {
        compatible = "wlf,wm8731";
        reg = <0x1a>;
 };
+
+Available audio endpoints for an audio-routing table:
+ * LOUT: Left Channel Line Output
+ * ROUT: Right Channel Line Output
+ * LHPOUT: Left Channel Headphone Output
+ * RHPOUT: Right Channel Headphone Output
+ * LLINEIN: Left Channel Line Input
+ * RLINEIN: Right Channel Line Input
+ * MICIN: Microphone Input
index f102cbc..94ec32c 100644 (file)
@@ -28,6 +28,25 @@ Optional properties:
     performed. If any entry has the value 0xffffffff, that GPIO's
     configuration will not be modified.
 
+Pins on the device (for linking into audio routes):
+
+  * IN1L
+  * IN1R
+  * IN2L
+  * IN2R
+  * IN3L
+  * IN3R
+  * DMICDAT
+  * HPOUTL
+  * HPOUTR
+  * LINEOUTL
+  * LINEOUTR
+  * LOP
+  * LON
+  * ROP
+  * RON
+  * MICBIAS
+
 Example:
 
 codec: wm8903@1a {
index 1c15043..d569f2a 100644 (file)
@@ -52,7 +52,7 @@ Default: 64
 
 busy_read
 ----------------
-Low latency busy poll timeout for socket reads. (needs CONFIG_NET_LL_RX_POLL)
+Low latency busy poll timeout for socket reads. (needs CONFIG_NET_RX_BUSY_POLL)
 Approximate time in us to busy loop waiting for packets on the device queue.
 This sets the default value of the SO_BUSY_POLL socket option.
 Can be set or overridden per socket by setting socket option SO_BUSY_POLL,
@@ -63,7 +63,7 @@ Default: 0 (off)
 
 busy_poll
 ----------------
-Low latency busy poll timeout for poll and select. (needs CONFIG_NET_LL_RX_POLL)
+Low latency busy poll timeout for poll and select. (needs CONFIG_NET_RX_BUSY_POLL)
 Approximate time in us to busy loop waiting for events.
 Recommended value depends on the number of sockets you poll on.
 For several sockets 50, for several hundreds 100.
index a26b10e..8c54609 100644 (file)
@@ -595,6 +595,7 @@ S:  Supported
 F:     sound/soc/codecs/adau*
 F:     sound/soc/codecs/adav*
 F:     sound/soc/codecs/ad1*
+F:     sound/soc/codecs/ad7*
 F:     sound/soc/codecs/ssm*
 F:     sound/soc/codecs/sigmadsp.*
 
@@ -965,6 +966,12 @@ M: Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
+ARM/TEXAS INSTRUMENT KEYSTONE ARCHITECTURE
+M:     Santosh Shilimkar <santosh.shilimkar@ti.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/mach-keystone/
+
 ARM/LOGICPD PXA270 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1259,7 +1266,6 @@ F:        drivers/rtc/rtc-coh901331.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
 
 ARM/Ux500 ARM ARCHITECTURE
-M:     Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -1406,7 +1412,7 @@ ATHEROS ATH6KL WIRELESS DRIVER
 M:     Kalle Valo <kvalo@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/ath6kl
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath6kl.git
+T:     git git://github.com/kvalo/ath.git
 S:     Supported
 F:     drivers/net/wireless/ath/ath6kl/
 
@@ -2871,7 +2877,7 @@ F:        drivers/media/usb/dvb-usb-v2/dvb_usb*
 F:     drivers/media/usb/dvb-usb-v2/usb_urb.c
 
 DYNAMIC DEBUG
-M:     Jason Baron <jbaron@redhat.com>
+M:     Jason Baron <jbaron@akamai.com>
 S:     Maintained
 F:     lib/dynamic_debug.c
 F:     include/linux/dynamic_debug.h
@@ -5576,9 +5582,9 @@ S:        Maintained
 F:     drivers/media/tuners/mxl5007t.*
 
 MYRICOM MYRI-10G 10GbE DRIVER (MYRI10GE)
-M:     Andrew Gallatin <gallatin@myri.com>
+M:     Hyong-Youb Kim <hykim@myri.com>
 L:     netdev@vger.kernel.org
-W:     http://www.myri.com/scs/download-Myri10GE.html
+W:     https://www.myricom.com/support/downloads/myri10ge.html
 S:     Supported
 F:     drivers/net/ethernet/myricom/myri10ge/
 
@@ -6726,6 +6732,14 @@ T:       git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
 F:     drivers/media/tuners/qt1010*
 
+QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
+M:     Kalle Valo <kvalo@qca.qualcomm.com>
+L:     ath10k@lists.infradead.org
+W:     http://wireless.kernel.org/en/users/Drivers/ath10k
+T:     git git://github.com/kvalo/ath.git
+S:     Supported
+F:     drivers/net/wireless/ath/ath10k/
+
 QUALCOMM HEXAGON ARCHITECTURE
 M:     Richard Kuo <rkuo@codeaurora.org>
 L:     linux-hexagon@vger.kernel.org
@@ -7353,7 +7367,6 @@ F:        drivers/net/ethernet/sfc/
 
 SGI GRU DRIVER
 M:     Dimitri Sivanich <sivanich@sgi.com>
-M:     Robin Holt <holt@sgi.com>
 S:     Maintained
 F:     drivers/misc/sgi-gru/
 
@@ -7373,7 +7386,8 @@ S:        Maintained for 2.6.
 F:     Documentation/sgi-visws.txt
 
 SGI XP/XPC/XPNET DRIVER
-M:     Robin Holt <holt@sgi.com>
+M:     Cliff Whickman <cpw@sgi.com>
+M:     Robin Holt <robinmholt@gmail.com>
 S:     Maintained
 F:     drivers/misc/sgi-xp/
 
@@ -7669,6 +7683,7 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://alsa-project.org/main/index.php/ASoC
 S:     Supported
+F:     Documentation/sound/alsa/soc/
 F:     sound/soc/
 F:     include/sound/soc*
 
@@ -8270,7 +8285,7 @@ S:        Maintained
 F:     sound/soc/codecs/twl4030*
 
 TI WILINK WIRELESS DRIVERS
-M:     Luciano Coelho <coelho@ti.com>
+M:     Luciano Coelho <luca@coelho.fi>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/wl12xx
 W:     http://wireless.kernel.org/en/users/Drivers/wl1251
@@ -8656,6 +8671,11 @@ T:       git git://git.alsa-project.org/alsa-kernel.git
 S:     Maintained
 F:     sound/usb/midi.*
 
+USB NETWORKING DRIVERS
+L:     linux-usb@vger.kernel.org
+S:     Odd Fixes
+F:     drivers/net/usb/
+
 USB OHCI DRIVER
 M:     Alan Stern <stern@rowland.harvard.edu>
 L:     linux-usb@vger.kernel.org
index 95a8e55..a5a55f4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 11
 SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc6
 NAME = Linux for Workgroups
 
 # *DOCUMENTATION*
index 8d2ae24..1feb169 100644 (file)
@@ -407,6 +407,12 @@ config CLONE_BACKWARDS2
        help
          Architecture has the first two arguments of clone(2) swapped.
 
+config CLONE_BACKWARDS3
+       bool
+       help
+         Architecture has tls passed as the 3rd argument of clone(2),
+         not the 5th one.
+
 config ODD_RT_SIGACTION
        bool
        help
index 8943c02..df57611 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>     /* For VMALLOC_START */
 #include <asm/thread_info.h>   /* For THREAD_SIZE */
+#include <asm/mmu.h>
 
 /* Note on the LD/ST addr modes with addr reg wback
  *
index 37c0f4e..43594d5 100644 (file)
@@ -20,7 +20,6 @@ config ARM
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HARDIRQS_SW_RESEND
-       select HAVE_AOUT
        select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_SECCOMP_FILTER
@@ -218,7 +217,8 @@ config VECTORS_BASE
        default DRAM_BASE if REMAP_VECTORS_TO_RAM
        default 0x00000000
        help
-         The base address of exception vectors.
+         The base address of exception vectors.  This must be two pages
+         in size.
 
 config ARM_PATCH_PHYS_VIRT
        bool "Patch physical to virtual translations at runtime" if EMBEDDED
index e401a76..583f4a0 100644 (file)
@@ -804,9 +804,19 @@ config DEBUG_LL_INCLUDE
 
 config DEBUG_UNCOMPRESS
        bool
-       default y if ARCH_MULTIPLATFORM && DEBUG_LL && \
-                    !DEBUG_OMAP2PLUS_UART && \
+       depends on ARCH_MULTIPLATFORM
+       default y if DEBUG_LL && !DEBUG_OMAP2PLUS_UART && \
                     !DEBUG_TEGRA_UART
+       help
+         This option influences the normal decompressor output for
+         multiplatform kernels.  Normally, multiplatform kernels disable
+         decompressor output because it is not possible to know where to
+         send the decompressor output.
+
+         When this option is set, the selected DEBUG_LL output method
+         will be re-used for normal decompressor output on multiplatform
+         kernels.
+         
 
 config UNCOMPRESS_INCLUDE
        string
index c0ac0f5..6fd2cea 100644 (file)
@@ -153,6 +153,7 @@ machine-$(CONFIG_ARCH_DAVINCI)              += davinci
 machine-$(CONFIG_ARCH_DOVE)            += dove
 machine-$(CONFIG_ARCH_EBSA110)         += ebsa110
 machine-$(CONFIG_ARCH_EP93XX)          += ep93xx
+machine-$(CONFIG_ARCH_EXYNOS)          += exynos
 machine-$(CONFIG_ARCH_GEMINI)          += gemini
 machine-$(CONFIG_ARCH_HIGHBANK)                += highbank
 machine-$(CONFIG_ARCH_INTEGRATOR)      += integrator
@@ -160,15 +161,16 @@ machine-$(CONFIG_ARCH_IOP13XX)            += iop13xx
 machine-$(CONFIG_ARCH_IOP32X)          += iop32x
 machine-$(CONFIG_ARCH_IOP33X)          += iop33x
 machine-$(CONFIG_ARCH_IXP4XX)          += ixp4xx
+machine-$(CONFIG_ARCH_KEYSTONE)                += keystone
 machine-$(CONFIG_ARCH_KIRKWOOD)                += kirkwood
 machine-$(CONFIG_ARCH_KS8695)          += ks8695
 machine-$(CONFIG_ARCH_LPC32XX)         += lpc32xx
 machine-$(CONFIG_ARCH_MMP)             += mmp
 machine-$(CONFIG_ARCH_MSM)             += msm
 machine-$(CONFIG_ARCH_MV78XX0)         += mv78xx0
+machine-$(CONFIG_ARCH_MVEBU)           += mvebu
 machine-$(CONFIG_ARCH_MXC)             += imx
 machine-$(CONFIG_ARCH_MXS)             += mxs
-machine-$(CONFIG_ARCH_MVEBU)           += mvebu
 machine-$(CONFIG_ARCH_NETX)            += netx
 machine-$(CONFIG_ARCH_NOMADIK)         += nomadik
 machine-$(CONFIG_ARCH_NSPIRE)          += nspire
@@ -176,7 +178,6 @@ machine-$(CONFIG_ARCH_OMAP1)                += omap1
 machine-$(CONFIG_ARCH_OMAP2PLUS)       += omap2
 machine-$(CONFIG_ARCH_ORION5X)         += orion5x
 machine-$(CONFIG_ARCH_PICOXCELL)       += picoxcell
-machine-$(CONFIG_ARCH_SIRF)            += prima2
 machine-$(CONFIG_ARCH_PXA)             += pxa
 machine-$(CONFIG_ARCH_REALVIEW)                += realview
 machine-$(CONFIG_ARCH_ROCKCHIP)                += rockchip
@@ -186,25 +187,24 @@ machine-$(CONFIG_ARCH_S3C64XX)            += s3c64xx
 machine-$(CONFIG_ARCH_S5P64X0)         += s5p64x0
 machine-$(CONFIG_ARCH_S5PC100)         += s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         += s5pv210
-machine-$(CONFIG_ARCH_EXYNOS)          += exynos
 machine-$(CONFIG_ARCH_SA1100)          += sa1100
 machine-$(CONFIG_ARCH_SHARK)           += shark
 machine-$(CONFIG_ARCH_SHMOBILE)        += shmobile
+machine-$(CONFIG_ARCH_SIRF)            += prima2
+machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
+machine-$(CONFIG_ARCH_STI)             += sti
+machine-$(CONFIG_ARCH_SUNXI)           += sunxi
 machine-$(CONFIG_ARCH_TEGRA)           += tegra
 machine-$(CONFIG_ARCH_U300)            += u300
 machine-$(CONFIG_ARCH_U8500)           += ux500
 machine-$(CONFIG_ARCH_VERSATILE)       += versatile
 machine-$(CONFIG_ARCH_VEXPRESS)                += vexpress
+machine-$(CONFIG_ARCH_VIRT)            += virt
 machine-$(CONFIG_ARCH_VT8500)          += vt8500
 machine-$(CONFIG_ARCH_W90X900)         += w90x900
+machine-$(CONFIG_ARCH_ZYNQ)            += zynq
 machine-$(CONFIG_FOOTBRIDGE)           += footbridge
-machine-$(CONFIG_ARCH_SOCFPGA)         += socfpga
 machine-$(CONFIG_PLAT_SPEAR)           += spear
-machine-$(CONFIG_ARCH_STI)             += sti
-machine-$(CONFIG_ARCH_VIRT)            += virt
-machine-$(CONFIG_ARCH_ZYNQ)            += zynq
-machine-$(CONFIG_ARCH_SUNXI)           += sunxi
-machine-$(CONFIG_ARCH_KEYSTONE)                += keystone
 
 # Platform directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
index ef57277..376090f 100644 (file)
        };
 
        i2s0: i2s@03830000 {
-               compatible = "samsung,i2s-v5";
+               compatible = "samsung,s5pv210-i2s";
                reg = <0x03830000 0x100>;
                dmas = <&pdma0 10
                        &pdma0 9
                        <&clock_audss EXYNOS_I2S_BUS>,
                        <&clock_audss EXYNOS_SCLK_I2S>;
                clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
-               samsung,supports-6ch;
-               samsung,supports-rstclr;
-               samsung,supports-secdai;
                samsung,idma-addr = <0x03000000>;
                pinctrl-names = "default";
                pinctrl-0 = <&i2s0_bus>;
        };
 
        i2s1: i2s@12D60000 {
-               compatible = "samsung,i2s-v5";
+               compatible = "samsung,s3c6410-i2s";
                reg = <0x12D60000 0x100>;
                dmas = <&pdma1 12
                        &pdma1 11>;
        };
 
        i2s2: i2s@12D70000 {
-               compatible = "samsung,i2s-v5";
+               compatible = "samsung,s3c6410-i2s";
                reg = <0x12D70000 0x100>;
                dmas = <&pdma0 12
                        &pdma0 11>;
index db2060c..9c1167b 100644 (file)
@@ -26,7 +26,7 @@
                cpu-offset = <0x80000>;
        };
 
-       msmgpio: gpio@fd510000 {
+       msmgpio: gpio@800000 {
                compatible = "qcom,msm-gpio";
                gpio-controller;
                #gpio-cells = <2>;
@@ -34,7 +34,7 @@
                interrupts = <0 32 0x4>;
                interrupt-controller;
                #interrupt-cells = <2>;
-               reg = <0xfd510000 0x4000>;
+               reg = <0x800000 0x4000>;
        };
 
        serial@16440000 {
index 08b7267..65d7b60 100644 (file)
 };
 
 &mmc1 {
-       vmmc-supply = <&vmmcsd_fixed>;
+       vmmc-supply = <&ldo9_reg>;
        bus-width = <4>;
 };
 
 
                        regulators {
                                smps123_reg: smps123 {
+                                       /* VDD_OPP_MPU */
                                        regulator-name = "smps123";
                                        regulator-min-microvolt = < 600000>;
                                        regulator-max-microvolt = <1500000>;
                                };
 
                                smps45_reg: smps45 {
+                                       /* VDD_OPP_MM */
                                        regulator-name = "smps45";
                                        regulator-min-microvolt = < 600000>;
                                        regulator-max-microvolt = <1310000>;
                                };
 
                                smps6_reg: smps6 {
+                                       /* VDD_DDR3 - over VDD_SMPS6 */
                                        regulator-name = "smps6";
                                        regulator-min-microvolt = <1200000>;
                                        regulator-max-microvolt = <1200000>;
                                };
 
                                smps7_reg: smps7 {
+                                       /* VDDS_1v8_OMAP over VDDS_1v8_MAIN */
                                        regulator-name = "smps7";
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
                                };
 
                                smps8_reg: smps8 {
+                                       /* VDD_OPP_CORE */
                                        regulator-name = "smps8";
                                        regulator-min-microvolt = < 600000>;
                                        regulator-max-microvolt = <1310000>;
                                };
 
                                smps9_reg: smps9 {
+                                       /* VDDA_2v1_AUD over VDD_2v1 */
                                        regulator-name = "smps9";
                                        regulator-min-microvolt = <2100000>;
                                        regulator-max-microvolt = <2100000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
                                        ti,smps-range = <0x80>;
                                };
 
                                smps10_reg: smps10 {
+                                       /* VBUS_5V_OTG */
                                        regulator-name = "smps10";
                                        regulator-min-microvolt = <5000000>;
                                        regulator-max-microvolt = <5000000>;
                                };
 
                                ldo1_reg: ldo1 {
+                                       /* VDDAPHY_CAM: vdda_csiport */
                                        regulator-name = "ldo1";
-                                       regulator-min-microvolt = <2800000>;
-                                       regulator-max-microvolt = <2800000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <1500000>;
+                                       regulator-max-microvolt = <1800000>;
                                };
 
                                ldo2_reg: ldo2 {
+                                       /* VCC_2V8_DISP: Does not go anywhere */
                                        regulator-name = "ldo2";
-                                       regulator-min-microvolt = <2900000>;
-                                       regulator-max-microvolt = <2900000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <2800000>;
+                                       regulator-max-microvolt = <2800000>;
+                                       /* Unused */
+                                       status = "disabled";
                                };
 
                                ldo3_reg: ldo3 {
+                                       /* VDDAPHY_MDM: vdda_lli */
                                        regulator-name = "ldo3";
-                                       regulator-min-microvolt = <3000000>;
-                                       regulator-max-microvolt = <3000000>;
-                                       regulator-always-on;
+                                       regulator-min-microvolt = <1500000>;
+                                       regulator-max-microvolt = <1500000>;
                                        regulator-boot-on;
+                                       /* Only if Modem is used */
+                                       status = "disabled";
                                };
 
                                ldo4_reg: ldo4 {
+                                       /* VDDAPHY_DISP: vdda_dsiport/hdmi */
                                        regulator-name = "ldo4";
-                                       regulator-min-microvolt = <2200000>;
-                                       regulator-max-microvolt = <2200000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <1500000>;
+                                       regulator-max-microvolt = <1800000>;
                                };
 
                                ldo5_reg: ldo5 {
+                                       /* VDDA_1V8_PHY: usb/sata/hdmi.. */
                                        regulator-name = "ldo5";
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
                                };
 
                                ldo6_reg: ldo6 {
+                                       /* VDDS_1V2_WKUP: hsic/ldo_emu_wkup */
                                        regulator-name = "ldo6";
-                                       regulator-min-microvolt = <1500000>;
-                                       regulator-max-microvolt = <1500000>;
+                                       regulator-min-microvolt = <1200000>;
+                                       regulator-max-microvolt = <1200000>;
                                        regulator-always-on;
                                        regulator-boot-on;
                                };
 
                                ldo7_reg: ldo7 {
+                                       /* VDD_VPP: vpp1 */
                                        regulator-name = "ldo7";
-                                       regulator-min-microvolt = <1500000>;
-                                       regulator-max-microvolt = <1500000>;
-                                       regulator-always-on;
-                                       regulator-boot-on;
+                                       regulator-min-microvolt = <2000000>;
+                                       regulator-max-microvolt = <2000000>;
+                                       /* Only for efuse reprograming! */
+                                       status = "disabled";
                                };
 
                                ldo8_reg: ldo8 {
+                                       /* VDD_3v0: Does not go anywhere */
                                        regulator-name = "ldo8";
-                                       regulator-min-microvolt = <1500000>;
-                                       regulator-max-microvolt = <1500000>;
-                                       regulator-always-on;
+                                       regulator-min-microvolt = <3000000>;
+                                       regulator-max-microvolt = <3000000>;
                                        regulator-boot-on;
+                                       /* Unused */
+                                       status = "disabled";
                                };
 
                                ldo9_reg: ldo9 {
+                                       /* VCC_DV_SDIO: vdds_sdcard */
                                        regulator-name = "ldo9";
                                        regulator-min-microvolt = <1800000>;
-                                       regulator-max-microvolt = <3300000>;
-                                       regulator-always-on;
+                                       regulator-max-microvolt = <3000000>;
                                        regulator-boot-on;
                                };
 
                                ldoln_reg: ldoln {
+                                       /* VDDA_1v8_REF: vdds_osc/mm_l4per.. */
                                        regulator-name = "ldoln";
                                        regulator-min-microvolt = <1800000>;
                                        regulator-max-microvolt = <1800000>;
                                };
 
                                ldousb_reg: ldousb {
+                                       /* VDDA_3V_USB: VDDA_USBHS33 */
                                        regulator-name = "ldousb";
                                        regulator-min-microvolt = <3250000>;
                                        regulator-max-microvolt = <3250000>;
                                        regulator-always-on;
                                        regulator-boot-on;
                                };
+
+                               regen3_reg: regen3 {
+                                       /* REGEN3 controls LDO9 supply to card */
+                                       regulator-name = "regen3";
+                                       regulator-always-on;
+                                       regulator-boot-on;
+                               };
                        };
                };
        };
index 7321403..f5b9898 100644 (file)
@@ -6,10 +6,12 @@
                #address-cells = <1>;
                #size-cells = <0>;
                cpu@0 {
+                       device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <0>;
                };
                cpu@1 {
+                       device_type = "cpu";
                        compatible = "arm,cortex-a9";
                        reg = <1>;
                };
index 2fcb3f2..5592be6 100644 (file)
        };
 
        usb-phy@c5004000 {
+               status = "okay";
                nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 1)
                        GPIO_ACTIVE_LOW>;
        };
diff --git a/arch/arm/include/asm/a.out-core.h b/arch/arm/include/asm/a.out-core.h
deleted file mode 100644 (file)
index 92f10cb..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/* a.out coredump register dumper
- *
- * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#ifndef _ASM_A_OUT_CORE_H
-#define _ASM_A_OUT_CORE_H
-
-#ifdef __KERNEL__
-
-#include <linux/user.h>
-#include <linux/elfcore.h>
-
-/*
- * fill in the user structure for an a.out core dump
- */
-static inline void aout_dump_thread(struct pt_regs *regs, struct user *dump)
-{
-       struct task_struct *tsk = current;
-
-       dump->magic = CMAGIC;
-       dump->start_code = tsk->mm->start_code;
-       dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
-
-       dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT;
-       dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       dump->u_ssize = 0;
-
-       memset(dump->u_debugreg, 0, sizeof(dump->u_debugreg));
-
-       if (dump->start_stack < 0x04000000)
-               dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
-
-       dump->regs = *regs;
-       dump->u_fpvalid = dump_fpu (regs, &dump->u_fp);
-}
-
-#endif /* __KERNEL__ */
-#endif /* _ASM_A_OUT_CORE_H */
index 8c25dc4..9672e97 100644 (file)
@@ -89,13 +89,18 @@ extern unsigned int processor_id;
                __val;                                                  \
        })
 
+/*
+ * The memory clobber prevents gcc 4.5 from reordering the mrc before
+ * any is_smp() tests, which can cause undefined instruction aborts on
+ * ARM1136 r0 due to the missing extended CP15 registers.
+ */
 #define read_cpuid_ext(ext_reg)                                                \
        ({                                                              \
                unsigned int __val;                                     \
                asm("mrc        p15, 0, %0, c0, " ext_reg               \
                    : "=r" (__val)                                      \
                    :                                                   \
-                   : "cc");                                            \
+                   : "memory");                                        \
                __val;                                                  \
        })
 
index 38050b1..56211f2 100644 (file)
@@ -130,4 +130,10 @@ struct mm_struct;
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
+#ifdef CONFIG_MMU
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+int arch_setup_additional_pages(struct linux_binprm *, int);
+#endif
+
 #endif
index e3d5554..6f18da0 100644 (file)
@@ -6,8 +6,11 @@
 typedef struct {
 #ifdef CONFIG_CPU_HAS_ASID
        atomic64_t      id;
+#else
+       int             switch_pending;
 #endif
        unsigned int    vmalloc_seq;
+       unsigned long   sigpage;
 } mm_context_t;
 
 #ifdef CONFIG_CPU_HAS_ASID
index b5792b7..9b32f76 100644 (file)
@@ -56,7 +56,7 @@ static inline void check_and_switch_context(struct mm_struct *mm,
                 * on non-ASID CPUs, the old mm will remain valid until the
                 * finish_arch_post_lock_switch() call.
                 */
-               set_ti_thread_flag(task_thread_info(tsk), TIF_SWITCH_MM);
+               mm->context.switch_pending = 1;
        else
                cpu_switch_mm(mm->pgd, mm);
 }
@@ -65,9 +65,21 @@ static inline void check_and_switch_context(struct mm_struct *mm,
        finish_arch_post_lock_switch
 static inline void finish_arch_post_lock_switch(void)
 {
-       if (test_and_clear_thread_flag(TIF_SWITCH_MM)) {
-               struct mm_struct *mm = current->mm;
-               cpu_switch_mm(mm->pgd, mm);
+       struct mm_struct *mm = current->mm;
+
+       if (mm && mm->context.switch_pending) {
+               /*
+                * Preemption must be disabled during cpu_switch_mm() as we
+                * have some stateful cache flush implementations. Check
+                * switch_pending again in case we were preempted and the
+                * switch to this mm was already done.
+                */
+               preempt_disable();
+               if (mm->context.switch_pending) {
+                       mm->context.switch_pending = 0;
+                       cpu_switch_mm(mm->pgd, mm);
+               }
+               preempt_enable_no_resched();
        }
 }
 
index 6363f3d..4355f0e 100644 (file)
@@ -142,7 +142,9 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from,
 #define clear_page(page)       memset((void *)(page), 0, PAGE_SIZE)
 extern void copy_page(void *to, const void *from);
 
+#ifdef CONFIG_KUSER_HELPERS
 #define __HAVE_ARCH_GATE_AREA 1
+#endif
 
 #ifdef CONFIG_ARM_LPAE
 #include <asm/pgtable-3level-types.h>
index 06e7d50..413f387 100644 (file)
@@ -54,7 +54,6 @@ struct thread_struct {
 
 #define start_thread(regs,pc,sp)                                       \
 ({                                                                     \
-       unsigned long *stack = (unsigned long *)sp;                     \
        memset(regs->uregs, 0, sizeof(regs->uregs));                    \
        if (current->personality & ADDR_LIMIT_32BIT)                    \
                regs->ARM_cpsr = USR_MODE;                              \
@@ -65,9 +64,6 @@ struct thread_struct {
        regs->ARM_cpsr |= PSR_ENDSTATE;                                 \
        regs->ARM_pc = pc & ~1;         /* pc */                        \
        regs->ARM_sp = sp;              /* sp */                        \
-       regs->ARM_r2 = stack[2];        /* r2 (envp) */                 \
-       regs->ARM_r1 = stack[1];        /* r1 (argv) */                 \
-       regs->ARM_r0 = stack[0];        /* r0 (argc) */                 \
        nommu_start_thread(regs);                                       \
 })
 
index 6462a72..a252c0b 100644 (file)
@@ -88,4 +88,7 @@ static inline u32 mpidr_hash_size(void)
 {
        return 1 << mpidr_hash.bits;
 }
+
+extern int platform_can_cpu_hotplug(void);
+
 #endif
index f8b8965..b07c09e 100644 (file)
@@ -107,7 +107,7 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock)
                "       subs    %1, %0, %0, ror #16\n"
                "       addeq   %0, %0, %4\n"
                "       strexeq %2, %0, [%3]"
-               : "=&r" (slock), "=&r" (contended), "=r" (res)
+               : "=&r" (slock), "=&r" (contended), "=&r" (res)
                : "r" (&lock->slock), "I" (1 << TICKET_SHIFT)
                : "cc");
        } while (res);
@@ -168,17 +168,20 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
 
 static inline int arch_write_trylock(arch_rwlock_t *rw)
 {
-       unsigned long tmp;
+       unsigned long contended, res;
 
-       __asm__ __volatile__(
-"      ldrex   %0, [%1]\n"
-"      teq     %0, #0\n"
-"      strexeq %0, %2, [%1]"
-       : "=&r" (tmp)
-       : "r" (&rw->lock), "r" (0x80000000)
-       : "cc");
+       do {
+               __asm__ __volatile__(
+               "       ldrex   %0, [%2]\n"
+               "       mov     %1, #0\n"
+               "       teq     %0, #0\n"
+               "       strexeq %1, %3, [%2]"
+               : "=&r" (contended), "=&r" (res)
+               : "r" (&rw->lock), "r" (0x80000000)
+               : "cc");
+       } while (res);
 
-       if (tmp == 0) {
+       if (!contended) {
                smp_mb();
                return 1;
        } else {
@@ -254,18 +257,26 @@ static inline void arch_read_unlock(arch_rwlock_t *rw)
 
 static inline int arch_read_trylock(arch_rwlock_t *rw)
 {
-       unsigned long tmp, tmp2 = 1;
+       unsigned long contended, res;
 
-       __asm__ __volatile__(
-"      ldrex   %0, [%2]\n"
-"      adds    %0, %0, #1\n"
-"      strexpl %1, %0, [%2]\n"
-       : "=&r" (tmp), "+r" (tmp2)
-       : "r" (&rw->lock)
-       : "cc");
+       do {
+               __asm__ __volatile__(
+               "       ldrex   %0, [%2]\n"
+               "       mov     %1, #0\n"
+               "       adds    %0, %0, #1\n"
+               "       strexpl %1, %0, [%2]"
+               : "=&r" (contended), "=&r" (res)
+               : "r" (&rw->lock)
+               : "cc");
+       } while (res);
 
-       smp_mb();
-       return tmp2 == 0;
+       /* If the lock is negative, then it is already held for write. */
+       if (contended < 0x80000000) {
+               smp_mb();
+               return 1;
+       } else {
+               return 0;
+       }
 }
 
 /* read_can_lock - would read_trylock() succeed? */
index 214d415..2b8114f 100644 (file)
@@ -156,7 +156,6 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *,
 #define TIF_USING_IWMMXT       17
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_RESTORE_SIGMASK    20
-#define TIF_SWITCH_MM          22      /* deferred switch_mm */
 
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
index 46e7cfb..0baf7f0 100644 (file)
@@ -43,6 +43,7 @@ struct mmu_gather {
        struct mm_struct        *mm;
        unsigned int            fullmm;
        struct vm_area_struct   *vma;
+       unsigned long           start, end;
        unsigned long           range_start;
        unsigned long           range_end;
        unsigned int            nr;
@@ -107,10 +108,12 @@ static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 }
 
 static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm)
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        tlb->mm = mm;
-       tlb->fullmm = fullmm;
+       tlb->fullmm = !(start | (end+1));
+       tlb->start = start;
+       tlb->end = end;
        tlb->vma = NULL;
        tlb->max = ARRAY_SIZE(tlb->local);
        tlb->pages = tlb->local;
index fdbb9e3..f467e9b 100644 (file)
@@ -443,7 +443,18 @@ static inline void local_flush_bp_all(void)
                isb();
 }
 
+#include <asm/cputype.h>
 #ifdef CONFIG_ARM_ERRATA_798181
+static inline int erratum_a15_798181(void)
+{
+       unsigned int midr = read_cpuid_id();
+
+       /* Cortex-A15 r0p0..r3p2 affected */
+       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
+               return 0;
+       return 1;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
        /*
@@ -453,6 +464,11 @@ static inline void dummy_flush_tlb_a15_erratum(void)
        dsb();
 }
 #else
+static inline int erratum_a15_798181(void)
+{
+       return 0;
+}
+
 static inline void dummy_flush_tlb_a15_erratum(void)
 {
 }
index 50af92b..4371f45 100644 (file)
@@ -29,6 +29,7 @@
 #define BOOT_CPU_MODE_MISMATCH PSR_N_BIT
 
 #ifndef __ASSEMBLY__
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_ARM_VIRT_EXT
 /*
  */
 extern int __boot_cpu_mode;
 
+static inline void sync_boot_mode(void)
+{
+       /*
+        * As secondaries write to __boot_cpu_mode with caches disabled, we
+        * must flush the corresponding cache entries to ensure the visibility
+        * of their writes.
+        */
+       sync_cache_r(&__boot_cpu_mode);
+}
+
 void __hyp_set_vectors(unsigned long phys_vector_base);
 unsigned long __hyp_get_vectors(void);
 #else
 #define __boot_cpu_mode        (SVC_MODE)
+#define sync_boot_mode()
 #endif
 
 #ifndef ZIMAGE
index 47bcb2d..18d76fd 100644 (file)
@@ -1,7 +1,6 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-header-y += a.out.h
 header-y += byteorder.h
 header-y += fcntl.h
 header-y += hwcap.h
diff --git a/arch/arm/include/uapi/asm/a.out.h b/arch/arm/include/uapi/asm/a.out.h
deleted file mode 100644 (file)
index 083894b..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __ARM_A_OUT_H__
-#define __ARM_A_OUT_H__
-
-#include <linux/personality.h>
-#include <linux/types.h>
-
-struct exec
-{
-  __u32 a_info;                /* Use macros N_MAGIC, etc for access */
-  __u32 a_text;                /* length of text, in bytes */
-  __u32 a_data;                /* length of data, in bytes */
-  __u32 a_bss;         /* length of uninitialized data area for file, in bytes */
-  __u32 a_syms;                /* length of symbol table data in file, in bytes */
-  __u32 a_entry;       /* start address */
-  __u32 a_trsize;      /* length of relocation info for text, in bytes */
-  __u32 a_drsize;      /* length of relocation info for data, in bytes */
-};
-
-/*
- * This is always the same
- */
-#define N_TXTADDR(a)   (0x00008000)
-
-#define N_TRSIZE(a)    ((a).a_trsize)
-#define N_DRSIZE(a)    ((a).a_drsize)
-#define N_SYMSIZE(a)   ((a).a_syms)
-
-#define M_ARM 103
-
-#ifndef LIBRARY_START_TEXT
-#define LIBRARY_START_TEXT     (0x00c00000)
-#endif
-
-#endif /* __A_OUT_GNU_H__ */
index a39cfc2..9cbe70c 100644 (file)
@@ -357,7 +357,8 @@ ENDPROC(__pabt_svc)
        .endm
 
        .macro  kuser_cmpxchg_check
-#if !defined(CONFIG_CPU_32v6K) && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
+#if !defined(CONFIG_CPU_32v6K) && defined(CONFIG_KUSER_HELPERS) && \
+    !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
 #ifndef CONFIG_MMU
 #warning "NPTL on non MMU needs fixing"
 #else
@@ -742,6 +743,18 @@ ENDPROC(__switch_to)
 #endif
        .endm
 
+       .macro  kuser_pad, sym, size
+       .if     (. - \sym) & 3
+       .rept   4 - (. - \sym) & 3
+       .byte   0
+       .endr
+       .endif
+       .rept   (\size - (. - \sym)) / 4
+       .word   0xe7fddef1
+       .endr
+       .endm
+
+#ifdef CONFIG_KUSER_HELPERS
        .align  5
        .globl  __kuser_helper_start
 __kuser_helper_start:
@@ -832,18 +845,13 @@ kuser_cmpxchg64_fixup:
 #error "incoherent kernel configuration"
 #endif
 
-       /* pad to next slot */
-       .rept   (16 - (. - __kuser_cmpxchg64)/4)
-       .word   0
-       .endr
-
-       .align  5
+       kuser_pad __kuser_cmpxchg64, 64
 
 __kuser_memory_barrier:                                @ 0xffff0fa0
        smp_dmb arm
        usr_ret lr
 
-       .align  5
+       kuser_pad __kuser_memory_barrier, 32
 
 __kuser_cmpxchg:                               @ 0xffff0fc0
 
@@ -916,13 +924,14 @@ kuser_cmpxchg32_fixup:
 
 #endif
 
-       .align  5
+       kuser_pad __kuser_cmpxchg, 32
 
 __kuser_get_tls:                               @ 0xffff0fe0
        ldr     r0, [pc, #(16 - 8)]     @ read TLS, set in kuser_get_tls_init
        usr_ret lr
        mrc     p15, 0, r0, c13, c0, 3  @ 0xffff0fe8 hardware TLS code
-       .rep    4
+       kuser_pad __kuser_get_tls, 16
+       .rep    3
        .word   0                       @ 0xffff0ff0 software TLS value, then
        .endr                           @ pad up to __kuser_helper_version
 
@@ -932,14 +941,16 @@ __kuser_helper_version:                           @ 0xffff0ffc
        .globl  __kuser_helper_end
 __kuser_helper_end:
 
+#endif
+
  THUMB(        .thumb  )
 
 /*
  * Vector stubs.
  *
- * This code is copied to 0xffff0200 so we can use branches in the
- * vectors, rather than ldr's.  Note that this code must not
- * exceed 0x300 bytes.
+ * This code is copied to 0xffff1000 so we can use branches in the
+ * vectors, rather than ldr's.  Note that this code must not exceed
+ * a page size.
  *
  * Common stub entry macro:
  *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
@@ -986,8 +997,17 @@ ENDPROC(vector_\name)
 1:
        .endm
 
-       .globl  __stubs_start
+       .section .stubs, "ax", %progbits
 __stubs_start:
+       @ This must be the first word
+       .word   vector_swi
+
+vector_rst:
+ ARM(  swi     SYS_ERROR0      )
+ THUMB(        svc     #0              )
+ THUMB(        nop                     )
+       b       vector_und
+
 /*
  * Interrupt dispatcher
  */
@@ -1082,6 +1102,16 @@ __stubs_start:
        .align  5
 
 /*=============================================================================
+ * Address exception handler
+ *-----------------------------------------------------------------------------
+ * These aren't too critical.
+ * (they're not supposed to happen, and won't happen in 32-bit data mode).
+ */
+
+vector_addrexcptn:
+       b       vector_addrexcptn
+
+/*=============================================================================
  * Undefined FIQs
  *-----------------------------------------------------------------------------
  * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
@@ -1094,45 +1124,19 @@ __stubs_start:
 vector_fiq:
        subs    pc, lr, #4
 
-/*=============================================================================
- * Address exception handler
- *-----------------------------------------------------------------------------
- * These aren't too critical.
- * (they're not supposed to happen, and won't happen in 32-bit data mode).
- */
-
-vector_addrexcptn:
-       b       vector_addrexcptn
-
-/*
- * We group all the following data together to optimise
- * for CPUs with separate I & D caches.
- */
-       .align  5
-
-.LCvswi:
-       .word   vector_swi
-
-       .globl  __stubs_end
-__stubs_end:
-
-       .equ    stubs_offset, __vectors_start + 0x200 - __stubs_start
+       .globl  vector_fiq_offset
+       .equ    vector_fiq_offset, vector_fiq
 
-       .globl  __vectors_start
+       .section .vectors, "ax", %progbits
 __vectors_start:
- ARM(  swi     SYS_ERROR0      )
- THUMB(        svc     #0              )
- THUMB(        nop                     )
-       W(b)    vector_und + stubs_offset
-       W(ldr)  pc, .LCvswi + stubs_offset
-       W(b)    vector_pabt + stubs_offset
-       W(b)    vector_dabt + stubs_offset
-       W(b)    vector_addrexcptn + stubs_offset
-       W(b)    vector_irq + stubs_offset
-       W(b)    vector_fiq + stubs_offset
-
-       .globl  __vectors_end
-__vectors_end:
+       W(b)    vector_rst
+       W(b)    vector_und
+       W(ldr)  pc, __vectors_start + 0x1000
+       W(b)    vector_pabt
+       W(b)    vector_dabt
+       W(b)    vector_addrexcptn
+       W(b)    vector_irq
+       W(b)    vector_fiq
 
        .data
 
index e00621f..52b2643 100644 (file)
@@ -49,7 +49,7 @@ __irq_entry:
        mov     r1, sp
        stmdb   sp!, {lr}
        @ routine called with r0 = irq number, r1 = struct pt_regs *
-       bl      nvic_do_IRQ
+       bl      nvic_handle_irq
 
        pop     {lr}
        @
index 2adda11..fc79202 100644 (file)
 #include <asm/irq.h>
 #include <asm/traps.h>
 
+#define FIQ_OFFSET ({                                  \
+               extern void *vector_fiq_offset;         \
+               (unsigned)&vector_fiq_offset;           \
+       })
+
 static unsigned long no_fiq_insn;
 
 /* Default reacquire function
@@ -79,14 +84,13 @@ int show_fiq_list(struct seq_file *p, int prec)
 
 void set_fiq_handler(void *start, unsigned int length)
 {
-#if defined(CONFIG_CPU_USE_DOMAINS)
-       memcpy((void *)0xffff001c, start, length);
-#else
-       memcpy(vectors_page + 0x1c, start, length);
-#endif
-       flush_icache_range(0xffff001c, 0xffff001c + length);
-       if (!vectors_high())
-               flush_icache_range(0x1c, 0x1c + length);
+       void *base = vectors_page;
+       unsigned offset = FIQ_OFFSET;
+
+       memcpy(base + offset, start, length);
+       if (!cache_is_vipt_nonaliasing())
+               flush_icache_range(base + offset, offset + length);
+       flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
 }
 
 int claim_fiq(struct fiq_handler *f)
@@ -144,6 +148,7 @@ EXPORT_SYMBOL(disable_fiq);
 
 void __init init_FIQ(int start)
 {
-       no_fiq_insn = *(unsigned long *)0xffff001c;
+       unsigned offset = FIQ_OFFSET;
+       no_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
        fiq_start = start;
 }
index b361de1..14235ba 100644 (file)
@@ -87,6 +87,7 @@ ENTRY(stext)
 ENDPROC(stext)
 
 #ifdef CONFIG_SMP
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 9cf6063..2c7cc1e 100644 (file)
@@ -343,6 +343,7 @@ __turn_mmu_on_loc:
        .long   __turn_mmu_on_end
 
 #if defined(CONFIG_SMP)
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 4910232..797b1a6 100644 (file)
@@ -56,8 +56,8 @@ ENTRY(__boot_cpu_mode)
        ldr     \reg3, [\reg2]
        ldr     \reg1, [\reg2, \reg3]
        cmp     \mode, \reg1            @ matches primary CPU boot mode?
-       orrne   r7, r7, #BOOT_CPU_MODE_MISMATCH
-       strne   r7, [r5, r6]            @ record what happened and give up
+       orrne   \reg1, \reg1, #BOOT_CPU_MODE_MISMATCH
+       strne   \reg1, [\reg2, \reg3]   @ record what happened and give up
        .endm
 
 #else  /* ZIMAGE */
index 4fb074c..d7c82df 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/mmu_context.h>
 #include <asm/cacheflush.h>
 #include <asm/mach-types.h>
+#include <asm/smp_plat.h>
 #include <asm/system_misc.h>
 
 extern const unsigned char relocate_new_kernel[];
@@ -39,6 +40,14 @@ int machine_kexec_prepare(struct kimage *image)
        int i, err;
 
        /*
+        * Validate that if the current HW supports SMP, then the SW supports
+        * and implements CPU hotplug for the current HW. If not, we won't be
+        * able to kexec reliably, so fail the prepare operation.
+        */
+       if (num_possible_cpus() > 1 && !platform_can_cpu_hotplug())
+               return -EINVAL;
+
+       /*
         * No segment at default ATAGs address. try to locate
         * a dtb using magic.
         */
@@ -134,10 +143,13 @@ void machine_kexec(struct kimage *image)
        unsigned long reboot_code_buffer_phys;
        void *reboot_code_buffer;
 
-       if (num_online_cpus() > 1) {
-               pr_err("kexec: error: multiple CPUs still online\n");
-               return;
-       }
+       /*
+        * This can only happen if machine_shutdown() failed to disable some
+        * CPU, and that can only happen if the checks in
+        * machine_kexec_prepare() were not correct. If this fails, we can't
+        * reliably kexec anyway, so BUG_ON is appropriate.
+        */
+       BUG_ON(num_online_cpus() > 1);
 
        page_list = image->head & PAGE_MASK;
 
index d9f5cd4..e186ee1 100644 (file)
@@ -53,7 +53,12 @@ armpmu_map_cache_event(const unsigned (*cache_map)
 static int
 armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
 {
-       int mapping = (*event_map)[config];
+       int mapping;
+
+       if (config >= PERF_COUNT_HW_MAX)
+               return -EINVAL;
+
+       mapping = (*event_map)[config];
        return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
 }
 
@@ -253,6 +258,9 @@ validate_event(struct pmu_hw_events *hw_events,
        struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
        struct pmu *leader_pmu = event->group_leader->pmu;
 
+       if (is_software_event(event))
+               return 1;
+
        if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF)
                return 1;
 
index d3ca4f6..94f6b05 100644 (file)
@@ -197,6 +197,7 @@ void machine_shutdown(void)
  */
 void machine_halt(void)
 {
+       local_irq_disable();
        smp_send_stop();
 
        local_irq_disable();
@@ -211,6 +212,7 @@ void machine_halt(void)
  */
 void machine_power_off(void)
 {
+       local_irq_disable();
        smp_send_stop();
 
        if (pm_power_off)
@@ -230,6 +232,7 @@ void machine_power_off(void)
  */
 void machine_restart(char *cmd)
 {
+       local_irq_disable();
        smp_send_stop();
 
        arm_pm_restart(reboot_mode, cmd);
@@ -426,10 +429,11 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
 }
 
 #ifdef CONFIG_MMU
+#ifdef CONFIG_KUSER_HELPERS
 /*
  * The vectors page is always readable from user space for the
- * atomic helpers and the signal restart code. Insert it into the
- * gate_vma so that it is visible through ptrace and /proc/<pid>/mem.
+ * atomic helpers. Insert it into the gate_vma so that it is visible
+ * through ptrace and /proc/<pid>/mem.
  */
 static struct vm_area_struct gate_vma = {
        .vm_start       = 0xffff0000,
@@ -458,9 +462,48 @@ int in_gate_area_no_mm(unsigned long addr)
 {
        return in_gate_area(NULL, addr);
 }
+#define is_gate_vma(vma)       ((vma) == &gate_vma)
+#else
+#define is_gate_vma(vma)       0
+#endif
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
-       return (vma == &gate_vma) ? "[vectors]" : NULL;
+       return is_gate_vma(vma) ? "[vectors]" :
+               (vma->vm_mm && vma->vm_start == vma->vm_mm->context.sigpage) ?
+                "[sigpage]" : NULL;
+}
+
+static struct page *signal_page;
+extern struct page *get_signal_page(void);
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long addr;
+       int ret;
+
+       if (!signal_page)
+               signal_page = get_signal_page();
+       if (!signal_page)
+               return -ENOMEM;
+
+       down_write(&mm->mmap_sem);
+       addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+       if (IS_ERR_VALUE(addr)) {
+               ret = addr;
+               goto up_fail;
+       }
+
+       ret = install_special_mapping(mm, addr, PAGE_SIZE,
+               VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+               &signal_page);
+
+       if (ret == 0)
+               mm->context.sigpage = addr;
+
+ up_fail:
+       up_write(&mm->mmap_sem);
+       return ret;
 }
 #endif
index 63af9a7..afc2489 100644 (file)
@@ -836,6 +836,8 @@ static int __init meminfo_cmp(const void *_a, const void *_b)
 void __init hyp_mode_check(void)
 {
 #ifdef CONFIG_ARM_VIRT_EXT
+       sync_boot_mode();
+
        if (is_hyp_mode_available()) {
                pr_info("CPU: All CPU(s) started in HYP mode.\n");
                pr_info("CPU: Virtualization extensions available.\n");
@@ -971,6 +973,7 @@ static const char *hwcap_str[] = {
        "vfpv4",
        "idiva",
        "idivt",
+       "vfpd32",
        "lpae",
        NULL
 };
index 1c16c35..ab33042 100644 (file)
@@ -8,6 +8,7 @@
  * published by the Free Software Foundation.
  */
 #include <linux/errno.h>
+#include <linux/random.h>
 #include <linux/signal.h>
 #include <linux/personality.h>
 #include <linux/uaccess.h>
 
 #include <asm/elf.h>
 #include <asm/cacheflush.h>
+#include <asm/traps.h>
 #include <asm/ucontext.h>
 #include <asm/unistd.h>
 #include <asm/vfp.h>
 
-#include "signal.h"
-
 /*
  * For ARM syscalls, we encode the syscall number into the instruction.
  */
 #define SWI_THUMB_SIGRETURN    (0xdf00 << 16 | 0x2700 | (__NR_sigreturn - __NR_SYSCALL_BASE))
 #define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (__NR_rt_sigreturn - __NR_SYSCALL_BASE))
 
-const unsigned long sigreturn_codes[7] = {
+static const unsigned long sigreturn_codes[7] = {
        MOV_R7_NR_SIGRETURN,    SWI_SYS_SIGRETURN,    SWI_THUMB_SIGRETURN,
        MOV_R7_NR_RT_SIGRETURN, SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN,
 };
 
+static unsigned long signal_return_offset;
+
 #ifdef CONFIG_CRUNCH
 static int preserve_crunch_context(struct crunch_sigframe __user *frame)
 {
@@ -400,14 +402,20 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
                    __put_user(sigreturn_codes[idx+1], rc+1))
                        return 1;
 
-               if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) {
+#ifdef CONFIG_MMU
+               if (cpsr & MODE32_BIT) {
+                       struct mm_struct *mm = current->mm;
+
                        /*
-                        * 32-bit code can use the new high-page
-                        * signal return code support except when the MPU has
-                        * protected the vectors page from PL0
+                        * 32-bit code can use the signal return page
+                        * except when the MPU has protected the vectors
+                        * page from PL0
                         */
-                       retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
-               } else {
+                       retcode = mm->context.sigpage + signal_return_offset +
+                                 (idx << 2) + thumb;
+               } else
+#endif
+               {
                        /*
                         * Ensure that the instruction cache sees
                         * the return code written onto the stack.
@@ -608,3 +616,33 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
        } while (thread_flags & _TIF_WORK_MASK);
        return 0;
 }
+
+struct page *get_signal_page(void)
+{
+       unsigned long ptr;
+       unsigned offset;
+       struct page *page;
+       void *addr;
+
+       page = alloc_pages(GFP_KERNEL, 0);
+
+       if (!page)
+               return NULL;
+
+       addr = page_address(page);
+
+       /* Give the signal return code some randomness */
+       offset = 0x200 + (get_random_int() & 0x7fc);
+       signal_return_offset = offset;
+
+       /*
+        * Copy signal return handlers into the vector page, and
+        * set sigreturn to be a pointer to these.
+        */
+       memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
+
+       ptr = (unsigned long)addr + offset;
+       flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
+
+       return page;
+}
diff --git a/arch/arm/kernel/signal.h b/arch/arm/kernel/signal.h
deleted file mode 100644 (file)
index 5ff067b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- *  linux/arch/arm/kernel/signal.h
- *
- *  Copyright (C) 2005-2009 Russell King.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define KERN_SIGRETURN_CODE    (CONFIG_VECTORS_BASE + 0x00000500)
-
-extern const unsigned long sigreturn_codes[7];
index c2b4f8f..2dc1934 100644 (file)
@@ -145,6 +145,16 @@ int boot_secondary(unsigned int cpu, struct task_struct *idle)
        return -ENOSYS;
 }
 
+int platform_can_cpu_hotplug(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       if (smp_ops.cpu_kill)
+               return 1;
+#endif
+
+       return 0;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 static void percpu_timer_stop(void);
 
index a98b62d..c2edfff 100644 (file)
@@ -70,23 +70,6 @@ static inline void ipi_flush_bp_all(void *ignored)
        local_flush_bp_all();
 }
 
-#ifdef CONFIG_ARM_ERRATA_798181
-static int erratum_a15_798181(void)
-{
-       unsigned int midr = read_cpuid_id();
-
-       /* Cortex-A15 r0p0..r3p2 affected */
-       if ((midr & 0xff0ffff0) != 0x410fc0f0 || midr > 0x413fc0f2)
-               return 0;
-       return 1;
-}
-#else
-static int erratum_a15_798181(void)
-{
-       return 0;
-}
-#endif
-
 static void ipi_flush_tlb_a15_erratum(void *arg)
 {
        dmb();
index cab094c..ab517fc 100644 (file)
@@ -35,8 +35,6 @@
 #include <asm/tls.h>
 #include <asm/system_misc.h>
 
-#include "signal.h"
-
 static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" };
 
 void *vectors_page;
@@ -800,15 +798,26 @@ void __init trap_init(void)
        return;
 }
 
-static void __init kuser_get_tls_init(unsigned long vectors)
+#ifdef CONFIG_KUSER_HELPERS
+static void __init kuser_init(void *vectors)
 {
+       extern char __kuser_helper_start[], __kuser_helper_end[];
+       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+
+       memcpy(vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+
        /*
         * vectors + 0xfe0 = __kuser_get_tls
         * vectors + 0xfe8 = hardware TLS instruction at 0xffff0fe8
         */
        if (tls_emu || has_tls_reg)
-               memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4);
+               memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);
 }
+#else
+static void __init kuser_init(void *vectors)
+{
+}
+#endif
 
 void __init early_trap_init(void *vectors_base)
 {
@@ -816,33 +825,30 @@ void __init early_trap_init(void *vectors_base)
        unsigned long vectors = (unsigned long)vectors_base;
        extern char __stubs_start[], __stubs_end[];
        extern char __vectors_start[], __vectors_end[];
-       extern char __kuser_helper_start[], __kuser_helper_end[];
-       int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+       unsigned i;
 
        vectors_page = vectors_base;
 
        /*
+        * Poison the vectors page with an undefined instruction.  This
+        * instruction is chosen to be undefined for both ARM and Thumb
+        * ISAs.  The Thumb version is an undefined instruction with a
+        * branch back to the undefined instruction.
+        */
+       for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)
+               ((u32 *)vectors_base)[i] = 0xe7fddef1;
+
+       /*
         * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
         * into the vector page, mapped at 0xffff0000, and ensure these
         * are visible to the instruction stream.
         */
        memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-       memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
-       memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
+       memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
 
-       /*
-        * Do processor specific fixups for the kuser helpers
-        */
-       kuser_get_tls_init(vectors);
-
-       /*
-        * Copy signal return handlers into the vector page, and
-        * set sigreturn to be a pointer to these.
-        */
-       memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
-              sigreturn_codes, sizeof(sigreturn_codes));
+       kuser_init(vectors_base);
 
-       flush_icache_range(vectors, vectors + PAGE_SIZE);
+       flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
        modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
 #else /* ifndef CONFIG_CPU_V7M */
        /*
index fa25e4e..7bcee5c 100644 (file)
@@ -148,6 +148,23 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        __init_begin = .;
 #endif
+       /*
+        * The vectors and stubs are relocatable code, and the
+        * only thing that matters is their relative offsets
+        */
+       __vectors_start = .;
+       .vectors 0 : AT(__vectors_start) {
+               *(.vectors)
+       }
+       . = __vectors_start + SIZEOF(.vectors);
+       __vectors_end = .;
+
+       __stubs_start = .;
+       .stubs 0x1000 : AT(__stubs_start) {
+               *(.stubs)
+       }
+       . = __stubs_start + SIZEOF(.stubs);
+       __stubs_end = .;
 
        INIT_TEXT_SECTION(8)
        .exit.text : {
index 00247c7..304f069 100644 (file)
@@ -108,8 +108,8 @@ static void __init dove_clk_init(void)
        orion_clkdev_add(NULL, "sdhci-dove.1", sdio1);
        orion_clkdev_add(NULL, "orion_nand", nand);
        orion_clkdev_add(NULL, "cafe1000-ccic.0", camera);
-       orion_clkdev_add(NULL, "kirkwood-i2s.0", i2s0);
-       orion_clkdev_add(NULL, "kirkwood-i2s.1", i2s1);
+       orion_clkdev_add(NULL, "mvebu-audio.0", i2s0);
+       orion_clkdev_add(NULL, "mvebu-audio.1", i2s1);
        orion_clkdev_add(NULL, "mv_crypto", crypto);
        orion_clkdev_add(NULL, "dove-ac97", ac97);
        orion_clkdev_add(NULL, "dove-pdma", pdma);
index e9238b5..1663de0 100644 (file)
@@ -264,7 +264,7 @@ void __init kirkwood_clk_init(void)
        orion_clkdev_add(NULL, MV_XOR_NAME ".1", xor1);
        orion_clkdev_add("0", "pcie", pex0);
        orion_clkdev_add("1", "pcie", pex1);
-       orion_clkdev_add(NULL, "kirkwood-i2s", audio);
+       orion_clkdev_add(NULL, "mvebu-audio", audio);
        orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".0", runit);
        orion_clkdev_add(NULL, MV64XXX_I2C_CTLR_NAME ".1", runit);
 
@@ -560,7 +560,7 @@ void __init kirkwood_timer_init(void)
 /*****************************************************************************
  * Audio
  ****************************************************************************/
-static struct resource kirkwood_i2s_resources[] = {
+static struct resource kirkwood_audio_resources[] = {
        [0] = {
                .start  = AUDIO_PHYS_BASE,
                .end    = AUDIO_PHYS_BASE + SZ_16K - 1,
@@ -573,29 +573,23 @@ static struct resource kirkwood_i2s_resources[] = {
        },
 };
 
-static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+static struct kirkwood_asoc_platform_data kirkwood_audio_data = {
        .burst       = 128,
 };
 
-static struct platform_device kirkwood_i2s_device = {
-       .name           = "kirkwood-i2s",
+static struct platform_device kirkwood_audio_device = {
+       .name           = "mvebu-audio",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(kirkwood_i2s_resources),
-       .resource       = kirkwood_i2s_resources,
+       .num_resources  = ARRAY_SIZE(kirkwood_audio_resources),
+       .resource       = kirkwood_audio_resources,
        .dev            = {
-               .platform_data  = &kirkwood_i2s_data,
+               .platform_data  = &kirkwood_audio_data,
        },
 };
 
-static struct platform_device kirkwood_pcm_device = {
-       .name           = "kirkwood-pcm-audio",
-       .id             = -1,
-};
-
 void __init kirkwood_audio_init(void)
 {
-       platform_device_register(&kirkwood_i2s_device);
-       platform_device_register(&kirkwood_pcm_device);
+       platform_device_register(&kirkwood_audio_device);
 }
 
 /*****************************************************************************
index 614e41e..905efc8 100644 (file)
@@ -121,8 +121,7 @@ config MSM_SMD
        bool
 
 config MSM_GPIOMUX
-       depends on !(ARCH_MSM8X60 || ARCH_MSM8960)
-       bool "MSM V1 TLMM GPIOMUX architecture"
+       bool
        help
          Support for MSM V1 TLMM GPIOMUX architecture.
 
diff --git a/arch/arm/mach-msm/gpiomux-v1.c b/arch/arm/mach-msm/gpiomux-v1.c
deleted file mode 100644 (file)
index 27de2ab..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-#include <linux/kernel.h>
-#include "gpiomux.h"
-#include "proc_comm.h"
-
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
-{
-       unsigned tlmm_config  = (val & ~GPIOMUX_CTL_MASK) |
-                               ((gpio & 0x3ff) << 4);
-       unsigned tlmm_disable = 0;
-       int rc;
-
-       rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
-                          &tlmm_config, &tlmm_disable);
-       if (rc)
-               pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n",
-                      __func__, rc, tlmm_config, tlmm_disable);
-}
index 8e82f41..4410d77 100644 (file)
@@ -73,16 +73,6 @@ extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
 int msm_gpiomux_write(unsigned gpio,
                      gpiomux_config_t active,
                      gpiomux_config_t suspended);
-
-/* Architecture-internal function for use by the framework only.
- * This function can assume the following:
- * - the gpio value has passed a bounds-check
- * - the gpiomux spinlock has been obtained
- *
- * This function is not for public consumption.  External users
- * should use msm_gpiomux_write.
- */
-void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
 #else
 static inline int msm_gpiomux_write(unsigned gpio,
                                    gpiomux_config_t active,
index 393aeef..043e570 100644 (file)
@@ -42,7 +42,7 @@
 
 /* Using generic display panel */
 static struct tfp410_platform_data omap4_dvi_panel = {
-       .i2c_bus_num            = 3,
+       .i2c_bus_num            = 2,
        .power_down_gpio        = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
 };
 
index 5cc9287..f99f68e 100644 (file)
@@ -129,6 +129,7 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
        struct device_node *node = pdev->dev.of_node;
        const char *oh_name;
        int oh_cnt, i, ret = 0;
+       bool device_active = false;
 
        oh_cnt = of_property_count_strings(node, "ti,hwmods");
        if (oh_cnt <= 0) {
@@ -152,6 +153,8 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
                        goto odbfd_exit1;
                }
                hwmods[i] = oh;
+               if (oh->flags & HWMOD_INIT_NO_IDLE)
+                       device_active = true;
        }
 
        od = omap_device_alloc(pdev, hwmods, oh_cnt);
@@ -172,6 +175,11 @@ static int omap_device_build_from_dt(struct platform_device *pdev)
 
        pdev->dev.pm_domain = &omap_device_pm_domain;
 
+       if (device_active) {
+               omap_device_enable(pdev);
+               pm_runtime_set_active(&pdev->dev);
+       }
+
 odbfd_exit1:
        kfree(hwmods);
 odbfd_exit:
@@ -842,6 +850,7 @@ static int __init omap_device_late_idle(struct device *dev, void *data)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct omap_device *od = to_omap_device(pdev);
+       int i;
 
        if (!od)
                return 0;
@@ -850,6 +859,15 @@ static int __init omap_device_late_idle(struct device *dev, void *data)
         * If omap_device state is enabled, but has no driver bound,
         * idle it.
         */
+
+       /*
+        * Some devices (like memory controllers) are always kept
+        * enabled, and should not be idled even with no drivers.
+        */
+       for (i = 0; i < od->hwmods_cnt; i++)
+               if (od->hwmods[i]->flags & HWMOD_INIT_NO_IDLE)
+                       return 0;
+
        if (od->_driver_status != BUS_NOTIFY_BOUND_DRIVER) {
                if (od->_state == OMAP_DEVICE_STATE_ENABLED) {
                        dev_warn(dev, "%s: enabled but no driver.  Idling\n",
index 7341eff..7f4db12 100644 (file)
@@ -2386,7 +2386,7 @@ static void __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data)
 
                np = of_dev_hwmod_lookup(of_find_node_by_name(NULL, "ocp"), oh);
                if (np)
-                       va_start = of_iomap(np, 0);
+                       va_start = of_iomap(np, oh->mpu_rt_idx);
        } else {
                va_start = ioremap(mem->pa_start, mem->pa_end - mem->pa_start);
        }
index aab33fd..e1482a9 100644 (file)
@@ -95,6 +95,54 @@ extern struct omap_hwmod_sysc_fields omap_hwmod_sysc_type3;
 #define MODULEMODE_HWCTRL              1
 #define MODULEMODE_SWCTRL              2
 
+#define DEBUG_OMAP2UART1_FLAGS 0
+#define DEBUG_OMAP2UART2_FLAGS 0
+#define DEBUG_OMAP2UART3_FLAGS 0
+#define DEBUG_OMAP3UART3_FLAGS 0
+#define DEBUG_OMAP3UART4_FLAGS 0
+#define DEBUG_OMAP4UART3_FLAGS 0
+#define DEBUG_OMAP4UART4_FLAGS 0
+#define DEBUG_TI81XXUART1_FLAGS        0
+#define DEBUG_TI81XXUART2_FLAGS        0
+#define DEBUG_TI81XXUART3_FLAGS        0
+#define DEBUG_AM33XXUART1_FLAGS        0
+
+#define DEBUG_OMAPUART_FLAGS   (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET)
+
+#if defined(CONFIG_DEBUG_OMAP2UART1)
+#undef DEBUG_OMAP2UART1_FLAGS
+#define DEBUG_OMAP2UART1_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP2UART2)
+#undef DEBUG_OMAP2UART2_FLAGS
+#define DEBUG_OMAP2UART2_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP2UART3)
+#undef DEBUG_OMAP2UART3_FLAGS
+#define DEBUG_OMAP2UART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP3UART3)
+#undef DEBUG_OMAP3UART3_FLAGS
+#define DEBUG_OMAP3UART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP3UART4)
+#undef DEBUG_OMAP3UART4_FLAGS
+#define DEBUG_OMAP3UART4_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP4UART3)
+#undef DEBUG_OMAP4UART3_FLAGS
+#define DEBUG_OMAP4UART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_OMAP4UART4)
+#undef DEBUG_OMAP4UART4_FLAGS
+#define DEBUG_OMAP4UART4_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_TI81XXUART1)
+#undef DEBUG_TI81XXUART1_FLAGS
+#define DEBUG_TI81XXUART1_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_TI81XXUART2)
+#undef DEBUG_TI81XXUART2_FLAGS
+#define DEBUG_TI81XXUART2_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_TI81XXUART3)
+#undef DEBUG_TI81XXUART3_FLAGS
+#define DEBUG_TI81XXUART3_FLAGS DEBUG_OMAPUART_FLAGS
+#elif defined(CONFIG_DEBUG_AM33XXUART1)
+#undef DEBUG_AM33XXUART1_FLAGS
+#define DEBUG_AM33XXUART1_FLAGS DEBUG_OMAPUART_FLAGS
+#endif
 
 /**
  * struct omap_hwmod_mux_info - hwmod specific mux configuration
@@ -568,6 +616,7 @@ struct omap_hwmod_link {
  * @voltdm: pointer to voltage domain (filled in at runtime)
  * @dev_attr: arbitrary device attributes that can be passed to the driver
  * @_sysc_cache: internal-use hwmod flags
+ * @mpu_rt_idx: index of device address space for register target (for DT boot)
  * @_mpu_rt_va: cached register target start address (internal use)
  * @_mpu_port: cached MPU register target slave (internal use)
  * @opt_clks_cnt: number of @opt_clks
@@ -617,6 +666,7 @@ struct omap_hwmod {
        struct list_head                node;
        struct omap_hwmod_ocp_if        *_mpu_port;
        u16                             flags;
+       u8                              mpu_rt_idx;
        u8                              response_lat;
        u8                              rst_lines_cnt;
        u8                              opt_clks_cnt;
index d05fc7b..56cebb0 100644 (file)
@@ -512,7 +512,7 @@ struct omap_hwmod omap2xxx_uart1_hwmod = {
        .mpu_irqs       = omap2_uart1_mpu_irqs,
        .sdma_reqs      = omap2_uart1_sdma_reqs,
        .main_clk       = "uart1_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP2UART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -532,7 +532,7 @@ struct omap_hwmod omap2xxx_uart2_hwmod = {
        .mpu_irqs       = omap2_uart2_mpu_irqs,
        .sdma_reqs      = omap2_uart2_sdma_reqs,
        .main_clk       = "uart2_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP2UART2_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -552,7 +552,7 @@ struct omap_hwmod omap2xxx_uart3_hwmod = {
        .mpu_irqs       = omap2_uart3_mpu_irqs,
        .sdma_reqs      = omap2_uart3_sdma_reqs,
        .main_clk       = "uart3_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP2UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
index 28bbd56..eb2f3b9 100644 (file)
@@ -562,6 +562,7 @@ static struct omap_hwmod am33xx_cpgmac0_hwmod = {
        .clkdm_name     = "cpsw_125mhz_clkdm",
        .flags          = (HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY),
        .main_clk       = "cpsw_125mhz_gclk",
+       .mpu_rt_idx     = 1,
        .prcm           = {
                .omap4  = {
                        .clkctrl_offs   = AM33XX_CM_PER_CPGMAC0_CLKCTRL_OFFSET,
@@ -1512,7 +1513,7 @@ static struct omap_hwmod am33xx_uart1_hwmod = {
        .name           = "uart1",
        .class          = &uart_class,
        .clkdm_name     = "l4_wkup_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_AM33XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .main_clk       = "dpll_per_m2_div4_wkupdm_ck",
        .prcm           = {
                .omap4  = {
index f7a3df2..0c3a427 100644 (file)
@@ -490,7 +490,7 @@ static struct omap_hwmod omap3xxx_uart1_hwmod = {
        .mpu_irqs       = omap2_uart1_mpu_irqs,
        .sdma_reqs      = omap2_uart1_sdma_reqs,
        .main_clk       = "uart1_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_TI81XXUART1_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -509,7 +509,7 @@ static struct omap_hwmod omap3xxx_uart2_hwmod = {
        .mpu_irqs       = omap2_uart2_mpu_irqs,
        .sdma_reqs      = omap2_uart2_sdma_reqs,
        .main_clk       = "uart2_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_TI81XXUART2_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = CORE_MOD,
@@ -528,7 +528,8 @@ static struct omap_hwmod omap3xxx_uart3_hwmod = {
        .mpu_irqs       = omap2_uart3_mpu_irqs,
        .sdma_reqs      = omap2_uart3_sdma_reqs,
        .main_clk       = "uart3_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP3UART3_FLAGS | DEBUG_TI81XXUART3_FLAGS |
+                               HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = OMAP3430_PER_MOD,
@@ -558,7 +559,7 @@ static struct omap_hwmod omap36xx_uart4_hwmod = {
        .mpu_irqs       = uart4_mpu_irqs,
        .sdma_reqs      = uart4_sdma_reqs,
        .main_clk       = "uart4_fck",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP3UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .prcm           = {
                .omap2 = {
                        .module_offs = OMAP3430_PER_MOD,
index d04b5e6..9c3b504 100644 (file)
@@ -2858,8 +2858,7 @@ static struct omap_hwmod omap44xx_uart3_hwmod = {
        .name           = "uart3",
        .class          = &omap44xx_uart_hwmod_class,
        .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET |
-                               HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP4UART3_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
@@ -2875,7 +2874,7 @@ static struct omap_hwmod omap44xx_uart4_hwmod = {
        .name           = "uart4",
        .class          = &omap44xx_uart_hwmod_class,
        .clkdm_name     = "l4_per_clkdm",
-       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .flags          = DEBUG_OMAP4UART4_FLAGS | HWMOD_SWSUP_SIDLE_ACT,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
index f37ae96..3c70f5c 100644 (file)
@@ -1375,7 +1375,7 @@ static struct omap_hwmod omap54xx_uart3_hwmod = {
        .name           = "uart3",
        .class          = &omap54xx_uart_hwmod_class,
        .clkdm_name     = "l4per_clkdm",
-       .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+       .flags          = DEBUG_OMAP4UART3_FLAGS,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
@@ -1391,6 +1391,7 @@ static struct omap_hwmod omap54xx_uart4_hwmod = {
        .name           = "uart4",
        .class          = &omap54xx_uart_hwmod_class,
        .clkdm_name     = "l4per_clkdm",
+       .flags          = DEBUG_OMAP4UART4_FLAGS,
        .main_clk       = "func_48m_fclk",
        .prcm = {
                .omap4 = {
index 3a674de..a388f8c 100644 (file)
@@ -208,17 +208,6 @@ static int __init omap_serial_early_init(void)
                                pr_info("%s used as console in debug mode: uart%d clocks will not be gated",
                                        uart_name, uart->num);
                        }
-
-                       /*
-                        * omap-uart can be used for earlyprintk logs
-                        * So if omap-uart is used as console then prevent
-                        * uart reset and idle to get logs from omap-uart
-                        * until uart console driver is available to take
-                        * care for console messages.
-                        * Idling or resetting omap-uart while printing logs
-                        * early boot logs can stall the boot-up.
-                        */
-                       oh->flags |= HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET;
                }
        } while (1);
 
index e115f67..c5be60d 100644 (file)
@@ -1162,9 +1162,6 @@ static void __init eva_init(void)
        gpio_request_one(61, GPIOF_OUT_INIT_HIGH, NULL); /* LCDDON */
        gpio_request_one(202, GPIOF_OUT_INIT_LOW, NULL); /* LCD0_LED_CONT */
 
-       /* Touchscreen */
-       gpio_request_one(166, GPIOF_OUT_INIT_HIGH, NULL); /* TP_RST_B */
-
        /* GETHER */
        gpio_request_one(18, GPIOF_OUT_INIT_HIGH, NULL); /* PHY_RST */
 
index d555464..3354a85 100644 (file)
@@ -167,7 +167,13 @@ static const struct pinctrl_map bockw_pinctrl_map[] = {
                                  "usb1", "usb1"),
        /* SDHI0 */
        PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
-                                 "sdhi0", "sdhi0"),
+                                 "sdhi0_data4", "sdhi0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
+                                 "sdhi0_ctrl", "sdhi0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
+                                 "sdhi0_cd", "sdhi0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
+                                 "sdhi0_wp", "sdhi0"),
 };
 
 #define FPGA   0x18200000
index d73e21d..8d6bd5c 100644 (file)
@@ -59,7 +59,7 @@ static __initdata struct gpio_led_platform_data lager_leds_pdata = {
 #define GPIO_KEY(c, g, d, ...) \
        { .code = c, .gpio = g, .desc = d, .active_low = 1 }
 
-static __initdata struct gpio_keys_button gpio_buttons[] = {
+static struct gpio_keys_button gpio_buttons[] = {
        GPIO_KEY(KEY_4,         RCAR_GP_PIN(1, 28),     "SW2-pin4"),
        GPIO_KEY(KEY_3,         RCAR_GP_PIN(1, 26),     "SW2-pin3"),
        GPIO_KEY(KEY_2,         RCAR_GP_PIN(1, 24),     "SW2-pin2"),
index 78ebc75..4c09bae 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 
-       __INIT
-
 /*
  * ST specific entry point for secondary CPUs.  This provides
  * a "holding pen" into which all secondary cores are held until we're
index 6cacdc8..db5c2ca 100644 (file)
@@ -421,24 +421,28 @@ config CPU_32v3
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v4
        bool
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v4T
        bool
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v5
        bool
        select CPU_USE_DOMAINS if MMU
        select NEEDS_SYSCALL_FOR_CMPXCHG if SMP
        select TLS_REG_EMUL if SMP || !MMU
+       select NEED_KUSER_HELPERS
 
 config CPU_32v6
        bool
@@ -776,6 +780,7 @@ config CPU_BPREDICT_DISABLE
 
 config TLS_REG_EMUL
        bool
+       select NEED_KUSER_HELPERS
        help
          An SMP system using a pre-ARMv6 processor (there are apparently
          a few prototypes like that in existence) and therefore access to
@@ -783,11 +788,40 @@ config TLS_REG_EMUL
 
 config NEEDS_SYSCALL_FOR_CMPXCHG
        bool
+       select NEED_KUSER_HELPERS
        help
          SMP on a pre-ARMv6 processor?  Well OK then.
          Forget about fast user space cmpxchg support.
          It is just not possible.
 
+config NEED_KUSER_HELPERS
+       bool
+
+config KUSER_HELPERS
+       bool "Enable kuser helpers in vector page" if !NEED_KUSER_HELPERS
+       default y
+       help
+         Warning: disabling this option may break user programs.
+
+         Provide kuser helpers in the vector page.  The kernel provides
+         helper code to userspace in read only form at a fixed location
+         in the high vector page to allow userspace to be independent of
+         the CPU type fitted to the system.  This permits binaries to be
+         run on ARMv4 through to ARMv7 without modification.
+
+         However, the fixed address nature of these helpers can be used
+         by ROP (return orientated programming) authors when creating
+         exploits.
+
+         If all of the binaries and libraries which run on your platform
+         are built specifically for your platform, and make no use of
+         these helpers, then you can turn this option off.  However,
+         when such an binary or library is run, it will receive a SIGILL
+         signal, which will terminate the program.
+
+         Say N here only if you are absolutely certain that you do not
+         need these helpers; otherwise, the safe option is to say Y.
+
 config DMA_CACHE_RWFO
        bool "Enable read/write for ownership DMA cache maintenance"
        depends on CPU_V6K && SMP
index b55b101..4a05444 100644 (file)
@@ -245,7 +245,8 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
        if (cpumask_test_and_clear_cpu(cpu, &tlb_flush_pending)) {
                local_flush_bp_all();
                local_flush_tlb_all();
-               dummy_flush_tlb_a15_erratum();
+               if (erratum_a15_798181())
+                       dummy_flush_tlb_a15_erratum();
        }
 
        atomic64_set(&per_cpu(active_asids, cpu), asid);
index 4f56617..53cdbd3 100644 (file)
@@ -989,6 +989,7 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
 
 void __init sanity_check_meminfo(void)
 {
+       phys_addr_t memblock_limit = 0;
        int i, j, highmem = 0;
        phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
 
@@ -1052,9 +1053,32 @@ void __init sanity_check_meminfo(void)
                        bank->size = size_limit;
                }
 #endif
-               if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit)
-                       arm_lowmem_limit = bank->start + bank->size;
+               if (!bank->highmem) {
+                       phys_addr_t bank_end = bank->start + bank->size;
 
+                       if (bank_end > arm_lowmem_limit)
+                               arm_lowmem_limit = bank_end;
+
+                       /*
+                        * Find the first non-section-aligned page, and point
+                        * memblock_limit at it. This relies on rounding the
+                        * limit down to be section-aligned, which happens at
+                        * the end of this function.
+                        *
+                        * With this algorithm, the start or end of almost any
+                        * bank can be non-section-aligned. The only exception
+                        * is that the start of the bank 0 must be section-
+                        * aligned, since otherwise memory would need to be
+                        * allocated when mapping the start of bank 0, which
+                        * occurs before any free memory is mapped.
+                        */
+                       if (!memblock_limit) {
+                               if (!IS_ALIGNED(bank->start, SECTION_SIZE))
+                                       memblock_limit = bank->start;
+                               else if (!IS_ALIGNED(bank_end, SECTION_SIZE))
+                                       memblock_limit = bank_end;
+                       }
+               }
                j++;
        }
 #ifdef CONFIG_HIGHMEM
@@ -1079,7 +1103,18 @@ void __init sanity_check_meminfo(void)
 #endif
        meminfo.nr_banks = j;
        high_memory = __va(arm_lowmem_limit - 1) + 1;
-       memblock_set_current_limit(arm_lowmem_limit);
+
+       /*
+        * Round the memblock limit down to a section size.  This
+        * helps to ensure that we will allocate memory from the
+        * last full section, which should be mapped.
+        */
+       if (memblock_limit)
+               memblock_limit = round_down(memblock_limit, SECTION_SIZE);
+       if (!memblock_limit)
+               memblock_limit = arm_lowmem_limit;
+
+       memblock_set_current_limit(memblock_limit);
 }
 
 static inline void prepare_page_table(void)
@@ -1160,7 +1195,7 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
        /*
         * Allocate the vector page early.
         */
-       vectors = early_alloc(PAGE_SIZE);
+       vectors = early_alloc(PAGE_SIZE * 2);
 
        early_trap_init(vectors);
 
@@ -1205,15 +1240,27 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
        map.pfn = __phys_to_pfn(virt_to_phys(vectors));
        map.virtual = 0xffff0000;
        map.length = PAGE_SIZE;
+#ifdef CONFIG_KUSER_HELPERS
        map.type = MT_HIGH_VECTORS;
+#else
+       map.type = MT_LOW_VECTORS;
+#endif
        create_mapping(&map);
 
        if (!vectors_high()) {
                map.virtual = 0;
+               map.length = PAGE_SIZE * 2;
                map.type = MT_LOW_VECTORS;
                create_mapping(&map);
        }
 
+       /* Now create a kernel read-only mapping */
+       map.pfn += 1;
+       map.virtual = 0xffff0000 + PAGE_SIZE;
+       map.length = PAGE_SIZE;
+       map.type = MT_LOW_VECTORS;
+       create_mapping(&map);
+
        /*
         * Ask the machine support to map in the statically mapped devices.
         */
@@ -1276,8 +1323,6 @@ void __init paging_init(struct machine_desc *mdesc)
 {
        void *zero_page;
 
-       memblock_set_current_limit(arm_lowmem_limit);
-
        build_mem_type_table();
        prepare_page_table();
        map_lowmem();
index f64afb9..bdd3be4 100644 (file)
@@ -110,7 +110,7 @@ ENTRY(cpu_v7_set_pte_ext)
  ARM(  str     r3, [r0, #2048]! )
  THUMB(        add     r0, r0, #2048 )
  THUMB(        str     r3, [r0] )
-       ALT_SMP(mov     pc,lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index c36ac69..01a719e 100644 (file)
@@ -81,7 +81,7 @@ ENTRY(cpu_v7_set_pte_ext)
        tst     r3, #1 << (55 - 32)             @ L_PTE_DIRTY
        orreq   r2, #L_PTE_RDONLY
 1:     strd    r2, r3, [r0]
-       ALT_SMP(mov     pc, lr)
+       ALT_SMP(W(nop))
        ALT_UP (mcr     p15, 0, r0, c7, c10, 1)         @ flush_pte
 #endif
        mov     pc, lr
index 5c6d5a3..73398bc 100644 (file)
@@ -75,13 +75,14 @@ ENTRY(cpu_v7_do_idle)
 ENDPROC(cpu_v7_do_idle)
 
 ENTRY(cpu_v7_dcache_clean_area)
-       ALT_SMP(mov     pc, lr)                 @ MP extensions imply L1 PTW
-       ALT_UP(W(nop))
-       dcache_line_size r2, r3
-1:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
+       ALT_SMP(W(nop))                 @ MP extensions imply L1 PTW
+       ALT_UP_B(1f)
+       mov     pc, lr
+1:     dcache_line_size r2, r3
+2:     mcr     p15, 0, r0, c7, c10, 1          @ clean D entry
        add     r0, r0, r2
        subs    r1, r1, r2
-       bhi     1b
+       bhi     2b
        dsb
        mov     pc, lr
 ENDPROC(cpu_v7_dcache_clean_area)
index 8e11e96..c83f27b 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/platform_device.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/irq.h>
 #include <mach/hardware.h>
@@ -60,6 +62,30 @@ struct ssp_device *pxa_ssp_request(int port, const char *label)
 }
 EXPORT_SYMBOL(pxa_ssp_request);
 
+struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
+                                     const char *label)
+{
+       struct ssp_device *ssp = NULL;
+
+       mutex_lock(&ssp_lock);
+
+       list_for_each_entry(ssp, &ssp_list, node) {
+               if (ssp->of_node == of_node && ssp->use_count == 0) {
+                       ssp->use_count++;
+                       ssp->label = label;
+                       break;
+               }
+       }
+
+       mutex_unlock(&ssp_lock);
+
+       if (&ssp->node == &ssp_list)
+               return NULL;
+
+       return ssp;
+}
+EXPORT_SYMBOL(pxa_ssp_request_of);
+
 void pxa_ssp_free(struct ssp_device *ssp)
 {
        mutex_lock(&ssp_lock);
@@ -72,96 +98,126 @@ void pxa_ssp_free(struct ssp_device *ssp)
 }
 EXPORT_SYMBOL(pxa_ssp_free);
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ssp_of_ids[] = {
+       { .compatible = "mrvl,pxa25x-ssp",      .data = (void *) PXA25x_SSP },
+       { .compatible = "mvrl,pxa25x-nssp",     .data = (void *) PXA25x_NSSP },
+       { .compatible = "mrvl,pxa27x-ssp",      .data = (void *) PXA27x_SSP },
+       { .compatible = "mrvl,pxa3xx-ssp",      .data = (void *) PXA3xx_SSP },
+       { .compatible = "mvrl,pxa168-ssp",      .data = (void *) PXA168_SSP },
+       { .compatible = "mrvl,pxa910-ssp",      .data = (void *) PXA910_SSP },
+       { .compatible = "mrvl,ce4100-ssp",      .data = (void *) CE4100_SSP },
+       { .compatible = "mrvl,lpss-ssp",        .data = (void *) LPSS_SSP },
+       { },
+};
+MODULE_DEVICE_TABLE(of, pxa_ssp_of_ids);
+#endif
+
 static int pxa_ssp_probe(struct platform_device *pdev)
 {
-       const struct platform_device_id *id = platform_get_device_id(pdev);
        struct resource *res;
        struct ssp_device *ssp;
-       int ret = 0;
+       struct device *dev = &pdev->dev;
 
-       ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
-       if (ssp == NULL) {
-               dev_err(&pdev->dev, "failed to allocate memory");
+       ssp = devm_kzalloc(dev, sizeof(struct ssp_device), GFP_KERNEL);
+       if (ssp == NULL)
                return -ENOMEM;
-       }
-       ssp->pdev = pdev;
 
-       ssp->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(ssp->clk)) {
-               ret = PTR_ERR(ssp->clk);
-               goto err_free;
-       }
+       ssp->pdev = pdev;
 
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
-       }
-       ssp->drcmr_rx = res->start;
+       ssp->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(ssp->clk))
+               return PTR_ERR(ssp->clk);
+
+       if (dev->of_node) {
+               struct of_phandle_args dma_spec;
+               struct device_node *np = dev->of_node;
+
+               /*
+                * FIXME: we should allocate the DMA channel from this
+                * context and pass the channel down to the ssp users.
+                * For now, we lookup the rx and tx indices manually
+                */
+
+               /* rx */
+               of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+                                          0, &dma_spec);
+               ssp->drcmr_rx = dma_spec.args[0];
+               of_node_put(dma_spec.np);
+
+               /* tx */
+               of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+                                          1, &dma_spec);
+               ssp->drcmr_tx = dma_spec.args[0];
+               of_node_put(dma_spec.np);
+       } else {
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (res == NULL) {
+                       dev_err(dev, "no SSP RX DRCMR defined\n");
+                       return -ENODEV;
+               }
+               ssp->drcmr_rx = res->start;
 
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (res == NULL) {
+                       dev_err(dev, "no SSP TX DRCMR defined\n");
+                       return -ENODEV;
+               }
+               ssp->drcmr_tx = res->start;
        }
-       ssp->drcmr_tx = res->start;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
-               dev_err(&pdev->dev, "no memory resource defined\n");
-               ret = -ENODEV;
-               goto err_free_clk;
+               dev_err(dev, "no memory resource defined\n");
+               return -ENODEV;
        }
 
-       res = request_mem_region(res->start, resource_size(res),
-                       pdev->name);
+       res = devm_request_mem_region(dev, res->start, resource_size(res),
+                                     pdev->name);
        if (res == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto err_free_clk;
+               dev_err(dev, "failed to request memory resource\n");
+               return -EBUSY;
        }
 
        ssp->phys_base = res->start;
 
-       ssp->mmio_base = ioremap(res->start, resource_size(res));
+       ssp->mmio_base = devm_ioremap(dev, res->start, resource_size(res));
        if (ssp->mmio_base == NULL) {
-               dev_err(&pdev->dev, "failed to ioremap() registers\n");
-               ret = -ENODEV;
-               goto err_free_mem;
+               dev_err(dev, "failed to ioremap() registers\n");
+               return -ENODEV;
        }
 
        ssp->irq = platform_get_irq(pdev, 0);
        if (ssp->irq < 0) {
-               dev_err(&pdev->dev, "no IRQ resource defined\n");
-               ret = -ENODEV;
-               goto err_free_io;
+               dev_err(dev, "no IRQ resource defined\n");
+               return -ENODEV;
+       }
+
+       if (dev->of_node) {
+               const struct of_device_id *id =
+                       of_match_device(of_match_ptr(pxa_ssp_of_ids), dev);
+               ssp->type = (int) id->data;
+       } else {
+               const struct platform_device_id *id =
+                       platform_get_device_id(pdev);
+               ssp->type = (int) id->driver_data;
+
+               /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
+                * starts from 0, do a translation here
+                */
+               ssp->port_id = pdev->id + 1;
        }
 
-       /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
-        * starts from 0, do a translation here
-        */
-       ssp->port_id = pdev->id + 1;
        ssp->use_count = 0;
-       ssp->type = (int)id->driver_data;
+       ssp->of_node = dev->of_node;
 
        mutex_lock(&ssp_lock);
        list_add(&ssp->node, &ssp_list);
        mutex_unlock(&ssp_lock);
 
        platform_set_drvdata(pdev, ssp);
-       return 0;
 
-err_free_io:
-       iounmap(ssp->mmio_base);
-err_free_mem:
-       release_mem_region(res->start, resource_size(res));
-err_free_clk:
-       clk_put(ssp->clk);
-err_free:
-       kfree(ssp);
-       return ret;
+       return 0;
 }
 
 static int pxa_ssp_remove(struct platform_device *pdev)
@@ -201,8 +257,9 @@ static struct platform_driver pxa_ssp_driver = {
        .probe          = pxa_ssp_probe,
        .remove         = pxa_ssp_remove,
        .driver         = {
-               .owner  = THIS_MODULE,
-               .name   = "pxa2xx-ssp",
+               .owner          = THIS_MODULE,
+               .name           = "pxa2xx-ssp",
+               .of_match_table = of_match_ptr(pxa_ssp_of_ids),
        },
        .id_table       = ssp_id_table,
 };
index f71c37e..c9770ba 100644 (file)
@@ -172,7 +172,7 @@ static void __init xen_percpu_init(void *unused)
        enable_percpu_irq(xen_events_irq, 0);
 }
 
-static void xen_restart(char str, const char *cmd)
+static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
 {
        struct sched_shutdown r = { .reason = SHUTDOWN_reboot };
        int rc;
index 46b3beb..717031a 100644 (file)
@@ -35,6 +35,7 @@ struct mmu_gather {
        struct mm_struct        *mm;
        unsigned int            fullmm;
        struct vm_area_struct   *vma;
+       unsigned long           start, end;
        unsigned long           range_start;
        unsigned long           range_end;
        unsigned int            nr;
@@ -97,10 +98,12 @@ static inline void tlb_flush_mmu(struct mmu_gather *tlb)
 }
 
 static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm)
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        tlb->mm = mm;
-       tlb->fullmm = fullmm;
+       tlb->fullmm = !(start | (end+1));
+       tlb->start = start;
+       tlb->end = end;
        tlb->vma = NULL;
        tlb->max = ARRAY_SIZE(tlb->local);
        tlb->pages = tlb->local;
index f914319..7de083d 100644 (file)
@@ -150,7 +150,6 @@ static struct ac97c_platform_data __initdata ac97c0_data = {
 static struct platform_device rmt_ts_device = {
        .name   = "ucb1400_ts",
        .id     = -1,
-       }
 };
 #endif
 
index 33a9792..77d442a 100644 (file)
@@ -158,6 +158,7 @@ source "kernel/Kconfig.hz"
 endmenu
 
 source "init/Kconfig"
+source "kernel/Kconfig.freezer"
 source "drivers/Kconfig"
 source "fs/Kconfig"
 
index 7913695..efbd292 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_ACPI_FAN=m
 CONFIG_ACPI_DOCK=y
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index f8e9133..f64980d 100644 (file)
@@ -25,7 +25,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index a5a9e02..0f4e9e4 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index 37b9b42..b025acf 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_ACPI_BUTTON=m
 CONFIG_ACPI_FAN=m
 CONFIG_ACPI_PROCESSOR=m
 CONFIG_ACPI_CONTAINER=m
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_ACPI=m
 CONFIG_PACKET=y
 CONFIG_UNIX=y
index ef3a9de..bc5efc7 100644 (file)
@@ -22,7 +22,7 @@
  * unmapping a portion of the virtual address space, these hooks are called according to
  * the following template:
  *
- *     tlb <- tlb_gather_mmu(mm, full_mm_flush);       // start unmap for address space MM
+ *     tlb <- tlb_gather_mmu(mm, start, end);          // start unmap for address space MM
  *     {
  *       for each vma that needs a shootdown do {
  *         tlb_start_vma(tlb, vma);
@@ -58,6 +58,7 @@ struct mmu_gather {
        unsigned int            max;
        unsigned char           fullmm;         /* non-zero means full mm flush */
        unsigned char           need_flush;     /* really unmapped some PTEs? */
+       unsigned long           start, end;
        unsigned long           start_addr;
        unsigned long           end_addr;
        struct page             **pages;
@@ -155,13 +156,15 @@ static inline void __tlb_alloc_page(struct mmu_gather *tlb)
 
 
 static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        tlb->mm = mm;
        tlb->max = ARRAY_SIZE(tlb->local);
        tlb->pages = tlb->local;
        tlb->nr = 0;
-       tlb->fullmm = full_mm_flush;
+       tlb->fullmm = !(start | (end+1));
+       tlb->start = start;
+       tlb->end = end;
        tlb->start_addr = ~0UL;
 }
 
index 2291a7d..fa277ae 100644 (file)
 #include <asm/machdep.h>
 #include <asm/natfeat.h>
 
+extern long nf_get_id2(const char *feature_name);
+
 asm("\n"
-"      .global nf_get_id,nf_call\n"
-"nf_get_id:\n"
+"      .global nf_get_id2,nf_call\n"
+"nf_get_id2:\n"
 "      .short  0x7300\n"
 "      rts\n"
 "nf_call:\n"
@@ -29,12 +31,25 @@ asm("\n"
 "1:    moveq.l #0,%d0\n"
 "      rts\n"
 "      .section __ex_table,\"a\"\n"
-"      .long   nf_get_id,1b\n"
+"      .long   nf_get_id2,1b\n"
 "      .long   nf_call,1b\n"
 "      .previous");
-EXPORT_SYMBOL_GPL(nf_get_id);
 EXPORT_SYMBOL_GPL(nf_call);
 
+long nf_get_id(const char *feature_name)
+{
+       /* feature_name may be in vmalloc()ed memory, so make a copy */
+       char name_copy[32];
+       size_t n;
+
+       n = strlcpy(name_copy, feature_name, sizeof(name_copy));
+       if (n >= sizeof(name_copy))
+               return 0;
+
+       return nf_get_id2(name_copy);
+}
+EXPORT_SYMBOL_GPL(nf_get_id);
+
 void nfprint(const char *fmt, ...)
 {
        static char buf[256];
index 444ea8a..ef881cf 100644 (file)
                unsigned long long n64;                         \
        } __n;                                                  \
        unsigned long __rem, __upper;                           \
+       unsigned long __base = (base);                          \
                                                                \
        __n.n64 = (n);                                          \
        if ((__upper = __n.n32[0])) {                           \
                asm ("divul.l %2,%1:%0"                         \
-                       : "=d" (__n.n32[0]), "=d" (__upper)     \
-                       : "d" (base), "0" (__n.n32[0]));        \
+                    : "=d" (__n.n32[0]), "=d" (__upper)        \
+                    : "d" (__base), "0" (__n.n32[0]));         \
        }                                                       \
        asm ("divu.l %2,%1:%0"                                  \
-               : "=d" (__n.n32[1]), "=d" (__rem)               \
-               : "d" (base), "1" (__upper), "0" (__n.n32[1])); \
+            : "=d" (__n.n32[1]), "=d" (__rem)                  \
+            : "d" (__base), "1" (__upper), "0" (__n.n32[1]));  \
        (n) = __n.n64;                                          \
        __rem;                                                  \
 })
index d22a4ec..4fab522 100644 (file)
@@ -28,7 +28,7 @@ config MICROBLAZE
        select GENERIC_CLOCKEVENTS
        select GENERIC_IDLE_POLL_SETUP
        select MODULES_USE_ELF_RELA
-       select CLONE_BACKWARDS
+       select CLONE_BACKWARDS3
 
 config SWAP
        def_bool n
index c3abed3..e12764c 100644 (file)
@@ -114,6 +114,7 @@ config BCM47XX
        select FW_CFE
        select HW_HAS_PCI
        select IRQ_CPU
+       select SYS_HAS_CPU_MIPS32_R1
        select NO_EXCEPT_FILL
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
index ba61192..2b8b118 100644 (file)
@@ -2,7 +2,6 @@ if BCM47XX
 
 config BCM47XX_SSB
        bool "SSB Support for Broadcom BCM47XX"
-       select SYS_HAS_CPU_MIPS32_R1
        select SSB
        select SSB_DRIVER_MIPS
        select SSB_DRIVER_EXTIF
index 1dc0860..fa44f3e 100644 (file)
@@ -17,6 +17,8 @@
 #define current_cpu_type()     current_cpu_data.cputype
 #endif
 
+#define boot_cpu_type()                cpu_data[0].cputype
+
 /*
  * SMP assumption: Options of CPU 0 are a superset of all processors.
  * This is true for all known MIPS systems.
index 5b2f2e6..9488fa5 100644 (file)
 #else
 #define CAC_BASE               _AC(0x80000000, UL)
 #endif
+#ifndef IO_BASE
 #define IO_BASE                        _AC(0xa0000000, UL)
+#endif
+#ifndef UNCAC_BASE
 #define UNCAC_BASE             _AC(0xa0000000, UL)
+#endif
 
 #ifndef MAP_BASE
 #ifdef CONFIG_KVM_GUEST
index b7a2306..88e292b 100644 (file)
@@ -25,11 +25,12 @@ struct siginfo;
 /*
  * Careful to keep union _sifields from shifting ...
  */
-#if __SIZEOF_LONG__ == 4
+#if _MIPS_SZLONG == 32
 #define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int))
-#endif
-#if __SIZEOF_LONG__ == 8
+#elif _MIPS_SZLONG == 64
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
+#else
+#error _MIPS_SZLONG neither 32 nor 64
 #endif
 
 #include <asm-generic/siginfo.h>
index f739aed..bd79c4f 100644 (file)
@@ -54,7 +54,11 @@ LEAF(bmips_smp_movevec)
        /* set up CPU1 CBR; move BASE to 0xa000_0000 */
        li      k0, 0xff400000
        mtc0    k0, $22, 6
-       li      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_1
+       /* set up relocation vector address based on thread ID */
+       mfc0    k1, $22, 3
+       srl     k1, 16
+       andi    k1, 0x8000
+       or      k1, CKSEG1 | BMIPS_RELO_VECTOR_CONTROL_0
        or      k0, k1
        li      k1, 0xa0080000
        sw      k1, 0(k0)
index c0bb4d5..126da74 100644 (file)
@@ -66,6 +66,8 @@ static void __init bmips_smp_setup(void)
        int i, cpu = 1, boot_cpu = 0;
 
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+       int cpu_hw_intr;
+
        /* arbitration priority */
        clear_c0_brcm_cmt_ctrl(0x30);
 
@@ -79,15 +81,13 @@ static void __init bmips_smp_setup(void)
         * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread
         * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
         * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
-        *
-        * If booting from TP1, leave the existing CMT interrupt routing
-        * such that TP0 responds to SW1 and TP1 responds to SW0.
         */
        if (boot_cpu == 0)
-               change_c0_brcm_cmt_intr(0xf8018000,
-                                       (0x02 << 27) | (0x03 << 15));
+               cpu_hw_intr = 0x02;
        else
-               change_c0_brcm_cmt_intr(0xf8018000, (0x1d << 27));
+               cpu_hw_intr = 0x1d;
+
+       change_c0_brcm_cmt_intr(0xf8018000, (cpu_hw_intr << 27) | (0x03 << 15));
 
        /* single core, 2 threads (2 pipelines) */
        max_cpus = 2;
@@ -202,9 +202,15 @@ static void bmips_init_secondary(void)
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
        void __iomem *cbr = BMIPS_GET_CBR();
        unsigned long old_vec;
+       unsigned long relo_vector;
+       int boot_cpu;
+
+       boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
+       relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
+                         BMIPS_RELO_VECTOR_CONTROL_1;
 
-       old_vec = __raw_readl(cbr + BMIPS_RELO_VECTOR_CONTROL_1);
-       __raw_writel(old_vec & ~0x20000000, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+       old_vec = __raw_readl(cbr + relo_vector);
+       __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
 
        clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
 #elif defined(CONFIG_CPU_BMIPS5000)
index e4b1140..3a2b6e9 100644 (file)
@@ -166,7 +166,7 @@ static void mipsxx_reg_setup(struct op_counter_config *ctr)
                        reg.control[i] |= M_PERFCTL_USER;
                if (ctr[i].exl)
                        reg.control[i] |= M_PERFCTL_EXL;
-               if (current_cpu_type() == CPU_XLR)
+               if (boot_cpu_type() == CPU_XLR)
                        reg.control[i] |= M_PERFCTL_COUNT_ALL_THREADS;
                reg.counter[i] = 0x80000000 - ctr[i].count;
        }
index d22dc0d..2b7e837 100644 (file)
@@ -206,11 +206,13 @@ static struct resource pnx833x_ethernet_resources[] = {
                .end   = PNX8335_IP3902_PORTS_END,
                .flags = IORESOURCE_MEM,
        },
+#ifdef CONFIG_SOC_PNX8335
        [1] = {
                .start = PNX8335_PIC_ETHERNET_INT,
                .end   = PNX8335_PIC_ETHERNET_INT,
                .flags = IORESOURCE_IRQ,
        },
+#endif
 };
 
 static struct platform_device pnx833x_ethernet_device = {
index 9f64c23..0238af1 100644 (file)
@@ -529,8 +529,7 @@ EXPORT_SYMBOL(asic_resource_get);
  */
 void platform_release_memory(void *ptr, int size)
 {
-       free_reserved_area((unsigned long)ptr, (unsigned long)(ptr + size),
-                          -1, NULL);
+       free_reserved_area(ptr, ptr + size, -1, NULL);
 }
 EXPORT_SYMBOL(platform_release_memory);
 
index 99dbab1..d60bf98 100644 (file)
@@ -55,6 +55,7 @@ config GENERIC_CSUM
 
 source "init/Kconfig"
 
+source "kernel/Kconfig.freezer"
 
 menu "Processor type and features"
 
diff --git a/arch/parisc/configs/c8000_defconfig b/arch/parisc/configs/c8000_defconfig
new file mode 100644 (file)
index 0000000..f110063
--- /dev/null
@@ -0,0 +1,279 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_PA8X00=y
+CONFIG_MLONGCALLS=y
+CONFIG_64BIT=y
+CONFIG_SMP=y
+CONFIG_PREEMPT=y
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_IOMMU_CCIO=y
+CONFIG_PCI=y
+CONFIG_PCI_LBA=y
+# CONFIG_SUPERIO is not set
+# CONFIG_CHASSIS_LCD_LED is not set
+# CONFIG_PDC_CHASSIS is not set
+# CONFIG_PDC_CHASSIS_WARN is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_DIAG=m
+# CONFIG_IPV6 is not set
+CONFIG_IP_DCCP=m
+# CONFIG_IP_DCCP_CCID3 is not set
+CONFIG_TIPC=m
+CONFIG_LLC2=m
+CONFIG_DNS_RESOLVER=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_STANDALONE is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_FIFO=y
+CONFIG_BLK_DEV_UMEM=m
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=6144
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_WCACHE=y
+CONFIG_ATA_OVER_ETH=m
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_PLATFORM=y
+CONFIG_BLK_DEV_GENERIC=y
+CONFIG_BLK_DEV_SIIMAGE=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION_SAS=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_NETCONSOLE=m
+CONFIG_TUN=y
+CONFIG_E1000=y
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+# CONFIG_WLAN is not set
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+CONFIG_MOUSE_PS2=m
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_CM109=m
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_GSCPS2=m
+# CONFIG_HP_SDC is not set
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_MUX is not set
+CONFIG_SERIAL_JSM=m
+CONFIG_PRINTER=y
+CONFIG_HW_RANDOM=y
+CONFIG_RAW_DRIVER=m
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_SSB=m
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_AGP=y
+CONFIG_AGP_PARISC=y
+CONFIG_DRM=y
+CONFIG_DRM_RADEON=y
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+# CONFIG_FB_STI is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_STI_CONSOLE is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_AD1889=m
+# CONFIG_SND_USB is not set
+# CONFIG_SND_GSC is not set
+CONFIG_HID_A4TECH=m
+CONFIG_HID_APPLE=m
+CONFIG_HID_BELKIN=m
+CONFIG_HID_CHERRY=m
+CONFIG_HID_CHICONY=m
+CONFIG_HID_CYPRESS=m
+CONFIG_HID_DRAGONRISE=m
+CONFIG_HID_EZKEY=m
+CONFIG_HID_KYE=m
+CONFIG_HID_GYRATION=m
+CONFIG_HID_TWINHAN=m
+CONFIG_HID_KENSINGTON=m
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_MONTEREY=m
+CONFIG_HID_NTRIG=m
+CONFIG_HID_ORTEK=m
+CONFIG_HID_PANTHERLORD=m
+CONFIG_HID_PETALYNX=m
+CONFIG_HID_SAMSUNG=m
+CONFIG_HID_SUNPLUS=m
+CONFIG_HID_GREENASIA=m
+CONFIG_HID_SMARTJOYPLUS=m
+CONFIG_HID_TOPSEED=m
+CONFIG_HID_THRUSTMASTER=m
+CONFIG_HID_ZEROPLUS=m
+CONFIG_USB_HID=m
+CONFIG_USB=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT4_FS=m
+CONFIG_REISERFS_FS=m
+CONFIG_REISERFS_PROC_INFO=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_QUOTA=y
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_NFS_FS=m
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
+CONFIG_PANIC_ON_OOPS=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_RT_MUTEX_TESTER=y
+CONFIG_PROVE_RCU_DELAY=y
+CONFIG_DEBUG_BLOCK_EXT_DEVT=y
+CONFIG_LATENCYTOP=y
+CONFIG_DEBUG_STRICT_USER_COPY_CHECKS=y
+CONFIG_KEYS=y
+# CONFIG_CRYPTO_HW is not set
+CONFIG_FONTS=y
index 9afdad6..eaf4dc1 100644 (file)
@@ -23,6 +23,7 @@ struct parisc_device {
        /* generic info returned from pdc_pat_cell_module() */
        unsigned long   mod_info;       /* PAT specific - Misc Module info */
        unsigned long   pmod_loc;       /* physical Module location */
+       unsigned long   mod0;
 #endif
        u64             dma_mask;       /* DMA mask for I/O */
        struct device   dev;
@@ -61,4 +62,6 @@ parisc_get_drvdata(struct parisc_device *d)
 
 extern struct bus_type parisc_bus_type;
 
+int iosapic_serial_irq(struct parisc_device *dev);
+
 #endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
index 2e65aa5..c035673 100644 (file)
@@ -71,18 +71,27 @@ flush_cache_all_local(void)
 }
 EXPORT_SYMBOL(flush_cache_all_local);
 
+/* Virtual address of pfn.  */
+#define pfn_va(pfn)    __va(PFN_PHYS(pfn))
+
 void
 update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
-       struct page *page = pte_page(*ptep);
+       unsigned long pfn = pte_pfn(*ptep);
+       struct page *page;
 
-       if (pfn_valid(page_to_pfn(page)) && page_mapping(page) &&
-           test_bit(PG_dcache_dirty, &page->flags)) {
+       /* We don't have pte special.  As a result, we can be called with
+          an invalid pfn and we don't need to flush the kernel dcache page.
+          This occurs with FireGL card in C8000.  */
+       if (!pfn_valid(pfn))
+               return;
 
-               flush_kernel_dcache_page(page);
+       page = pfn_to_page(pfn);
+       if (page_mapping(page) && test_bit(PG_dcache_dirty, &page->flags)) {
+               flush_kernel_dcache_page_addr(pfn_va(pfn));
                clear_bit(PG_dcache_dirty, &page->flags);
        } else if (parisc_requires_coherency())
-               flush_kernel_dcache_page(page);
+               flush_kernel_dcache_page_addr(pfn_va(pfn));
 }
 
 void
@@ -495,44 +504,42 @@ static inline pte_t *get_ptep(pgd_t *pgd, unsigned long addr)
 
 void flush_cache_mm(struct mm_struct *mm)
 {
+       struct vm_area_struct *vma;
+       pgd_t *pgd;
+
        /* Flushing the whole cache on each cpu takes forever on
           rp3440, etc.  So, avoid it if the mm isn't too big.  */
-       if (mm_total_size(mm) < parisc_cache_flush_threshold) {
-               struct vm_area_struct *vma;
-
-               if (mm->context == mfsp(3)) {
-                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                               flush_user_dcache_range_asm(vma->vm_start,
-                                       vma->vm_end);
-                               if (vma->vm_flags & VM_EXEC)
-                                       flush_user_icache_range_asm(
-                                         vma->vm_start, vma->vm_end);
-                       }
-               } else {
-                       pgd_t *pgd = mm->pgd;
-
-                       for (vma = mm->mmap; vma; vma = vma->vm_next) {
-                               unsigned long addr;
-
-                               for (addr = vma->vm_start; addr < vma->vm_end;
-                                    addr += PAGE_SIZE) {
-                                       pte_t *ptep = get_ptep(pgd, addr);
-                                       if (ptep != NULL) {
-                                               pte_t pte = *ptep;
-                                               __flush_cache_page(vma, addr,
-                                                 page_to_phys(pte_page(pte)));
-                                       }
-                               }
-                       }
+       if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
+               flush_cache_all();
+               return;
+       }
+
+       if (mm->context == mfsp(3)) {
+               for (vma = mm->mmap; vma; vma = vma->vm_next) {
+                       flush_user_dcache_range_asm(vma->vm_start, vma->vm_end);
+                       if ((vma->vm_flags & VM_EXEC) == 0)
+                               continue;
+                       flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
                }
                return;
        }
 
-#ifdef CONFIG_SMP
-       flush_cache_all();
-#else
-       flush_cache_all_local();
-#endif
+       pgd = mm->pgd;
+       for (vma = mm->mmap; vma; vma = vma->vm_next) {
+               unsigned long addr;
+
+               for (addr = vma->vm_start; addr < vma->vm_end;
+                    addr += PAGE_SIZE) {
+                       unsigned long pfn;
+                       pte_t *ptep = get_ptep(pgd, addr);
+                       if (!ptep)
+                               continue;
+                       pfn = pte_pfn(*ptep);
+                       if (!pfn_valid(pfn))
+                               continue;
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+               }
+       }
 }
 
 void
@@ -556,33 +563,32 @@ flush_user_icache_range(unsigned long start, unsigned long end)
 void flush_cache_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end)
 {
+       unsigned long addr;
+       pgd_t *pgd;
+
        BUG_ON(!vma->vm_mm->context);
 
-       if ((end - start) < parisc_cache_flush_threshold) {
-               if (vma->vm_mm->context == mfsp(3)) {
-                       flush_user_dcache_range_asm(start, end);
-                       if (vma->vm_flags & VM_EXEC)
-                               flush_user_icache_range_asm(start, end);
-               } else {
-                       unsigned long addr;
-                       pgd_t *pgd = vma->vm_mm->pgd;
-
-                       for (addr = start & PAGE_MASK; addr < end;
-                            addr += PAGE_SIZE) {
-                               pte_t *ptep = get_ptep(pgd, addr);
-                               if (ptep != NULL) {
-                                       pte_t pte = *ptep;
-                                       flush_cache_page(vma,
-                                          addr, pte_pfn(pte));
-                               }
-                       }
-               }
-       } else {
-#ifdef CONFIG_SMP
+       if ((end - start) >= parisc_cache_flush_threshold) {
                flush_cache_all();
-#else
-               flush_cache_all_local();
-#endif
+               return;
+       }
+
+       if (vma->vm_mm->context == mfsp(3)) {
+               flush_user_dcache_range_asm(start, end);
+               if (vma->vm_flags & VM_EXEC)
+                       flush_user_icache_range_asm(start, end);
+               return;
+       }
+
+       pgd = vma->vm_mm->pgd;
+       for (addr = start & PAGE_MASK; addr < end; addr += PAGE_SIZE) {
+               unsigned long pfn;
+               pte_t *ptep = get_ptep(pgd, addr);
+               if (!ptep)
+                       continue;
+               pfn = pte_pfn(*ptep);
+               if (pfn_valid(pfn))
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
        }
 }
 
@@ -591,9 +597,10 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 {
        BUG_ON(!vma->vm_mm->context);
 
-       flush_tlb_page(vma, vmaddr);
-       __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
-
+       if (pfn_valid(pfn)) {
+               flush_tlb_page(vma, vmaddr);
+               __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+       }
 }
 
 #ifdef CONFIG_PARISC_TMPALIAS
index 3295ef4..f0b6722 100644 (file)
@@ -211,6 +211,7 @@ pat_query_module(ulong pcell_loc, ulong mod_index)
        /* REVISIT: who is the consumer of this? not sure yet... */
        dev->mod_info = pa_pdc_cell->mod_info;  /* pass to PAT_GET_ENTITY() */
        dev->pmod_loc = pa_pdc_cell->mod_location;
+       dev->mod0 = pa_pdc_cell->mod[0];
 
        register_parisc_device(dev);    /* advertise device */
 
index 940188d..07349b0 100644 (file)
 #define A(__x) ((unsigned long)(__x))
 
 /*
- * Atomically swap in the new signal mask, and wait for a signal.
- */
-#ifdef CONFIG_64BIT
-#include "sys32.h"
-#endif
-
-/*
  * Do a signal return - restore sigcontext.
  */
 
index 33eca1b..6c6a271 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/uaccess.h>
 
 #include "signal32.h"
-#include "sys32.h"
 
 #define DEBUG_COMPAT_SIG 0 
 #define DEBUG_COMPAT_SIG_LEVEL 2
diff --git a/arch/parisc/kernel/sys32.h b/arch/parisc/kernel/sys32.h
deleted file mode 100644 (file)
index 60dd470..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* 
- *    Copyright (C) 2002 Richard Hirst <rhirst at parisc-linux.org>
- *    Copyright (C) 2003 James Bottomley <jejb at parisc-linux.org>
- *    Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org>
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef _PARISC64_KERNEL_SYS32_H
-#define _PARISC64_KERNEL_SYS32_H
-
-#include <linux/compat.h>
-
-/* Call a kernel syscall which will use kernel space instead of user
- * space for its copy_to/from_user.
- */
-#define KERNEL_SYSCALL(ret, syscall, args...) \
-{ \
-    mm_segment_t old_fs = get_fs(); \
-    set_fs(KERNEL_DS); \
-    ret = syscall(args); \
-    set_fs (old_fs); \
-}
-
-#endif
index a134ff4..bb9f3b6 100644 (file)
@@ -42,8 +42,6 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
-#include "sys32.h"
-
 #undef DEBUG
 
 #ifdef DEBUG
index 3bf72cd..dbd9d3c 100644 (file)
@@ -566,7 +566,7 @@ config SCHED_SMT
 config PPC_DENORMALISATION
        bool "PowerPC denormalisation exception handling"
        depends on PPC_BOOK3S_64
-       default "n"
+       default "y" if PPC_POWERNV
        ---help---
          Add support for handling denormalisation of single precision
          values.  Useful for bare metal only.  If unsure say Y here.
index c86fcb9..0e8cfd0 100644 (file)
@@ -58,7 +58,7 @@ CONFIG_SCHED_SMT=y
 CONFIG_PPC_DENORMALISATION=y
 CONFIG_PCCARD=y
 CONFIG_ELECTRA_CF=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
 CONFIG_PACKET=y
index 4b20f76..0085dc4 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_IRQ_ALL_CPUS=y
 CONFIG_SPARSEMEM_MANUAL=y
 CONFIG_PCI_MSI=y
 CONFIG_PCCARD=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
 CONFIG_XFRM_USER=m
index bea8587..1d4b976 100644 (file)
@@ -53,7 +53,7 @@ CONFIG_PPC_64K_PAGES=y
 CONFIG_PPC_SUBPAGE_PROT=y
 CONFIG_SCHED_SMT=y
 CONFIG_PPC_DENORMALISATION=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_HOTPLUG_PCI_RPA=m
 CONFIG_HOTPLUG_PCI_RPA_DLPAR=m
 CONFIG_PACKET=y
index 2dd7bfc..8b24926 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/types.h>
 #include <asm/hw_irq.h>
 #include <linux/device.h>
+#include <uapi/asm/perf_event.h>
 
 #define MAX_HWEVENTS           8
 #define MAX_EVENT_ALTERNATIVES 8
@@ -69,11 +70,6 @@ struct power_pmu {
 #define PPMU_LIMITED_PMC_REQD  2       /* have to put this on a limited PMC */
 #define PPMU_ONLY_COUNT_RUN    4       /* only counting in run state */
 
-/*
- * We use the event config bit 63 as a flag to request EBB.
- */
-#define EVENT_CONFIG_EBB_SHIFT 63
-
 extern int register_power_pmu(struct power_pmu *);
 
 struct pt_regs;
index 47a35b0..e378ccc 100644 (file)
@@ -247,6 +247,10 @@ struct thread_struct {
        unsigned long   tm_orig_msr;    /* Thread's MSR on ctx switch */
        struct pt_regs  ckpt_regs;      /* Checkpointed registers */
 
+       unsigned long   tm_tar;
+       unsigned long   tm_ppr;
+       unsigned long   tm_dscr;
+
        /*
         * Transactional FP and VSX 0-31 register set.
         * NOTE: the sense of these is the opposite of the integer ckpt_regs!
index a6840e4..99222e2 100644 (file)
 #define SPRN_HRMOR     0x139   /* Real mode offset register */
 #define SPRN_HSRR0     0x13A   /* Hypervisor Save/Restore 0 */
 #define SPRN_HSRR1     0x13B   /* Hypervisor Save/Restore 1 */
+/* HFSCR and FSCR bit numbers are the same */
+#define FSCR_TAR_LG    8       /* Enable Target Address Register */
+#define FSCR_EBB_LG    7       /* Enable Event Based Branching */
+#define FSCR_TM_LG     5       /* Enable Transactional Memory */
+#define FSCR_PM_LG     4       /* Enable prob/priv access to PMU SPRs */
+#define FSCR_BHRB_LG   3       /* Enable Branch History Rolling Buffer*/
+#define FSCR_DSCR_LG   2       /* Enable Data Stream Control Register */
+#define FSCR_VECVSX_LG 1       /* Enable VMX/VSX  */
+#define FSCR_FP_LG     0       /* Enable Floating Point */
 #define SPRN_FSCR      0x099   /* Facility Status & Control Register */
-#define   FSCR_TAR     (1 << (63-55)) /* Enable Target Address Register */
-#define   FSCR_EBB     (1 << (63-56)) /* Enable Event Based Branching */
-#define   FSCR_DSCR    (1 << (63-61)) /* Enable Data Stream Control Register */
+#define   FSCR_TAR     __MASK(FSCR_TAR_LG)
+#define   FSCR_EBB     __MASK(FSCR_EBB_LG)
+#define   FSCR_DSCR    __MASK(FSCR_DSCR_LG)
 #define SPRN_HFSCR     0xbe    /* HV=1 Facility Status & Control Register */
-#define   HFSCR_TAR    (1 << (63-55)) /* Enable Target Address Register */
-#define   HFSCR_EBB    (1 << (63-56)) /* Enable Event Based Branching */
-#define   HFSCR_TM     (1 << (63-58)) /* Enable Transactional Memory */
-#define   HFSCR_PM     (1 << (63-60)) /* Enable prob/priv access to PMU SPRs */
-#define   HFSCR_BHRB   (1 << (63-59)) /* Enable Branch History Rolling Buffer*/
-#define   HFSCR_DSCR   (1 << (63-61)) /* Enable Data Stream Control Register */
-#define   HFSCR_VECVSX (1 << (63-62)) /* Enable VMX/VSX  */
-#define   HFSCR_FP     (1 << (63-63)) /* Enable Floating Point */
+#define   HFSCR_TAR    __MASK(FSCR_TAR_LG)
+#define   HFSCR_EBB    __MASK(FSCR_EBB_LG)
+#define   HFSCR_TM     __MASK(FSCR_TM_LG)
+#define   HFSCR_PM     __MASK(FSCR_PM_LG)
+#define   HFSCR_BHRB   __MASK(FSCR_BHRB_LG)
+#define   HFSCR_DSCR   __MASK(FSCR_DSCR_LG)
+#define   HFSCR_VECVSX __MASK(FSCR_VECVSX_LG)
+#define   HFSCR_FP     __MASK(FSCR_FP_LG)
 #define SPRN_TAR       0x32f   /* Target Address Register */
 #define SPRN_LPCR      0x13E   /* LPAR Control Register */
 #define   LPCR_VPM0    (1ul << (63-0))
index ffbaabe..48cfc85 100644 (file)
@@ -145,6 +145,10 @@ extern void __cpu_die(unsigned int cpu);
 #define smp_setup_cpu_maps()
 static inline void inhibit_secondary_onlining(void) {}
 static inline void uninhibit_secondary_onlining(void) {}
+static inline const struct cpumask *cpu_sibling_mask(int cpu)
+{
+       return cpumask_of(cpu);
+}
 
 #endif /* CONFIG_SMP */
 
index 49a13e0..294c2ce 100644 (file)
@@ -15,6 +15,15 @@ extern struct task_struct *__switch_to(struct task_struct *,
 struct thread_struct;
 extern struct task_struct *_switch(struct thread_struct *prev,
                                   struct thread_struct *next);
+#ifdef CONFIG_PPC_BOOK3S_64
+static inline void save_tar(struct thread_struct *prev)
+{
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
+               prev->tar = mfspr(SPRN_TAR);
+}
+#else
+static inline void save_tar(struct thread_struct *prev) {}
+#endif
 
 extern void giveup_fpu(struct task_struct *);
 extern void load_up_fpu(void);
index 5182c86..48be855 100644 (file)
@@ -20,6 +20,7 @@ header-y += mman.h
 header-y += msgbuf.h
 header-y += nvram.h
 header-y += param.h
+header-y += perf_event.h
 header-y += poll.h
 header-y += posix_types.h
 header-y += ps3fb.h
diff --git a/arch/powerpc/include/uapi/asm/perf_event.h b/arch/powerpc/include/uapi/asm/perf_event.h
new file mode 100644 (file)
index 0000000..80a4d40
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2013 Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ */
+
+#ifndef _UAPI_ASM_POWERPC_PERF_EVENT_H
+#define _UAPI_ASM_POWERPC_PERF_EVENT_H
+
+/*
+ * We use bit 63 of perf_event_attr.config as a flag to request EBB.
+ */
+#define PERF_EVENT_CONFIG_EBB_SHIFT    63
+
+#endif /* _UAPI_ASM_POWERPC_PERF_EVENT_H */
index c7e8afc..8207459 100644 (file)
@@ -138,6 +138,9 @@ int main(void)
        DEFINE(THREAD_TM_TFHAR, offsetof(struct thread_struct, tm_tfhar));
        DEFINE(THREAD_TM_TEXASR, offsetof(struct thread_struct, tm_texasr));
        DEFINE(THREAD_TM_TFIAR, offsetof(struct thread_struct, tm_tfiar));
+       DEFINE(THREAD_TM_TAR, offsetof(struct thread_struct, tm_tar));
+       DEFINE(THREAD_TM_PPR, offsetof(struct thread_struct, tm_ppr));
+       DEFINE(THREAD_TM_DSCR, offsetof(struct thread_struct, tm_dscr));
        DEFINE(PT_CKPT_REGS, offsetof(struct thread_struct, ckpt_regs));
        DEFINE(THREAD_TRANSACT_VR0, offsetof(struct thread_struct,
                                         transact_vr[0]));
index ea9414c..55593ee 100644 (file)
@@ -1061,7 +1061,7 @@ static const struct file_operations proc_eeh_operations = {
 
 static int __init eeh_init_proc(void)
 {
-       if (machine_is(pseries))
+       if (machine_is(pseries) || machine_is(powernv))
                proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations);
        return 0;
 }
index ab15b8d..2bd0b88 100644 (file)
@@ -449,15 +449,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
 
 #ifdef CONFIG_PPC_BOOK3S_64
 BEGIN_FTR_SECTION
-       /*
-        * Back up the TAR across context switches.  Note that the TAR is not
-        * available for use in the kernel.  (To provide this, the TAR should
-        * be backed up/restored on exception entry/exit instead, and be in
-        * pt_regs.  FIXME, this should be in pt_regs anyway (for debug).)
-        */
-       mfspr   r0,SPRN_TAR
-       std     r0,THREAD_TAR(r3)
-
        /* Event based branch registers */
        mfspr   r0, SPRN_BESCR
        std     r0, THREAD_BESCR(r3)
@@ -584,9 +575,34 @@ BEGIN_FTR_SECTION
        ld      r7,DSCR_DEFAULT@toc(2)
        ld      r0,THREAD_DSCR(r4)
        cmpwi   r6,0
+       li      r8, FSCR_DSCR
        bne     1f
        ld      r0,0(r7)
-1:     cmpd    r0,r25
+       b       3f
+1:
+  BEGIN_FTR_SECTION_NESTED(70)
+       mfspr   r6, SPRN_FSCR
+       or      r6, r6, r8
+       mtspr   SPRN_FSCR, r6
+    BEGIN_FTR_SECTION_NESTED(69)
+       mfspr   r6, SPRN_HFSCR
+       or      r6, r6, r8
+       mtspr   SPRN_HFSCR, r6
+    END_FTR_SECTION_NESTED(CPU_FTR_HVMODE, CPU_FTR_HVMODE, 69)
+       b       4f
+  END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70)
+3:
+  BEGIN_FTR_SECTION_NESTED(70)
+       mfspr   r6, SPRN_FSCR
+       andc    r6, r6, r8
+       mtspr   SPRN_FSCR, r6
+    BEGIN_FTR_SECTION_NESTED(69)
+       mfspr   r6, SPRN_HFSCR
+       andc    r6, r6, r8
+       mtspr   SPRN_HFSCR, r6
+    END_FTR_SECTION_NESTED(CPU_FTR_HVMODE, CPU_FTR_HVMODE, 69)
+  END_FTR_SECTION_NESTED(CPU_FTR_ARCH_207S, CPU_FTR_ARCH_207S, 70)
+4:     cmpd    r0,r25
        beq     2f
        mtspr   SPRN_DSCR,r0
 2:
index 4e00d22..902ca3c 100644 (file)
@@ -848,7 +848,7 @@ hv_facility_unavailable_relon_trampoline:
        . = 0x4f80
        SET_SCRATCH0(r13)
        EXCEPTION_PROLOG_0(PACA_EXGEN)
-       b       facility_unavailable_relon_hv
+       b       hv_facility_unavailable_relon_hv
 
        STD_RELON_EXCEPTION_PSERIES(0x5300, 0x1300, instruction_breakpoint)
 #ifdef CONFIG_PPC_DENORMALISATION
@@ -1175,6 +1175,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
        b       .ret_from_except
 
        STD_EXCEPTION_COMMON(0xf60, facility_unavailable, .facility_unavailable_exception)
+       STD_EXCEPTION_COMMON(0xf80, hv_facility_unavailable, .facility_unavailable_exception)
 
        .align  7
        .globl  __end_handlers
@@ -1188,7 +1189,7 @@ __end_handlers:
        STD_RELON_EXCEPTION_PSERIES_OOL(0xf20, altivec_unavailable)
        STD_RELON_EXCEPTION_PSERIES_OOL(0xf40, vsx_unavailable)
        STD_RELON_EXCEPTION_PSERIES_OOL(0xf60, facility_unavailable)
-       STD_RELON_EXCEPTION_HV_OOL(0xf80, facility_unavailable)
+       STD_RELON_EXCEPTION_HV_OOL(0xf80, hv_facility_unavailable)
 
 #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
 /*
index 2e51cde..c69440c 100644 (file)
@@ -362,7 +362,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
                seq_printf(p, "%10u ", per_cpu(irq_stat, j).spurious_irqs);
        seq_printf(p, "  Spurious interrupts\n");
 
-       seq_printf(p, "%*s: ", prec, "CNT");
+       seq_printf(p, "%*s: ", prec, "PMI");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", per_cpu(irq_stat, j).pmu_irqs);
        seq_printf(p, "  Performance monitoring interrupts\n");
index c517dbe..8083be2 100644 (file)
@@ -600,6 +600,16 @@ struct task_struct *__switch_to(struct task_struct *prev,
        struct ppc64_tlb_batch *batch;
 #endif
 
+       /* Back up the TAR across context switches.
+        * Note that the TAR is not available for use in the kernel.  (To
+        * provide this, the TAR should be backed up/restored on exception
+        * entry/exit instead, and be in pt_regs.  FIXME, this should be in
+        * pt_regs anyway (for debug).)
+        * Save the TAR here before we do treclaim/trecheckpoint as these
+        * will change the TAR.
+        */
+       save_tar(&prev->thread);
+
        __switch_to_tm(prev);
 
 #ifdef CONFIG_SMP
index 51be8fb..0554d1f 100644 (file)
@@ -233,6 +233,16 @@ dont_backup_fp:
        std     r5, _CCR(r7)
        std     r6, _XER(r7)
 
+
+       /* ******************** TAR, PPR, DSCR ********** */
+       mfspr   r3, SPRN_TAR
+       mfspr   r4, SPRN_PPR
+       mfspr   r5, SPRN_DSCR
+
+       std     r3, THREAD_TM_TAR(r12)
+       std     r4, THREAD_TM_PPR(r12)
+       std     r5, THREAD_TM_DSCR(r12)
+
        /* MSR and flags:  We don't change CRs, and we don't need to alter
         * MSR.
         */
@@ -347,6 +357,16 @@ dont_restore_fp:
        mtmsr   r6                              /* FP/Vec off again! */
 
 restore_gprs:
+
+       /* ******************** TAR, PPR, DSCR ********** */
+       ld      r4, THREAD_TM_TAR(r3)
+       ld      r5, THREAD_TM_PPR(r3)
+       ld      r6, THREAD_TM_DSCR(r3)
+
+       mtspr   SPRN_TAR,       r4
+       mtspr   SPRN_PPR,       r5
+       mtspr   SPRN_DSCR,      r6
+
        /* ******************** CR,LR,CCR,MSR ********** */
        ld      r3, _CTR(r7)
        ld      r4, _LINK(r7)
index bf33c22..e435bc0 100644 (file)
@@ -44,9 +44,7 @@
 #include <asm/machdep.h>
 #include <asm/rtas.h>
 #include <asm/pmc.h>
-#ifdef CONFIG_PPC32
 #include <asm/reg.h>
-#endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 #include <asm/backlight.h>
 #endif
@@ -1296,43 +1294,54 @@ void vsx_unavailable_exception(struct pt_regs *regs)
        die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT);
 }
 
+#ifdef CONFIG_PPC64
 void facility_unavailable_exception(struct pt_regs *regs)
 {
        static char *facility_strings[] = {
-               "FPU",
-               "VMX/VSX",
-               "DSCR",
-               "PMU SPRs",
-               "BHRB",
-               "TM",
-               "AT",
-               "EBB",
-               "TAR",
+               [FSCR_FP_LG] = "FPU",
+               [FSCR_VECVSX_LG] = "VMX/VSX",
+               [FSCR_DSCR_LG] = "DSCR",
+               [FSCR_PM_LG] = "PMU SPRs",
+               [FSCR_BHRB_LG] = "BHRB",
+               [FSCR_TM_LG] = "TM",
+               [FSCR_EBB_LG] = "EBB",
+               [FSCR_TAR_LG] = "TAR",
        };
-       char *facility, *prefix;
+       char *facility = "unknown";
        u64 value;
+       u8 status;
+       bool hv;
 
-       if (regs->trap == 0xf60) {
-               value = mfspr(SPRN_FSCR);
-               prefix = "";
-       } else {
+       hv = (regs->trap == 0xf80);
+       if (hv)
                value = mfspr(SPRN_HFSCR);
-               prefix = "Hypervisor ";
+       else
+               value = mfspr(SPRN_FSCR);
+
+       status = value >> 56;
+       if (status == FSCR_DSCR_LG) {
+               /* User is acessing the DSCR.  Set the inherit bit and allow
+                * the user to set it directly in future by setting via the
+                * H/FSCR DSCR bit.
+                */
+               current->thread.dscr_inherit = 1;
+               if (hv)
+                       mtspr(SPRN_HFSCR, value | HFSCR_DSCR);
+               else
+                       mtspr(SPRN_FSCR,  value | FSCR_DSCR);
+               return;
        }
 
-       value = value >> 56;
+       if ((status < ARRAY_SIZE(facility_strings)) &&
+           facility_strings[status])
+               facility = facility_strings[status];
 
        /* We restore the interrupt state now */
        if (!arch_irq_disabled_regs(regs))
                local_irq_enable();
 
-       if (value < ARRAY_SIZE(facility_strings))
-               facility = facility_strings[value];
-       else
-               facility = "unknown";
-
        pr_err("%sFacility '%s' unavailable, exception at 0x%lx, MSR=%lx\n",
-               prefix, facility, regs->nip, regs->msr);
+              hv ? "Hypervisor " : "", facility, regs->nip, regs->msr);
 
        if (user_mode(regs)) {
                _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
@@ -1341,6 +1350,7 @@ void facility_unavailable_exception(struct pt_regs *regs)
 
        die("Unexpected facility unavailable exception", regs, SIGABRT);
 }
+#endif
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
 
index 2efa9dd..7629cd3 100644 (file)
@@ -1809,7 +1809,7 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
                rma_size <<= PAGE_SHIFT;
                rmls = lpcr_rmls(rma_size);
                err = -EINVAL;
-               if (rmls < 0) {
+               if ((long)rmls < 0) {
                        pr_err("KVM: Can't use RMA of 0x%lx bytes\n", rma_size);
                        goto out_srcu;
                }
@@ -1874,7 +1874,7 @@ int kvmppc_core_init_vm(struct kvm *kvm)
        /* Allocate the guest's logical partition ID */
 
        lpid = kvmppc_alloc_lpid();
-       if (lpid < 0)
+       if ((long)lpid < 0)
                return -ENOMEM;
        kvm->arch.lpid = lpid;
 
index 19498a5..c6e13d9 100644 (file)
@@ -1047,11 +1047,12 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
        if (err)
                goto free_shadow_vcpu;
 
+       err = -ENOMEM;
        p = __get_free_page(GFP_KERNEL|__GFP_ZERO);
-       /* the real shared page fills the last 4k of our page */
-       vcpu->arch.shared = (void*)(p + PAGE_SIZE - 4096);
        if (!p)
                goto uninit_vcpu;
+       /* the real shared page fills the last 4k of our page */
+       vcpu->arch.shared = (void *)(p + PAGE_SIZE - 4096);
 
 #ifdef CONFIG_PPC_BOOK3S_64
        /* default to book3s_64 (970fx) */
index 0839721..5850798 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
+#include <asm/cputhreads.h>
 #include <asm/sparsemem.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
@@ -1318,7 +1319,8 @@ static int update_cpu_associativity_changes_mask(void)
                        }
                }
                if (changed) {
-                       cpumask_set_cpu(cpu, changes);
+                       cpumask_or(changes, changes, cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
                }
        }
 
@@ -1426,7 +1428,7 @@ static int update_cpu_topology(void *data)
        if (!data)
                return -EINVAL;
 
-       cpu = get_cpu();
+       cpu = smp_processor_id();
 
        for (update = data; update; update = update->next) {
                if (cpu != update->cpu)
@@ -1446,12 +1448,12 @@ static int update_cpu_topology(void *data)
  */
 int arch_update_cpu_topology(void)
 {
-       unsigned int cpu, changed = 0;
+       unsigned int cpu, sibling, changed = 0;
        struct topology_update_data *updates, *ud;
        unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
        cpumask_t updated_cpus;
        struct device *dev;
-       int weight, i = 0;
+       int weight, new_nid, i = 0;
 
        weight = cpumask_weight(&cpu_associativity_changes_mask);
        if (!weight)
@@ -1464,19 +1466,46 @@ int arch_update_cpu_topology(void)
        cpumask_clear(&updated_cpus);
 
        for_each_cpu(cpu, &cpu_associativity_changes_mask) {
-               ud = &updates[i++];
-               ud->cpu = cpu;
-               vphn_get_associativity(cpu, associativity);
-               ud->new_nid = associativity_to_nid(associativity);
-
-               if (ud->new_nid < 0 || !node_online(ud->new_nid))
-                       ud->new_nid = first_online_node;
+               /*
+                * If siblings aren't flagged for changes, updates list
+                * will be too short. Skip on this update and set for next
+                * update.
+                */
+               if (!cpumask_subset(cpu_sibling_mask(cpu),
+                                       &cpu_associativity_changes_mask)) {
+                       pr_info("Sibling bits not set for associativity "
+                                       "change, cpu%d\n", cpu);
+                       cpumask_or(&cpu_associativity_changes_mask,
+                                       &cpu_associativity_changes_mask,
+                                       cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
+                       continue;
+               }
 
-               ud->old_nid = numa_cpu_lookup_table[cpu];
-               cpumask_set_cpu(cpu, &updated_cpus);
+               /* Use associativity from first thread for all siblings */
+               vphn_get_associativity(cpu, associativity);
+               new_nid = associativity_to_nid(associativity);
+               if (new_nid < 0 || !node_online(new_nid))
+                       new_nid = first_online_node;
+
+               if (new_nid == numa_cpu_lookup_table[cpu]) {
+                       cpumask_andnot(&cpu_associativity_changes_mask,
+                                       &cpu_associativity_changes_mask,
+                                       cpu_sibling_mask(cpu));
+                       cpu = cpu_last_thread_sibling(cpu);
+                       continue;
+               }
 
-               if (i < weight)
-                       ud->next = &updates[i];
+               for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
+                       ud = &updates[i++];
+                       ud->cpu = sibling;
+                       ud->new_nid = new_nid;
+                       ud->old_nid = numa_cpu_lookup_table[sibling];
+                       cpumask_set_cpu(sibling, &updated_cpus);
+                       if (i < weight)
+                               ud->next = &updates[i];
+               }
+               cpu = cpu_last_thread_sibling(cpu);
        }
 
        stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
index 24a45f9..eeae308 100644 (file)
@@ -484,7 +484,7 @@ static bool is_ebb_event(struct perf_event *event)
         * use bit 63 of the event code for something else if they wish.
         */
        return (ppmu->flags & PPMU_EBB) &&
-              ((event->attr.config >> EVENT_CONFIG_EBB_SHIFT) & 1);
+              ((event->attr.config >> PERF_EVENT_CONFIG_EBB_SHIFT) & 1);
 }
 
 static int ebb_event_check(struct perf_event *event)
index 7466374..2ee4a70 100644 (file)
         (EVENT_UNIT_MASK      << EVENT_UNIT_SHIFT)             |       \
         (EVENT_COMBINE_MASK   << EVENT_COMBINE_SHIFT)          |       \
         (EVENT_MARKED_MASK    << EVENT_MARKED_SHIFT)           |       \
-        (EVENT_EBB_MASK       << EVENT_CONFIG_EBB_SHIFT)       |       \
+        (EVENT_EBB_MASK       << PERF_EVENT_CONFIG_EBB_SHIFT)  |       \
          EVENT_PSEL_MASK)
 
 /* MMCRA IFM bits - POWER8 */
@@ -233,10 +233,10 @@ static int power8_get_constraint(u64 event, unsigned long *maskp, unsigned long
        pmc   = (event >> EVENT_PMC_SHIFT)        & EVENT_PMC_MASK;
        unit  = (event >> EVENT_UNIT_SHIFT)       & EVENT_UNIT_MASK;
        cache = (event >> EVENT_CACHE_SEL_SHIFT)  & EVENT_CACHE_SEL_MASK;
-       ebb   = (event >> EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
+       ebb   = (event >> PERF_EVENT_CONFIG_EBB_SHIFT) & EVENT_EBB_MASK;
 
        /* Clear the EBB bit in the event, so event checks work below */
-       event &= ~(EVENT_EBB_MASK << EVENT_CONFIG_EBB_SHIFT);
+       event &= ~(EVENT_EBB_MASK << PERF_EVENT_CONFIG_EBB_SHIFT);
 
        if (pmc) {
                if (pmc > 6)
index 9f8671a..6a5f2b1 100644 (file)
@@ -569,35 +569,6 @@ error:
        return ret;
 }
 
-static int unzip_oops(char *oops_buf, char *big_buf)
-{
-       struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf;
-       u64 timestamp = oops_hdr->timestamp;
-       char *big_oops_data = NULL;
-       char *oops_data_buf = NULL;
-       size_t big_oops_data_sz;
-       int unzipped_len;
-
-       big_oops_data = big_buf + sizeof(struct oops_log_info);
-       big_oops_data_sz = big_oops_buf_sz - sizeof(struct oops_log_info);
-       oops_data_buf = oops_buf + sizeof(struct oops_log_info);
-
-       unzipped_len = nvram_decompress(oops_data_buf, big_oops_data,
-                                       oops_hdr->report_length,
-                                       big_oops_data_sz);
-
-       if (unzipped_len < 0) {
-               pr_err("nvram: decompression failed; returned %d\n",
-                                                               unzipped_len);
-               return -1;
-       }
-       oops_hdr = (struct oops_log_info *)big_buf;
-       oops_hdr->version = OOPS_HDR_VERSION;
-       oops_hdr->report_length = (u16) unzipped_len;
-       oops_hdr->timestamp = timestamp;
-       return 0;
-}
-
 static int nvram_pstore_open(struct pstore_info *psi)
 {
        /* Reset the iterator to start reading partitions again */
@@ -685,10 +656,9 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
        unsigned int err_type, id_no, size = 0;
        struct nvram_os_partition *part = NULL;
        char *buff = NULL, *big_buff = NULL;
-       int rc, sig = 0;
+       int sig = 0;
        loff_t p;
 
-read_partition:
        read_type++;
 
        switch (nvram_type_ids[read_type]) {
@@ -749,30 +719,46 @@ read_partition:
                *id = id_no;
 
        if (nvram_type_ids[read_type] == PSTORE_TYPE_DMESG) {
+               int length, unzipped_len;
+               size_t hdr_size;
+
                oops_hdr = (struct oops_log_info *)buff;
-               *buf = buff + sizeof(*oops_hdr);
+               if (oops_hdr->version < OOPS_HDR_VERSION) {
+                       /* Old format oops header had 2-byte record size */
+                       hdr_size = sizeof(u16);
+                       length = oops_hdr->version;
+                       time->tv_sec = 0;
+                       time->tv_nsec = 0;
+               } else {
+                       hdr_size = sizeof(*oops_hdr);
+                       length = oops_hdr->report_length;
+                       time->tv_sec = oops_hdr->timestamp;
+                       time->tv_nsec = 0;
+               }
+               *buf = kmalloc(length, GFP_KERNEL);
+               if (*buf == NULL)
+                       return -ENOMEM;
+               memcpy(*buf, buff + hdr_size, length);
+               kfree(buff);
 
                if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) {
                        big_buff = kmalloc(big_oops_buf_sz, GFP_KERNEL);
                        if (!big_buff)
                                return -ENOMEM;
 
-                       rc = unzip_oops(buff, big_buff);
+                       unzipped_len = nvram_decompress(*buf, big_buff,
+                                               length, big_oops_buf_sz);
 
-                       if (rc != 0) {
-                               kfree(buff);
+                       if (unzipped_len < 0) {
+                               pr_err("nvram: decompression failed, returned "
+                                       "rc %d\n", unzipped_len);
                                kfree(big_buff);
-                               goto read_partition;
+                       } else {
+                               *buf = big_buff;
+                               length = unzipped_len;
                        }
-
-                       oops_hdr = (struct oops_log_info *)big_buff;
-                       *buf = big_buff + sizeof(*oops_hdr);
-                       kfree(buff);
                }
-
-               time->tv_sec = oops_hdr->timestamp;
-               time->tv_nsec = 0;
-               return oops_hdr->report_length;
+               return length;
        }
 
        *buf = buff;
@@ -816,6 +802,7 @@ static int nvram_pstore_init(void)
 static void __init nvram_init_oops_partition(int rtas_partition_exists)
 {
        int rc;
+       size_t size;
 
        rc = pseries_nvram_init_os_partition(&oops_log_partition);
        if (rc != 0) {
@@ -844,8 +831,9 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists)
        big_oops_buf_sz = (oops_data_sz * 100) / 45;
        big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
        if (big_oops_buf) {
-               stream.workspace = kmalloc(zlib_deflate_workspacesize(
-                               WINDOW_BITS, MEM_LEVEL), GFP_KERNEL);
+               size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
+                       zlib_inflate_workspacesize());
+               stream.workspace = kmalloc(size, GFP_KERNEL);
                if (!stream.workspace) {
                        pr_err("nvram: No memory for compression workspace; "
                                "skipping compression of %s partition data\n",
index 22f75b5..8a4cae7 100644 (file)
@@ -118,6 +118,7 @@ config S390
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
+       select HAVE_KERNEL_LZ4
        select HAVE_KERNEL_LZMA
        select HAVE_KERNEL_LZO
        select HAVE_KERNEL_XZ
@@ -227,11 +228,12 @@ config MARCH_Z196
          not work on older machines.
 
 config MARCH_ZEC12
-       bool "IBM zEC12"
+       bool "IBM zBC12 and zEC12"
        select HAVE_MARCH_ZEC12_FEATURES if 64BIT
        help
-         Select this to enable optimizations for IBM zEC12 (2827 series). The
-         kernel will be slightly faster but will not work on older machines.
+         Select this to enable optimizations for IBM zBC12 and zEC12 (2828 and
+         2827 series). The kernel will be slightly faster but will not work on
+         older machines.
 
 endchoice
 
@@ -709,6 +711,7 @@ config S390_GUEST
        def_bool y
        prompt "s390 support for virtio devices"
        depends on 64BIT
+       select TTY
        select VIRTUALIZATION
        select VIRTIO
        select VIRTIO_CONSOLE
index 3ad8f61..866ecbe 100644 (file)
@@ -6,9 +6,9 @@
 
 BITS := $(if $(CONFIG_64BIT),64,31)
 
-targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 \
-          vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo misc.o piggy.o \
-          sizes.h head$(BITS).o
+targets        := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
+targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
+targets += misc.o piggy.o sizes.h head$(BITS).o
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
@@ -48,6 +48,7 @@ vmlinux.bin.all-y := $(obj)/vmlinux.bin
 
 suffix-$(CONFIG_KERNEL_GZIP)  := gz
 suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZ4)  := lz4
 suffix-$(CONFIG_KERNEL_LZMA)  := lzma
 suffix-$(CONFIG_KERNEL_LZO)  := lzo
 suffix-$(CONFIG_KERNEL_XZ)  := xz
@@ -56,6 +57,8 @@ $(obj)/vmlinux.bin.gz: $(vmlinux.bin.all-y)
        $(call if_changed,gzip)
 $(obj)/vmlinux.bin.bz2: $(vmlinux.bin.all-y)
        $(call if_changed,bzip2)
+$(obj)/vmlinux.bin.lz4: $(vmlinux.bin.all-y)
+       $(call if_changed,lz4)
 $(obj)/vmlinux.bin.lzma: $(vmlinux.bin.all-y)
        $(call if_changed,lzma)
 $(obj)/vmlinux.bin.lzo: $(vmlinux.bin.all-y)
index c4c6a1c..57cbaff 100644 (file)
@@ -47,6 +47,10 @@ static unsigned long free_mem_end_ptr;
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
 #ifdef CONFIG_KERNEL_LZMA
 #include "../../../../lib/decompress_unlzma.c"
 #endif
index 4d8604e..7d46767 100644 (file)
@@ -693,7 +693,7 @@ static inline int find_next_bit_left(const unsigned long *addr,
        size -= offset;
        p = addr + offset / BITS_PER_LONG;
        if (bit) {
-               set = __flo_word(0, *p & (~0UL << bit));
+               set = __flo_word(0, *p & (~0UL >> bit));
                if (set >= size)
                        return size + offset;
                if (set < BITS_PER_LONG)
index b75d7d6..6d6d92b 100644 (file)
@@ -32,6 +32,7 @@ struct mmu_gather {
        struct mm_struct *mm;
        struct mmu_table_batch *batch;
        unsigned int fullmm;
+       unsigned long start, end;
 };
 
 struct mmu_table_batch {
@@ -48,10 +49,13 @@ extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
 
 static inline void tlb_gather_mmu(struct mmu_gather *tlb,
                                  struct mm_struct *mm,
-                                 unsigned int full_mm_flush)
+                                 unsigned long start,
+                                 unsigned long end)
 {
        tlb->mm = mm;
-       tlb->fullmm = full_mm_flush;
+       tlb->start = start;
+       tlb->end = end;
+       tlb->fullmm = !(start | (end+1));
        tlb->batch = NULL;
        if (tlb->fullmm)
                __tlb_flush_mm(mm);
index a6fc037..500aa10 100644 (file)
@@ -52,12 +52,13 @@ static struct kvm_s390_sie_block *sie_block(struct pt_regs *regs)
 
 static bool is_in_guest(struct pt_regs *regs)
 {
-       unsigned long ip = instruction_pointer(regs);
-
        if (user_mode(regs))
                return false;
-
-       return ip == (unsigned long) &sie_exit;
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+       return instruction_pointer(regs) == (unsigned long) &sie_exit;
+#else
+       return false;
+#endif
 }
 
 static unsigned long guest_is_user_mode(struct pt_regs *regs)
index 497451e..aeed8a6 100644 (file)
@@ -994,6 +994,7 @@ static void __init setup_hwcaps(void)
                strcpy(elf_platform, "z196");
                break;
        case 0x2827:
+       case 0x2828:
                strcpy(elf_platform, "zEC12");
                break;
        }
index ba694d2..34c1c9a 100644 (file)
@@ -702,14 +702,25 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
                return rc;
 
        vcpu->arch.sie_block->icptcode = 0;
-       preempt_disable();
-       kvm_guest_enter();
-       preempt_enable();
        VCPU_EVENT(vcpu, 6, "entering sie flags %x",
                   atomic_read(&vcpu->arch.sie_block->cpuflags));
        trace_kvm_s390_sie_enter(vcpu,
                                 atomic_read(&vcpu->arch.sie_block->cpuflags));
+
+       /*
+        * As PF_VCPU will be used in fault handler, between guest_enter
+        * and guest_exit should be no uaccess.
+        */
+       preempt_disable();
+       kvm_guest_enter();
+       preempt_enable();
        rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
+       kvm_guest_exit();
+
+       VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
+                  vcpu->arch.sie_block->icptcode);
+       trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
+
        if (rc > 0)
                rc = 0;
        if (rc < 0) {
@@ -721,10 +732,6 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
                        rc = kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
                }
        }
-       VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
-                  vcpu->arch.sie_block->icptcode);
-       trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
-       kvm_guest_exit();
 
        memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
        return rc;
index 0da3e6e..4cdc54e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/compat.h>
 #include <asm/asm-offsets.h>
+#include <asm/facility.h>
 #include <asm/current.h>
 #include <asm/debug.h>
 #include <asm/ebcdic.h>
@@ -532,8 +533,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
        /* Only provide non-quiescing support if the host supports it */
-       if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ &&
-           S390_lowcore.stfl_fac_list & 0x00020000)
+       if (vcpu->run->s.regs.gprs[reg1] & PFMF_NQ && !test_facility(14))
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
 
        /* No support for conditional-SSKE */
index ce36ea8..ad446b0 100644 (file)
@@ -69,6 +69,7 @@ static void __init setup_zero_pages(void)
                order = 2;
                break;
        case 0x2827:    /* zEC12 */
+       case 0x2828:    /* zEC12 */
        default:
                order = 5;
                break;
index ffeb17c..930783d 100644 (file)
@@ -440,7 +440,7 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops)
                switch (id.machine) {
                case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break;
                case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break;
-               case 0x2827:              ops->cpu_type = "s390/zEC12"; break;
+               case 0x2827: case 0x2828: ops->cpu_type = "s390/zEC12"; break;
                default: return -ENODEV;
                }
        }
index c8def8b..5fc2375 100644 (file)
@@ -87,6 +87,8 @@ config STACKTRACE_SUPPORT
 
 source "init/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 config MMU
        def_bool y
 
index 2051821..0cf4097 100644 (file)
@@ -22,7 +22,7 @@ CONFIG_PREEMPT=y
 CONFIG_CMDLINE_OVERWRITE=y
 CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
 CONFIG_PCI=y
-CONFIG_HOTPLUG_PCI=m
+CONFIG_HOTPLUG_PCI=y
 CONFIG_BINFMT_MISC=y
 CONFIG_NET=y
 CONFIG_PACKET=y
index e61d43d..362192e 100644 (file)
@@ -36,10 +36,12 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
 }
 
 static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        tlb->mm = mm;
-       tlb->fullmm = full_mm_flush;
+       tlb->start = start;
+       tlb->end = end;
+       tlb->fullmm = !(start | (end+1));
 
        init_tlb_gather(tlb);
 }
index 4febacd..29b0301 100644 (file)
@@ -45,10 +45,12 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
 }
 
 static inline void
-tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        tlb->mm = mm;
-       tlb->fullmm = full_mm_flush;
+       tlb->start = start;
+       tlb->end = end;
+       tlb->fullmm = !(start | (end+1));
 
        init_tlb_gather(tlb);
 }
index d606463..b7388a4 100644 (file)
@@ -225,7 +225,7 @@ static void low_free(unsigned long size, unsigned long addr)
        unsigned long nr_pages;
 
        nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
-       efi_call_phys2(sys_table->boottime->free_pages, addr, size);
+       efi_call_phys2(sys_table->boottime->free_pages, addr, nr_pages);
 }
 
 static void find_bits(unsigned long mask, u8 *pos, u8 *size)
index f2b489c..3bf2dd0 100644 (file)
@@ -55,9 +55,53 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp)
 #define native_pmdp_get_and_clear(xp) native_local_pmdp_get_and_clear(xp)
 #endif
 
+#ifdef CONFIG_MEM_SOFT_DIRTY
+
+/*
+ * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE, _PAGE_BIT_SOFT_DIRTY and
+ * _PAGE_BIT_PROTNONE are taken, split up the 28 bits of offset
+ * into this range.
+ */
+#define PTE_FILE_MAX_BITS      28
+#define PTE_FILE_SHIFT1                (_PAGE_BIT_PRESENT + 1)
+#define PTE_FILE_SHIFT2                (_PAGE_BIT_FILE + 1)
+#define PTE_FILE_SHIFT3                (_PAGE_BIT_PROTNONE + 1)
+#define PTE_FILE_SHIFT4                (_PAGE_BIT_SOFT_DIRTY + 1)
+#define PTE_FILE_BITS1         (PTE_FILE_SHIFT2 - PTE_FILE_SHIFT1 - 1)
+#define PTE_FILE_BITS2         (PTE_FILE_SHIFT3 - PTE_FILE_SHIFT2 - 1)
+#define PTE_FILE_BITS3         (PTE_FILE_SHIFT4 - PTE_FILE_SHIFT3 - 1)
+
+#define pte_to_pgoff(pte)                                              \
+       ((((pte).pte_low >> (PTE_FILE_SHIFT1))                          \
+         & ((1U << PTE_FILE_BITS1) - 1)))                              \
+       + ((((pte).pte_low >> (PTE_FILE_SHIFT2))                        \
+           & ((1U << PTE_FILE_BITS2) - 1))                             \
+          << (PTE_FILE_BITS1))                                         \
+       + ((((pte).pte_low >> (PTE_FILE_SHIFT3))                        \
+           & ((1U << PTE_FILE_BITS3) - 1))                             \
+          << (PTE_FILE_BITS1 + PTE_FILE_BITS2))                        \
+       + ((((pte).pte_low >> (PTE_FILE_SHIFT4)))                       \
+           << (PTE_FILE_BITS1 + PTE_FILE_BITS2 + PTE_FILE_BITS3))
+
+#define pgoff_to_pte(off)                                              \
+       ((pte_t) { .pte_low =                                           \
+        ((((off)) & ((1U << PTE_FILE_BITS1) - 1)) << PTE_FILE_SHIFT1)  \
+        + ((((off) >> PTE_FILE_BITS1)                                  \
+            & ((1U << PTE_FILE_BITS2) - 1))                            \
+           << PTE_FILE_SHIFT2)                                         \
+        + ((((off) >> (PTE_FILE_BITS1 + PTE_FILE_BITS2))               \
+            & ((1U << PTE_FILE_BITS3) - 1))                            \
+           << PTE_FILE_SHIFT3)                                         \
+        + ((((off) >>                                                  \
+             (PTE_FILE_BITS1 + PTE_FILE_BITS2 + PTE_FILE_BITS3)))      \
+           << PTE_FILE_SHIFT4)                                         \
+        + _PAGE_FILE })
+
+#else /* CONFIG_MEM_SOFT_DIRTY */
+
 /*
  * Bits _PAGE_BIT_PRESENT, _PAGE_BIT_FILE and _PAGE_BIT_PROTNONE are taken,
- * split up the 29 bits of offset into this range:
+ * split up the 29 bits of offset into this range.
  */
 #define PTE_FILE_MAX_BITS      29
 #define PTE_FILE_SHIFT1                (_PAGE_BIT_PRESENT + 1)
@@ -88,6 +132,8 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *xp)
            << PTE_FILE_SHIFT3)                                         \
         + _PAGE_FILE })
 
+#endif /* CONFIG_MEM_SOFT_DIRTY */
+
 /* Encode and de-code a swap entry */
 #if _PAGE_BIT_FILE < _PAGE_BIT_PROTNONE
 #define SWP_TYPE_BITS (_PAGE_BIT_FILE - _PAGE_BIT_PRESENT - 1)
index 4cc9f2b..81bb91b 100644 (file)
@@ -179,6 +179,9 @@ static inline pmd_t native_pmdp_get_and_clear(pmd_t *pmdp)
 /*
  * Bits 0, 6 and 7 are taken in the low part of the pte,
  * put the 32 bits of offset into the high part.
+ *
+ * For soft-dirty tracking 11 bit is taken from
+ * the low part of pte as well.
  */
 #define pte_to_pgoff(pte) ((pte).pte_high)
 #define pgoff_to_pte(off)                                              \
index 7dc305a..1c00631 100644 (file)
@@ -314,6 +314,36 @@ static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
        return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY);
 }
 
+static inline pte_t pte_swp_mksoft_dirty(pte_t pte)
+{
+       return pte_set_flags(pte, _PAGE_SWP_SOFT_DIRTY);
+}
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+       return pte_flags(pte) & _PAGE_SWP_SOFT_DIRTY;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+       return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY);
+}
+
+static inline pte_t pte_file_clear_soft_dirty(pte_t pte)
+{
+       return pte_clear_flags(pte, _PAGE_SOFT_DIRTY);
+}
+
+static inline pte_t pte_file_mksoft_dirty(pte_t pte)
+{
+       return pte_set_flags(pte, _PAGE_SOFT_DIRTY);
+}
+
+static inline int pte_file_soft_dirty(pte_t pte)
+{
+       return pte_flags(pte) & _PAGE_SOFT_DIRTY;
+}
+
 /*
  * Mask out unsupported bits in a present pgprot.  Non-present pgprots
  * can use those bits for other purposes, so leave them be.
index c98ac63..f4843e0 100644 (file)
  * they do not conflict with each other.
  */
 
+#define _PAGE_BIT_SOFT_DIRTY   _PAGE_BIT_HIDDEN
+
 #ifdef CONFIG_MEM_SOFT_DIRTY
-#define _PAGE_SOFT_DIRTY       (_AT(pteval_t, 1) << _PAGE_BIT_HIDDEN)
+#define _PAGE_SOFT_DIRTY       (_AT(pteval_t, 1) << _PAGE_BIT_SOFT_DIRTY)
 #else
 #define _PAGE_SOFT_DIRTY       (_AT(pteval_t, 0))
 #endif
 
+/*
+ * Tracking soft dirty bit when a page goes to a swap is tricky.
+ * We need a bit which can be stored in pte _and_ not conflict
+ * with swap entry format. On x86 bits 6 and 7 are *not* involved
+ * into swap entry computation, but bit 6 is used for nonlinear
+ * file mapping, so we borrow bit 7 for soft dirty tracking.
+ */
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define _PAGE_SWP_SOFT_DIRTY   _PAGE_PSE
+#else
+#define _PAGE_SWP_SOFT_DIRTY   (_AT(pteval_t, 0))
+#endif
+
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
 #define _PAGE_NX       (_AT(pteval_t, 1) << _PAGE_BIT_NX)
 #else
index 33692ea..e3ddd7d 100644 (file)
@@ -233,8 +233,4 @@ static inline void arch_write_unlock(arch_rwlock_t *rw)
 #define arch_read_relax(lock)  cpu_relax()
 #define arch_write_relax(lock) cpu_relax()
 
-/* The {read|write|spin}_lock() on x86 are full memory barriers. */
-static inline void smp_mb__after_lock(void) { }
-#define ARCH_HAS_SMP_MB_AFTER_LOCK
-
 #endif /* _ASM_X86_SPINLOCK_H */
index e270352..c370e1c 100644 (file)
@@ -111,8 +111,8 @@ static struct severity {
 #ifdef CONFIG_MEMORY_FAILURE
        MCESEV(
                KEEP, "Action required but unaffected thread is continuable",
-               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR),
-               MCGMASK(MCG_STATUS_RIPV, MCG_STATUS_RIPV)
+               SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR, MCI_UC_SAR|MCI_ADDR),
+               MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, MCG_STATUS_RIPV)
                ),
        MCESEV(
                AR, "Action required: data load error in a user process",
index fbc9210..a45d8d4 100644 (file)
@@ -2270,6 +2270,7 @@ __init int intel_pmu_init(void)
        case 70:
        case 71:
        case 63:
+       case 69:
                x86_pmu.late_ack = true;
                memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids));
                memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
index cad791d..1fb6c72 100644 (file)
@@ -314,8 +314,8 @@ static struct uncore_event_desc snbep_uncore_imc_events[] = {
 static struct uncore_event_desc snbep_uncore_qpi_events[] = {
        INTEL_UNCORE_EVENT_DESC(clockticks,       "event=0x14"),
        INTEL_UNCORE_EVENT_DESC(txl_flits_active, "event=0x00,umask=0x06"),
-       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x02,umask=0x08"),
-       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x03,umask=0x04"),
+       INTEL_UNCORE_EVENT_DESC(drs_data,         "event=0x102,umask=0x08"),
+       INTEL_UNCORE_EVENT_DESC(ncb_data,         "event=0x103,umask=0x04"),
        { /* end: all zeroes */ },
 };
 
index 94ab6b9..63bdb29 100644 (file)
@@ -196,15 +196,23 @@ static void __init ati_bugs_contd(int num, int slot, int func)
 static void __init intel_remapping_check(int num, int slot, int func)
 {
        u8 revision;
+       u16 device;
 
+       device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
        revision = read_pci_config_byte(num, slot, func, PCI_REVISION_ID);
 
        /*
-        * Revision 0x13 of this chipset supports irq remapping
-        * but has an erratum that breaks its behavior, flag it as such
+        * Revision 13 of all triggering devices id in this quirk have
+        * a problem draining interrupts when irq remapping is enabled,
+        * and should be flagged as broken.  Additionally revisions 0x12
+        * and 0x22 of device id 0x3405 has this problem.
         */
        if (revision == 0x13)
                set_irq_remapping_broken();
+       else if ((device == 0x3405) &&
+           ((revision == 0x12) ||
+            (revision == 0x22)))
+               set_irq_remapping_broken();
 
 }
 
@@ -239,6 +247,8 @@ static struct chipset early_qrk[] __initdata = {
          PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
        { PCI_VENDOR_ID_INTEL, 0x3403, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
+       { PCI_VENDOR_ID_INTEL, 0x3405, PCI_CLASS_BRIDGE_HOST,
+         PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        {}
index 202d24f..5d576ab 100644 (file)
@@ -116,7 +116,7 @@ static void mxcsr_feature_mask_init(void)
 
        if (cpu_has_fxsr) {
                memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
-               asm volatile("fxsave %0" : : "m" (fx_scratch));
+               asm volatile("fxsave %0" : "+m" (fx_scratch));
                mask = fx_scratch.mxcsr_mask;
                if (mask == 0)
                        mask = 0x0000ffbf;
index 47ebb1d..7a0adb7 100644 (file)
@@ -220,12 +220,13 @@ int apply_microcode_amd(int cpu)
                return 0;
        }
 
-       if (__apply_microcode_amd(mc_amd))
+       if (__apply_microcode_amd(mc_amd)) {
                pr_err("CPU%d: update failed for patch_level=0x%08x\n",
                        cpu, mc_amd->hdr.patch_id);
-       else
-               pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
-                       mc_amd->hdr.patch_id);
+               return -1;
+       }
+       pr_info("CPU%d: new patch_level=0x%08x\n", cpu,
+               mc_amd->hdr.patch_id);
 
        uci->cpu_sig.rev = mc_amd->hdr.patch_id;
        c->microcode = mc_amd->hdr.patch_id;
index dbded5a..48f8375 100644 (file)
@@ -101,7 +101,7 @@ static void find_start_end(unsigned long flags, unsigned long *begin,
                                *begin = new_begin;
                }
        } else {
-               *begin = TASK_UNMAPPED_BASE;
+               *begin = mmap_legacy_base();
                *end = TASK_SIZE;
        }
 }
index 62c29a5..f63778c 100644 (file)
@@ -98,7 +98,7 @@ static unsigned long mmap_base(void)
  * Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64
  * does, but not when emulating X86_32
  */
-static unsigned long mmap_legacy_base(void)
+unsigned long mmap_legacy_base(void)
 {
        if (mmap_is_ia32())
                return TASK_UNMAPPED_BASE;
index 643b8b5..8244f5e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/reboot.h>
 #include <linux/serial_reg.h>
 #include <linux/serial_8250.h>
 #include <linux/reboot.h>
index d21167b..dc34a5b 100644 (file)
@@ -359,6 +359,9 @@ int braille_register_console(struct console *console, int index,
                char *console_options, char *braille_options)
 {
        int ret;
+
+       if (!(console->flags & CON_BRL))
+               return 0;
        if (!console_options)
                /* Only support VisioBraille for now */
                console_options = "57600o8";
@@ -374,15 +377,17 @@ int braille_register_console(struct console *console, int index,
        braille_co = console;
        register_keyboard_notifier(&keyboard_notifier_block);
        register_vt_notifier(&vt_notifier_block);
-       return 0;
+       return 1;
 }
 
 int braille_unregister_console(struct console *console)
 {
        if (braille_co != console)
                return -EINVAL;
+       if (!(console->flags & CON_BRL))
+               return 0;
        unregister_keyboard_notifier(&keyboard_notifier_block);
        unregister_vt_notifier(&vt_notifier_block);
        braille_co = NULL;
-       return 0;
+       return 1;
 }
index fd6c51c..5a74a9c 100644 (file)
@@ -451,7 +451,6 @@ static void acpi_processor_remove(struct acpi_device *device)
        /* Clean up. */
        per_cpu(processor_device_array, pr->id) = NULL;
        per_cpu(processors, pr->id) = NULL;
-       try_offline_node(cpu_to_node(pr->id));
 
        /* Remove the CPU. */
        get_online_cpus();
@@ -459,6 +458,8 @@ static void acpi_processor_remove(struct acpi_device *device)
        acpi_unmap_lsapic(pr->id);
        put_online_cpus();
 
+       try_offline_node(cpu_to_node(pr->id));
+
  out:
        free_cpumask_var(pr->throttling.shared_cpu_map);
        kfree(pr);
index 082b4dd..d405fba 100644 (file)
@@ -117,6 +117,7 @@ struct acpi_battery {
        struct acpi_device *device;
        struct notifier_block pm_nb;
        unsigned long update_time;
+       int revision;
        int rate_now;
        int capacity_now;
        int voltage_now;
@@ -359,6 +360,7 @@ static struct acpi_offsets info_offsets[] = {
 };
 
 static struct acpi_offsets extended_info_offsets[] = {
+       {offsetof(struct acpi_battery, revision), 0},
        {offsetof(struct acpi_battery, power_unit), 0},
        {offsetof(struct acpi_battery, design_capacity), 0},
        {offsetof(struct acpi_battery, full_charge_capacity), 0},
index f680957..408f6b2 100644 (file)
@@ -31,6 +31,7 @@ static LIST_HEAD(bus_type_list);
 static DECLARE_RWSEM(bus_type_sem);
 
 #define PHYSICAL_NODE_STRING "physical_node"
+#define PHYSICAL_NODE_NAME_SIZE (sizeof(PHYSICAL_NODE_STRING) + 10)
 
 int register_acpi_bus_type(struct acpi_bus_type *type)
 {
@@ -78,41 +79,108 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
        return ret;
 }
 
-static acpi_status do_acpi_find_child(acpi_handle handle, u32 lvl_not_used,
-                                     void *addr_p, void **ret_p)
+static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
+                                 void *not_used, void **ret_p)
 {
-       unsigned long long addr, sta;
-       acpi_status status;
+       struct acpi_device *adev = NULL;
 
-       status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
-       if (ACPI_SUCCESS(status) && addr == *((u64 *)addr_p)) {
+       acpi_bus_get_device(handle, &adev);
+       if (adev) {
                *ret_p = handle;
-               status = acpi_bus_get_status_handle(handle, &sta);
-               if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_ENABLED))
-                       return AE_CTRL_TERMINATE;
+               return AE_CTRL_TERMINATE;
        }
        return AE_OK;
 }
 
-acpi_handle acpi_get_child(acpi_handle parent, u64 address)
+static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
 {
-       void *ret = NULL;
+       unsigned long long sta;
+       acpi_status status;
+
+       status = acpi_bus_get_status_handle(handle, &sta);
+       if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
+               return false;
+
+       if (is_bridge) {
+               void *test = NULL;
+
+               /* Check if this object has at least one child device. */
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+                                   acpi_dev_present, NULL, NULL, &test);
+               return !!test;
+       }
+       return true;
+}
+
+struct find_child_context {
+       u64 addr;
+       bool is_bridge;
+       acpi_handle ret;
+       bool ret_checked;
+};
+
+static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
+                                void *data, void **not_used)
+{
+       struct find_child_context *context = data;
+       unsigned long long addr;
+       acpi_status status;
 
-       if (!parent)
-               return NULL;
+       status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
+       if (ACPI_FAILURE(status) || addr != context->addr)
+               return AE_OK;
 
-       acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, NULL,
-                           do_acpi_find_child, &address, &ret);
-       return (acpi_handle)ret;
+       if (!context->ret) {
+               /* This is the first matching object.  Save its handle. */
+               context->ret = handle;
+               return AE_OK;
+       }
+       /*
+        * There is more than one matching object with the same _ADR value.
+        * That really is unexpected, so we are kind of beyond the scope of the
+        * spec here.  We have to choose which one to return, though.
+        *
+        * First, check if the previously found object is good enough and return
+        * its handle if so.  Second, check the same for the object that we've
+        * just found.
+        */
+       if (!context->ret_checked) {
+               if (acpi_extra_checks_passed(context->ret, context->is_bridge))
+                       return AE_CTRL_TERMINATE;
+               else
+                       context->ret_checked = true;
+       }
+       if (acpi_extra_checks_passed(handle, context->is_bridge)) {
+               context->ret = handle;
+               return AE_CTRL_TERMINATE;
+       }
+       return AE_OK;
 }
-EXPORT_SYMBOL(acpi_get_child);
+
+acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge)
+{
+       if (parent) {
+               struct find_child_context context = {
+                       .addr = addr,
+                       .is_bridge = is_bridge,
+               };
+
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child,
+                                   NULL, &context, NULL);
+               return context.ret;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(acpi_find_child);
 
 int acpi_bind_one(struct device *dev, acpi_handle handle)
 {
        struct acpi_device *acpi_dev;
        acpi_status status;
        struct acpi_device_physical_node *physical_node, *pn;
-       char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
+       char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
+       struct list_head *physnode_list;
+       unsigned int node_id;
        int retval = -EINVAL;
 
        if (ACPI_HANDLE(dev)) {
@@ -139,25 +207,27 @@ int acpi_bind_one(struct device *dev, acpi_handle handle)
 
        mutex_lock(&acpi_dev->physical_node_lock);
 
-       /* Sanity check. */
-       list_for_each_entry(pn, &acpi_dev->physical_node_list, node)
+       /*
+        * Keep the list sorted by node_id so that the IDs of removed nodes can
+        * be recycled easily.
+        */
+       physnode_list = &acpi_dev->physical_node_list;
+       node_id = 0;
+       list_for_each_entry(pn, &acpi_dev->physical_node_list, node) {
+               /* Sanity check. */
                if (pn->dev == dev) {
                        dev_warn(dev, "Already associated with ACPI node\n");
                        goto err_free;
                }
-
-       /* allocate physical node id according to physical_node_id_bitmap */
-       physical_node->node_id =
-               find_first_zero_bit(acpi_dev->physical_node_id_bitmap,
-               ACPI_MAX_PHYSICAL_NODE);
-       if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
-               retval = -ENOSPC;
-               goto err_free;
+               if (pn->node_id == node_id) {
+                       physnode_list = &pn->node;
+                       node_id++;
+               }
        }
 
-       set_bit(physical_node->node_id, acpi_dev->physical_node_id_bitmap);
+       physical_node->node_id = node_id;
        physical_node->dev = dev;
-       list_add_tail(&physical_node->node, &acpi_dev->physical_node_list);
+       list_add(&physical_node->node, physnode_list);
        acpi_dev->physical_node_count++;
 
        mutex_unlock(&acpi_dev->physical_node_lock);
@@ -208,7 +278,7 @@ int acpi_unbind_one(struct device *dev)
 
        mutex_lock(&acpi_dev->physical_node_lock);
        list_for_each_safe(node, next, &acpi_dev->physical_node_list) {
-               char physical_node_name[sizeof(PHYSICAL_NODE_STRING) + 2];
+               char physical_node_name[PHYSICAL_NODE_NAME_SIZE];
 
                entry = list_entry(node, struct acpi_device_physical_node,
                        node);
@@ -216,7 +286,6 @@ int acpi_unbind_one(struct device *dev)
                        continue;
 
                list_del(node);
-               clear_bit(entry->node_id, acpi_dev->physical_node_id_bitmap);
 
                acpi_dev->physical_node_count--;
 
index aa1227a..04a1378 100644 (file)
@@ -311,6 +311,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
                           dev->pnp.bus_id,
                           (u32) dev->wakeup.sleep_state);
 
+               mutex_lock(&dev->physical_node_lock);
+
                if (!dev->physical_node_count) {
                        seq_printf(seq, "%c%-8s\n",
                                dev->wakeup.flags.run_wake ? '*' : ' ',
@@ -338,6 +340,8 @@ acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
                                put_device(ldev);
                        }
                }
+
+               mutex_unlock(&dev->physical_node_lock);
        }
        mutex_unlock(&acpi_device_lock);
        return 0;
@@ -347,12 +351,16 @@ static void physical_device_enable_wakeup(struct acpi_device *adev)
 {
        struct acpi_device_physical_node *entry;
 
+       mutex_lock(&adev->physical_node_lock);
+
        list_for_each_entry(entry,
                &adev->physical_node_list, node)
                if (entry->dev && device_can_wakeup(entry->dev)) {
                        bool enable = !device_may_wakeup(entry->dev);
                        device_set_wakeup_enable(entry->dev, enable);
                }
+
+       mutex_unlock(&adev->physical_node_lock);
 }
 
 static ssize_t
index 0ec434d..e1284b8 100644 (file)
@@ -689,7 +689,7 @@ static int acpi_video_bqc_quirk(struct acpi_video_device *device,
         * Some systems always report current brightness level as maximum
         * through _BQC, we need to test another value for them.
         */
-       test_level = current_level == max_level ? br->levels[2] : max_level;
+       test_level = current_level == max_level ? br->levels[3] : max_level;
 
        result = acpi_video_device_lcd_set_level(device, test_level);
        if (result)
index 4ec7c04..26386f0 100644 (file)
@@ -237,6 +237,7 @@ static const struct of_device_id imx_pata_dt_ids[] = {
                /* sentinel */
        }
 };
+MODULE_DEVICE_TABLE(of, imx_pata_dt_ids);
 
 static struct platform_driver pata_imx_driver = {
        .probe          = pata_imx_probe,
index e691026..3455f83 100644 (file)
@@ -719,7 +719,8 @@ static int regcache_sync_block_raw(struct regmap *map, void *block,
                }
        }
 
-       return regcache_sync_block_raw_flush(map, &data, base, regtmp);
+       return regcache_sync_block_raw_flush(map, &data, base, regtmp +
+                       map->reg_stride);
 }
 
 int regcache_sync_block(struct regmap *map, void *block,
index 99cb944..4d45dba 100644 (file)
@@ -906,16 +906,10 @@ bio_pageinc(struct bio *bio)
        int i;
 
        bio_for_each_segment(bv, bio, i) {
-               page = bv->bv_page;
                /* Non-zero page count for non-head members of
-                * compound pages is no longer allowed by the kernel,
-                * but this has never been seen here.
+                * compound pages is no longer allowed by the kernel.
                 */
-               if (unlikely(PageCompound(page)))
-                       if (compound_trans_head(page) != page) {
-                               pr_crit("page tail used for block I/O\n");
-                               BUG();
-                       }
+               page = compound_trans_head(bv->bv_page);
                atomic_inc(&page->_count);
        }
 }
@@ -924,10 +918,13 @@ static void
 bio_pagedec(struct bio *bio)
 {
        struct bio_vec *bv;
+       struct page *page;
        int i;
 
-       bio_for_each_segment(bv, bio, i)
-               atomic_dec(&bv->bv_page->_count);
+       bio_for_each_segment(bv, bio, i) {
+               page = compound_trans_head(bv->bv_page);
+               atomic_dec(&page->_count);
+       }
 }
 
 static void
index 11f467c..a12b923 100644 (file)
@@ -91,6 +91,10 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0489, 0xe04e) },
        { USB_DEVICE(0x0489, 0xe056) },
        { USB_DEVICE(0x0489, 0xe04d) },
+       { USB_DEVICE(0x04c5, 0x1330) },
+       { USB_DEVICE(0x13d3, 0x3402) },
+       { USB_DEVICE(0x0cf3, 0x3121) },
+       { USB_DEVICE(0x0cf3, 0xe003) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -128,6 +132,10 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU22 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
@@ -193,24 +201,44 @@ error:
 
 static int ath3k_get_state(struct usb_device *udev, unsigned char *state)
 {
-       int pipe = 0;
+       int ret, pipe = 0;
+       char *buf;
+
+       buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        pipe = usb_rcvctrlpipe(udev, 0);
-       return usb_control_msg(udev, pipe, ATH3K_GETSTATE,
-                       USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
-                       state, 0x01, USB_CTRL_SET_TIMEOUT);
+       ret = usb_control_msg(udev, pipe, ATH3K_GETSTATE,
+                             USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                             buf, sizeof(*buf), USB_CTRL_SET_TIMEOUT);
+
+       *state = *buf;
+       kfree(buf);
+
+       return ret;
 }
 
 static int ath3k_get_version(struct usb_device *udev,
                        struct ath3k_version *version)
 {
-       int pipe = 0;
+       int ret, pipe = 0;
+       struct ath3k_version *buf;
+       const int size = sizeof(*buf);
+
+       buf = kmalloc(size, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        pipe = usb_rcvctrlpipe(udev, 0);
-       return usb_control_msg(udev, pipe, ATH3K_GETVERSION,
-                       USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, version,
-                       sizeof(struct ath3k_version),
-                       USB_CTRL_SET_TIMEOUT);
+       ret = usb_control_msg(udev, pipe, ATH3K_GETVERSION,
+                             USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+                             buf, size, USB_CTRL_SET_TIMEOUT);
+
+       memcpy(version, buf, size);
+       kfree(buf);
+
+       return ret;
 }
 
 static int ath3k_load_fwfile(struct usb_device *udev,
index de4cf4d..8e16f0a 100644 (file)
@@ -154,6 +154,10 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe056), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x04c5, 0x1330), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x3121), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0xe003), .driver_info = BTUSB_ATH3012 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -1095,7 +1099,7 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev,
        if (IS_ERR(skb)) {
                BT_ERR("%s sending Intel patch command (0x%4.4x) failed (%ld)",
                       hdev->name, cmd->opcode, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        /* It ensures that the returned event matches the event data read from
@@ -1147,7 +1151,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s sending initial HCI reset command failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1161,7 +1165,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s reading Intel fw version command failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        if (skb->len != sizeof(*ver)) {
@@ -1219,7 +1223,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
                BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
                release_firmware(fw);
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
 
        if (skb->data[0]) {
@@ -1276,7 +1280,7 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1292,7 +1296,7 @@ exit_mfg_disable:
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
@@ -1310,7 +1314,7 @@ exit_mfg_deactivate:
        if (IS_ERR(skb)) {
                BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
                       hdev->name, PTR_ERR(skb));
-               return -PTR_ERR(skb);
+               return PTR_ERR(skb);
        }
        kfree_skb(skb);
 
index bf5d247..15f2e70 100644 (file)
@@ -129,7 +129,8 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
        off_t j, io_pg_start;
        int io_pg_count;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type ||
+               agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
                return -EINVAL;
        }
 
@@ -175,7 +176,8 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
        struct _parisc_agp_info *info = &parisc_agp_info;
        int i, io_pg_start, io_pg_count;
 
-       if (type != 0 || mem->type != 0) {
+       if (type != mem->type ||
+               agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type)) {
                return -EINVAL;
        }
 
index 1b456fe..fc45567 100644 (file)
@@ -272,9 +272,12 @@ static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
        unsigned long flags;
 
        spin_lock_irqsave(&portdev->ports_lock, flags);
-       list_for_each_entry(port, &portdev->ports, list)
-               if (port->cdev->dev == dev)
+       list_for_each_entry(port, &portdev->ports, list) {
+               if (port->cdev->dev == dev) {
+                       kref_get(&port->kref);
                        goto out;
+               }
+       }
        port = NULL;
 out:
        spin_unlock_irqrestore(&portdev->ports_lock, flags);
@@ -746,6 +749,10 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
 
        port = filp->private_data;
 
+       /* Port is hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
+
        if (!port_has_data(port)) {
                /*
                 * If nothing's connected on the host just return 0 in
@@ -762,7 +769,7 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
                if (ret < 0)
                        return ret;
        }
-       /* Port got hot-unplugged. */
+       /* Port got hot-unplugged while we were waiting above. */
        if (!port->guest_connected)
                return -ENODEV;
        /*
@@ -932,13 +939,25 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
        if (is_rproc_serial(port->out_vq->vdev))
                return -EINVAL;
 
+       /*
+        * pipe->nrbufs == 0 means there are no data to transfer,
+        * so this returns just 0 for no data.
+        */
+       pipe_lock(pipe);
+       if (!pipe->nrbufs) {
+               ret = 0;
+               goto error_out;
+       }
+
        ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
        if (ret < 0)
-               return ret;
+               goto error_out;
 
        buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
-       if (!buf)
-               return -ENOMEM;
+       if (!buf) {
+               ret = -ENOMEM;
+               goto error_out;
+       }
 
        sgl.n = 0;
        sgl.len = 0;
@@ -946,12 +965,17 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
        sgl.sg = buf->sg;
        sg_init_table(sgl.sg, sgl.size);
        ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
+       pipe_unlock(pipe);
        if (likely(ret > 0))
                ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
 
        if (unlikely(ret <= 0))
                free_buf(buf, true);
        return ret;
+
+error_out:
+       pipe_unlock(pipe);
+       return ret;
 }
 
 static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
@@ -1019,14 +1043,14 @@ static int port_fops_open(struct inode *inode, struct file *filp)
        struct port *port;
        int ret;
 
+       /* We get the port with a kref here */
        port = find_port_by_devt(cdev->dev);
+       if (!port) {
+               /* Port was unplugged before we could proceed */
+               return -ENXIO;
+       }
        filp->private_data = port;
 
-       /* Prevent against a port getting hot-unplugged at the same time */
-       spin_lock_irq(&port->portdev->ports_lock);
-       kref_get(&port->kref);
-       spin_unlock_irq(&port->portdev->ports_lock);
-
        /*
         * Don't allow opening of console port devices -- that's done
         * via /dev/hvc
@@ -1498,14 +1522,6 @@ static void remove_port(struct kref *kref)
 
        port = container_of(kref, struct port, kref);
 
-       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-       device_destroy(pdrvdata.class, port->dev->devt);
-       cdev_del(port->cdev);
-
-       kfree(port->name);
-
-       debugfs_remove(port->debugfs_file);
-
        kfree(port);
 }
 
@@ -1539,12 +1555,14 @@ static void unplug_port(struct port *port)
        spin_unlock_irq(&port->portdev->ports_lock);
 
        if (port->guest_connected) {
+               /* Let the app know the port is going down. */
+               send_sigio_to_port(port);
+
+               /* Do this after sigio is actually sent */
                port->guest_connected = false;
                port->host_connected = false;
-               wake_up_interruptible(&port->waitqueue);
 
-               /* Let the app know the port is going down. */
-               send_sigio_to_port(port);
+               wake_up_interruptible(&port->waitqueue);
        }
 
        if (is_console_port(port)) {
@@ -1563,6 +1581,14 @@ static void unplug_port(struct port *port)
         */
        port->portdev = NULL;
 
+       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+       device_destroy(pdrvdata.class, port->dev->devt);
+       cdev_del(port->cdev);
+
+       kfree(port->name);
+
+       debugfs_remove(port->debugfs_file);
+
        /*
         * Locks around here are not necessary - a port can't be
         * opened after we removed the port struct from ports_list
index 1bdb882..4e57397 100644 (file)
@@ -581,11 +581,15 @@ struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
        DIV(none, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4),
        DIV(none, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8),
        DIV(none, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4),
-       DIV(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3),
-       DIV(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3),
+       DIV_F(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3,
+                                               CLK_GET_RATE_NOCACHE, 0),
+       DIV_F(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3,
+                                               CLK_GET_RATE_NOCACHE, 0),
        DIV(none, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3),
-       DIV(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, 4, 3),
-       DIV(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3),
+       DIV_F(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1,
+                                               4, 3, CLK_GET_RATE_NOCACHE, 0),
+       DIV_F(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
+                                               8, 3, CLK_GET_RATE_NOCACHE, 0),
        DIV(sclk_fimg2d, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
 };
 
@@ -863,57 +867,57 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
        GATE_DA(i2s0, "samsung-i2s.0", "i2s0", "aclk100",
                        E4X12_GATE_IP_MAUDIO, 3, 0, 0, "iis"),
        GATE(fimc_isp, "isp", "aclk200", E4X12_GATE_ISP0, 0,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(fimc_drc, "drc", "aclk200", E4X12_GATE_ISP0, 1,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(fimc_fd, "fd", "aclk200", E4X12_GATE_ISP0, 2,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(fimc_lite0, "lite0", "aclk200", E4X12_GATE_ISP0, 3,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(fimc_lite1, "lite1", "aclk200", E4X12_GATE_ISP0, 4,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(mcuisp, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(gicisp, "gicisp", "aclk200", E4X12_GATE_ISP0, 7,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(smmu_isp, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(smmu_drc, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(smmu_fd, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(smmu_lite0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(smmu_lite1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(ppmuispmx, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(ppmuispx, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(mcuctl_isp, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(mpwm_isp, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(i2c0_isp, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(i2c1_isp, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(mtcadc_isp, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(pwm_isp, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(wdt_isp, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(uart_isp, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(asyncaxim, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(smmu_ispcx, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(spi0_isp, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
-                       CLK_IGNORE_UNUSED, 0),
+                       CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(g2d, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),
 };
 
index 5c205b6..089d3e3 100644 (file)
@@ -71,6 +71,7 @@ static DEFINE_SPINLOCK(armpll_lock);
 static DEFINE_SPINLOCK(ddrpll_lock);
 static DEFINE_SPINLOCK(iopll_lock);
 static DEFINE_SPINLOCK(armclk_lock);
+static DEFINE_SPINLOCK(swdtclk_lock);
 static DEFINE_SPINLOCK(ddrclk_lock);
 static DEFINE_SPINLOCK(dciclk_lock);
 static DEFINE_SPINLOCK(gem0clk_lock);
@@ -293,7 +294,7 @@ static void __init zynq_clk_setup(struct device_node *np)
        }
        clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt],
                        swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT,
-                       SLCR_SWDT_CLK_SEL, 0, 1, 0, &gem0clk_lock);
+                       SLCR_SWDT_CLK_SEL, 0, 1, 0, &swdtclk_lock);
 
        /* DDR clocks */
        clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0,
@@ -364,8 +365,9 @@ static void __init zynq_clk_setup(struct device_node *np)
                        CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6,
                        CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                        &gem0clk_lock);
-       clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, 0,
-                       SLCR_GEM0_CLK_CTRL, 6, 1, 0, &gem0clk_lock);
+       clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2,
+                       CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 6, 1, 0,
+                       &gem0clk_lock);
        clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0],
                        "gem0_emio_mux", CLK_SET_RATE_PARENT,
                        SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock);
@@ -386,8 +388,9 @@ static void __init zynq_clk_setup(struct device_node *np)
                        CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6,
                        CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                        &gem1clk_lock);
-       clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, 0,
-                       SLCR_GEM1_CLK_CTRL, 6, 1, 0, &gem1clk_lock);
+       clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2,
+                       CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 6, 1, 0,
+                       &gem1clk_lock);
        clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1],
                        "gem1_emio_mux", CLK_SET_RATE_PARENT,
                        SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock);
index a4ad733..f0a5e2b 100644 (file)
@@ -1177,14 +1177,11 @@ static int __cpufreq_remove_dev(struct device *dev,
                                __func__, cpu_dev->id, cpu);
        }
 
-       if ((cpus == 1) && (cpufreq_driver->target))
-               __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
-
-       pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
-       cpufreq_cpu_put(data);
-
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
+               if (cpufreq_driver->target)
+                       __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT);
+
                lock_policy_rwsem_read(cpu);
                kobj = &data->kobj;
                cmp = &data->kobj_unregister;
@@ -1205,9 +1202,13 @@ static int __cpufreq_remove_dev(struct device *dev,
                free_cpumask_var(data->related_cpus);
                free_cpumask_var(data->cpus);
                kfree(data);
-       } else if (cpufreq_driver->target) {
-               __cpufreq_governor(data, CPUFREQ_GOV_START);
-               __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+       } else {
+               pr_debug("%s: removing link, cpu: %d\n", __func__, cpu);
+               cpufreq_cpu_put(data);
+               if (cpufreq_driver->target) {
+                       __cpufreq_governor(data, CPUFREQ_GOV_START);
+                       __cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
+               }
        }
 
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
index 0ceb2ef..f97cb3d 100644 (file)
@@ -221,8 +221,8 @@ static ssize_t store_down_threshold(struct dbs_data *dbs_data, const char *buf,
        return count;
 }
 
-static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
-               size_t count)
+static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
+               const char *buf, size_t count)
 {
        struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
        unsigned int input, j;
@@ -235,10 +235,10 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
        if (input > 1)
                input = 1;
 
-       if (input == cs_tuners->ignore_nice) /* nothing to do */
+       if (input == cs_tuners->ignore_nice_load) /* nothing to do */
                return count;
 
-       cs_tuners->ignore_nice = input;
+       cs_tuners->ignore_nice_load = input;
 
        /* we need to re-evaluate prev_cpu_idle */
        for_each_online_cpu(j) {
@@ -246,7 +246,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
                dbs_info = &per_cpu(cs_cpu_dbs_info, j);
                dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
                                        &dbs_info->cdbs.prev_cpu_wall, 0);
-               if (cs_tuners->ignore_nice)
+               if (cs_tuners->ignore_nice_load)
                        dbs_info->cdbs.prev_cpu_nice =
                                kcpustat_cpu(j).cpustat[CPUTIME_NICE];
        }
@@ -279,7 +279,7 @@ show_store_one(cs, sampling_rate);
 show_store_one(cs, sampling_down_factor);
 show_store_one(cs, up_threshold);
 show_store_one(cs, down_threshold);
-show_store_one(cs, ignore_nice);
+show_store_one(cs, ignore_nice_load);
 show_store_one(cs, freq_step);
 declare_show_sampling_rate_min(cs);
 
@@ -287,7 +287,7 @@ gov_sys_pol_attr_rw(sampling_rate);
 gov_sys_pol_attr_rw(sampling_down_factor);
 gov_sys_pol_attr_rw(up_threshold);
 gov_sys_pol_attr_rw(down_threshold);
-gov_sys_pol_attr_rw(ignore_nice);
+gov_sys_pol_attr_rw(ignore_nice_load);
 gov_sys_pol_attr_rw(freq_step);
 gov_sys_pol_attr_ro(sampling_rate_min);
 
@@ -297,7 +297,7 @@ static struct attribute *dbs_attributes_gov_sys[] = {
        &sampling_down_factor_gov_sys.attr,
        &up_threshold_gov_sys.attr,
        &down_threshold_gov_sys.attr,
-       &ignore_nice_gov_sys.attr,
+       &ignore_nice_load_gov_sys.attr,
        &freq_step_gov_sys.attr,
        NULL
 };
@@ -313,7 +313,7 @@ static struct attribute *dbs_attributes_gov_pol[] = {
        &sampling_down_factor_gov_pol.attr,
        &up_threshold_gov_pol.attr,
        &down_threshold_gov_pol.attr,
-       &ignore_nice_gov_pol.attr,
+       &ignore_nice_load_gov_pol.attr,
        &freq_step_gov_pol.attr,
        NULL
 };
@@ -338,7 +338,7 @@ static int cs_init(struct dbs_data *dbs_data)
        tuners->up_threshold = DEF_FREQUENCY_UP_THRESHOLD;
        tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
        tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
-       tuners->ignore_nice = 0;
+       tuners->ignore_nice_load = 0;
        tuners->freq_step = DEF_FREQUENCY_STEP;
 
        dbs_data->tuners = tuners;
index 7b839a8..e59afaa 100644 (file)
@@ -47,9 +47,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
        unsigned int j;
 
        if (dbs_data->cdata->governor == GOV_ONDEMAND)
-               ignore_nice = od_tuners->ignore_nice;
+               ignore_nice = od_tuners->ignore_nice_load;
        else
-               ignore_nice = cs_tuners->ignore_nice;
+               ignore_nice = cs_tuners->ignore_nice_load;
 
        policy = cdbs->cur_policy;
 
@@ -298,12 +298,12 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                cs_tuners = dbs_data->tuners;
                cs_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
                sampling_rate = cs_tuners->sampling_rate;
-               ignore_nice = cs_tuners->ignore_nice;
+               ignore_nice = cs_tuners->ignore_nice_load;
        } else {
                od_tuners = dbs_data->tuners;
                od_dbs_info = dbs_data->cdata->get_cpu_dbs_info_s(cpu);
                sampling_rate = od_tuners->sampling_rate;
-               ignore_nice = od_tuners->ignore_nice;
+               ignore_nice = od_tuners->ignore_nice_load;
                od_ops = dbs_data->cdata->gov_ops;
                io_busy = od_tuners->io_is_busy;
        }
index 6663ec3..d5f12b4 100644 (file)
@@ -165,7 +165,7 @@ struct cs_cpu_dbs_info_s {
 
 /* Per policy Governers sysfs tunables */
 struct od_dbs_tuners {
-       unsigned int ignore_nice;
+       unsigned int ignore_nice_load;
        unsigned int sampling_rate;
        unsigned int sampling_down_factor;
        unsigned int up_threshold;
@@ -175,7 +175,7 @@ struct od_dbs_tuners {
 };
 
 struct cs_dbs_tuners {
-       unsigned int ignore_nice;
+       unsigned int ignore_nice_load;
        unsigned int sampling_rate;
        unsigned int sampling_down_factor;
        unsigned int up_threshold;
index 93eb5cb..c087347 100644 (file)
@@ -403,8 +403,8 @@ static ssize_t store_sampling_down_factor(struct dbs_data *dbs_data,
        return count;
 }
 
-static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
-               size_t count)
+static ssize_t store_ignore_nice_load(struct dbs_data *dbs_data,
+               const char *buf, size_t count)
 {
        struct od_dbs_tuners *od_tuners = dbs_data->tuners;
        unsigned int input;
@@ -419,10 +419,10 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
        if (input > 1)
                input = 1;
 
-       if (input == od_tuners->ignore_nice) { /* nothing to do */
+       if (input == od_tuners->ignore_nice_load) { /* nothing to do */
                return count;
        }
-       od_tuners->ignore_nice = input;
+       od_tuners->ignore_nice_load = input;
 
        /* we need to re-evaluate prev_cpu_idle */
        for_each_online_cpu(j) {
@@ -430,7 +430,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
                dbs_info = &per_cpu(od_cpu_dbs_info, j);
                dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
                        &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
-               if (od_tuners->ignore_nice)
+               if (od_tuners->ignore_nice_load)
                        dbs_info->cdbs.prev_cpu_nice =
                                kcpustat_cpu(j).cpustat[CPUTIME_NICE];
 
@@ -461,7 +461,7 @@ show_store_one(od, sampling_rate);
 show_store_one(od, io_is_busy);
 show_store_one(od, up_threshold);
 show_store_one(od, sampling_down_factor);
-show_store_one(od, ignore_nice);
+show_store_one(od, ignore_nice_load);
 show_store_one(od, powersave_bias);
 declare_show_sampling_rate_min(od);
 
@@ -469,7 +469,7 @@ gov_sys_pol_attr_rw(sampling_rate);
 gov_sys_pol_attr_rw(io_is_busy);
 gov_sys_pol_attr_rw(up_threshold);
 gov_sys_pol_attr_rw(sampling_down_factor);
-gov_sys_pol_attr_rw(ignore_nice);
+gov_sys_pol_attr_rw(ignore_nice_load);
 gov_sys_pol_attr_rw(powersave_bias);
 gov_sys_pol_attr_ro(sampling_rate_min);
 
@@ -478,7 +478,7 @@ static struct attribute *dbs_attributes_gov_sys[] = {
        &sampling_rate_gov_sys.attr,
        &up_threshold_gov_sys.attr,
        &sampling_down_factor_gov_sys.attr,
-       &ignore_nice_gov_sys.attr,
+       &ignore_nice_load_gov_sys.attr,
        &powersave_bias_gov_sys.attr,
        &io_is_busy_gov_sys.attr,
        NULL
@@ -494,7 +494,7 @@ static struct attribute *dbs_attributes_gov_pol[] = {
        &sampling_rate_gov_pol.attr,
        &up_threshold_gov_pol.attr,
        &sampling_down_factor_gov_pol.attr,
-       &ignore_nice_gov_pol.attr,
+       &ignore_nice_load_gov_pol.attr,
        &powersave_bias_gov_pol.attr,
        &io_is_busy_gov_pol.attr,
        NULL
@@ -544,7 +544,7 @@ static int od_init(struct dbs_data *dbs_data)
        }
 
        tuners->sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR;
-       tuners->ignore_nice = 0;
+       tuners->ignore_nice_load = 0;
        tuners->powersave_bias = default_powersave_bias;
        tuners->io_is_busy = should_io_be_busy();
 
index bb838b9..9536852 100644 (file)
@@ -118,11 +118,6 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
                clk_put(cpuclk);
                return -EINVAL;
        }
-       ret = clk_set_rate(cpuclk, rate);
-       if (ret) {
-               clk_put(cpuclk);
-               return ret;
-       }
 
        /* clock table init */
        for (i = 2;
@@ -130,6 +125,12 @@ static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
             i++)
                loongson2_clockmod_table[i].frequency = (rate * i) / 8;
 
+       ret = clk_set_rate(cpuclk, rate);
+       if (ret) {
+               clk_put(cpuclk);
+               return ret;
+       }
+
        policy->cur = loongson2_cpufreq_get(policy->cpu);
 
        cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],
index fe343a0..bc580b6 100644 (file)
 #define MAX_INTERESTING 50000
 #define STDDEV_THRESH 400
 
-/* 60 * 60 > STDDEV_THRESH * INTERVALS = 400 * 8 */
-#define MAX_DEVIATION 60
-
-static DEFINE_PER_CPU(struct hrtimer, menu_hrtimer);
-static DEFINE_PER_CPU(int, hrtimer_status);
-/* menu hrtimer mode */
-enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
 
 /*
  * Concepts and ideas behind the menu governor
@@ -116,13 +109,6 @@ enum {MENU_HRTIMER_STOP, MENU_HRTIMER_REPEAT, MENU_HRTIMER_GENERAL};
  *
  */
 
-/*
- * The C-state residency is so long that is is worthwhile to exit
- * from the shallow C-state and re-enter into a deeper C-state.
- */
-static unsigned int perfect_cstate_ms __read_mostly = 30;
-module_param(perfect_cstate_ms, uint, 0000);
-
 struct menu_device {
        int             last_state_idx;
        int             needs_update;
@@ -205,52 +191,17 @@ static u64 div_round64(u64 dividend, u32 divisor)
        return div_u64(dividend + (divisor / 2), divisor);
 }
 
-/* Cancel the hrtimer if it is not triggered yet */
-void menu_hrtimer_cancel(void)
-{
-       int cpu = smp_processor_id();
-       struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
-
-       /* The timer is still not time out*/
-       if (per_cpu(hrtimer_status, cpu)) {
-               hrtimer_cancel(hrtmr);
-               per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-       }
-}
-EXPORT_SYMBOL_GPL(menu_hrtimer_cancel);
-
-/* Call back for hrtimer is triggered */
-static enum hrtimer_restart menu_hrtimer_notify(struct hrtimer *hrtimer)
-{
-       int cpu = smp_processor_id();
-       struct menu_device *data = &per_cpu(menu_devices, cpu);
-
-       /* In general case, the expected residency is much larger than
-        *  deepest C-state target residency, but prediction logic still
-        *  predicts a small predicted residency, so the prediction
-        *  history is totally broken if the timer is triggered.
-        *  So reset the correction factor.
-        */
-       if (per_cpu(hrtimer_status, cpu) == MENU_HRTIMER_GENERAL)
-               data->correction_factor[data->bucket] = RESOLUTION * DECAY;
-
-       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_STOP;
-
-       return HRTIMER_NORESTART;
-}
-
 /*
  * Try detecting repeating patterns by keeping track of the last 8
  * intervals, and checking if the standard deviation of that set
  * of points is below a threshold. If it is... then use the
  * average of these 8 points as the estimated value.
  */
-static u32 get_typical_interval(struct menu_device *data)
+static void get_typical_interval(struct menu_device *data)
 {
        int i = 0, divisor = 0;
        uint64_t max = 0, avg = 0, stddev = 0;
        int64_t thresh = LLONG_MAX; /* Discard outliers above this value. */
-       unsigned int ret = 0;
 
 again:
 
@@ -291,16 +242,13 @@ again:
        if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
                                                        || stddev <= 20) {
                data->predicted_us = avg;
-               ret = 1;
-               return ret;
+               return;
 
        } else if ((divisor * 4) > INTERVALS * 3) {
                /* Exclude the max interval */
                thresh = max - 1;
                goto again;
        }
-
-       return ret;
 }
 
 /**
@@ -315,9 +263,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        int i;
        int multiplier;
        struct timespec t;
-       int repeat = 0, low_predicted = 0;
-       int cpu = smp_processor_id();
-       struct hrtimer *hrtmr = &per_cpu(menu_hrtimer, cpu);
 
        if (data->needs_update) {
                menu_update(drv, dev);
@@ -352,7 +297,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
        data->predicted_us = div_round64(data->expected_us * data->correction_factor[data->bucket],
                                         RESOLUTION * DECAY);
 
-       repeat = get_typical_interval(data);
+       get_typical_interval(data);
 
        /*
         * We want to default to C1 (hlt), not to busy polling
@@ -373,10 +318,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
 
                if (s->disabled || su->disable)
                        continue;
-               if (s->target_residency > data->predicted_us) {
-                       low_predicted = 1;
+               if (s->target_residency > data->predicted_us)
                        continue;
-               }
                if (s->exit_latency > latency_req)
                        continue;
                if (s->exit_latency * multiplier > data->predicted_us)
@@ -386,44 +329,6 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
                data->exit_us = s->exit_latency;
        }
 
-       /* not deepest C-state chosen for low predicted residency */
-       if (low_predicted) {
-               unsigned int timer_us = 0;
-               unsigned int perfect_us = 0;
-
-               /*
-                * Set a timer to detect whether this sleep is much
-                * longer than repeat mode predicted.  If the timer
-                * triggers, the code will evaluate whether to put
-                * the CPU into a deeper C-state.
-                * The timer is cancelled on CPU wakeup.
-                */
-               timer_us = 2 * (data->predicted_us + MAX_DEVIATION);
-
-               perfect_us = perfect_cstate_ms * 1000;
-
-               if (repeat && (4 * timer_us < data->expected_us)) {
-                       RCU_NONIDLE(hrtimer_start(hrtmr,
-                               ns_to_ktime(1000 * timer_us),
-                               HRTIMER_MODE_REL_PINNED));
-                       /* In repeat case, menu hrtimer is started */
-                       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_REPEAT;
-               } else if (perfect_us < data->expected_us) {
-                       /*
-                        * The next timer is long. This could be because
-                        * we did not make a useful prediction.
-                        * In that case, it makes sense to re-enter
-                        * into a deeper C-state after some time.
-                        */
-                       RCU_NONIDLE(hrtimer_start(hrtmr,
-                               ns_to_ktime(1000 * timer_us),
-                               HRTIMER_MODE_REL_PINNED));
-                       /* In general case, menu hrtimer is started */
-                       per_cpu(hrtimer_status, cpu) = MENU_HRTIMER_GENERAL;
-               }
-
-       }
-
        return data->last_state_idx;
 }
 
@@ -514,9 +419,6 @@ static int menu_enable_device(struct cpuidle_driver *drv,
                                struct cpuidle_device *dev)
 {
        struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
-       struct hrtimer *t = &per_cpu(menu_hrtimer, dev->cpu);
-       hrtimer_init(t, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       t->function = menu_hrtimer_notify;
 
        memset(data, 0, sizeof(struct menu_device));
 
index ce3dc3e..0bbdea5 100644 (file)
@@ -867,6 +867,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
 
        if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
                dev_err(&pdev->dev, "Cannot find proper base address\n");
+               err = -ENODEV;
                goto err_disable_pdev;
        }
 
index 593827b..fa645d8 100644 (file)
@@ -2505,6 +2505,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
        /* Assign cookies to all nodes */
        while (!list_empty(&last->node)) {
                desc = list_entry(last->node.next, struct dma_pl330_desc, node);
+               if (pch->cyclic) {
+                       desc->txd.callback = last->txd.callback;
+                       desc->txd.callback_param = last->txd.callback_param;
+               }
 
                dma_cookie_assign(&desc->txd);
 
@@ -2688,45 +2692,82 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
                size_t period_len, enum dma_transfer_direction direction,
                unsigned long flags, void *context)
 {
-       struct dma_pl330_desc *desc;
+       struct dma_pl330_desc *desc = NULL, *first = NULL;
        struct dma_pl330_chan *pch = to_pchan(chan);
+       struct dma_pl330_dmac *pdmac = pch->dmac;
+       unsigned int i;
        dma_addr_t dst;
        dma_addr_t src;
 
-       desc = pl330_get_desc(pch);
-       if (!desc) {
-               dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
-                       __func__, __LINE__);
+       if (len % period_len != 0)
                return NULL;
-       }
 
-       switch (direction) {
-       case DMA_MEM_TO_DEV:
-               desc->rqcfg.src_inc = 1;
-               desc->rqcfg.dst_inc = 0;
-               desc->req.rqtype = MEMTODEV;
-               src = dma_addr;
-               dst = pch->fifo_addr;
-               break;
-       case DMA_DEV_TO_MEM:
-               desc->rqcfg.src_inc = 0;
-               desc->rqcfg.dst_inc = 1;
-               desc->req.rqtype = DEVTOMEM;
-               src = pch->fifo_addr;
-               dst = dma_addr;
-               break;
-       default:
+       if (!is_slave_direction(direction)) {
                dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
                __func__, __LINE__);
                return NULL;
        }
 
-       desc->rqcfg.brst_size = pch->burst_sz;
-       desc->rqcfg.brst_len = 1;
+       for (i = 0; i < len / period_len; i++) {
+               desc = pl330_get_desc(pch);
+               if (!desc) {
+                       dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+                               __func__, __LINE__);
 
-       pch->cyclic = true;
+                       if (!first)
+                               return NULL;
+
+                       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+                       while (!list_empty(&first->node)) {
+                               desc = list_entry(first->node.next,
+                                               struct dma_pl330_desc, node);
+                               list_move_tail(&desc->node, &pdmac->desc_pool);
+                       }
+
+                       list_move_tail(&first->node, &pdmac->desc_pool);
 
-       fill_px(&desc->px, dst, src, period_len);
+                       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+                       return NULL;
+               }
+
+               switch (direction) {
+               case DMA_MEM_TO_DEV:
+                       desc->rqcfg.src_inc = 1;
+                       desc->rqcfg.dst_inc = 0;
+                       desc->req.rqtype = MEMTODEV;
+                       src = dma_addr;
+                       dst = pch->fifo_addr;
+                       break;
+               case DMA_DEV_TO_MEM:
+                       desc->rqcfg.src_inc = 0;
+                       desc->rqcfg.dst_inc = 1;
+                       desc->req.rqtype = DEVTOMEM;
+                       src = pch->fifo_addr;
+                       dst = dma_addr;
+                       break;
+               default:
+                       break;
+               }
+
+               desc->rqcfg.brst_size = pch->burst_sz;
+               desc->rqcfg.brst_len = 1;
+               fill_px(&desc->px, dst, src, period_len);
+
+               if (!first)
+                       first = desc;
+               else
+                       list_add_tail(&desc->node, &first->node);
+
+               dma_addr += period_len;
+       }
+
+       if (!desc)
+               return NULL;
+
+       pch->cyclic = true;
+       desc->txd.flags = flags;
 
        return &desc->txd;
 }
index b67f45f..5039fbc 100644 (file)
@@ -400,8 +400,8 @@ static size_t sh_dmae_get_partial(struct shdma_chan *schan,
                                                    shdma_chan);
        struct sh_dmae_desc *sh_desc = container_of(sdesc,
                                        struct sh_dmae_desc, shdma_desc);
-       return (sh_desc->hw.tcr - sh_dmae_readl(sh_chan, TCR)) <<
-               sh_chan->xmit_shift;
+       return sh_desc->hw.tcr -
+               (sh_dmae_readl(sh_chan, TCR) << sh_chan->xmit_shift);
 }
 
 /* Called from error IRQ or NMI */
index 7ef316f..ac1b43a 100644 (file)
@@ -54,6 +54,7 @@
 #define FW_CDEV_KERNEL_VERSION                 5
 #define FW_CDEV_VERSION_EVENT_REQUEST2         4
 #define FW_CDEV_VERSION_ALLOCATE_REGION_END    4
+#define FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW        5
 
 struct client {
        u32 version;
@@ -1005,6 +1006,8 @@ static int ioctl_create_iso_context(struct client *client, union ioctl_arg *arg)
                        a->channel, a->speed, a->header_size, cb, client);
        if (IS_ERR(context))
                return PTR_ERR(context);
+       if (client->version < FW_CDEV_VERSION_AUTO_FLUSH_ISO_OVERFLOW)
+               context->drop_overflow_headers = true;
 
        /* We only support one context at this time. */
        spin_lock_irq(&client->lock);
index 9e1db64..afb701e 100644 (file)
@@ -2749,8 +2749,11 @@ static void copy_iso_headers(struct iso_context *ctx, const u32 *dma_hdr)
 {
        u32 *ctx_hdr;
 
-       if (ctx->header_length + ctx->base.header_size > PAGE_SIZE)
+       if (ctx->header_length + ctx->base.header_size > PAGE_SIZE) {
+               if (ctx->base.drop_overflow_headers)
+                       return;
                flush_iso_completions(ctx);
+       }
 
        ctx_hdr = ctx->header + ctx->header_length;
        ctx->last_timestamp = (u16)le32_to_cpu((__force __le32)dma_hdr[0]);
@@ -2910,8 +2913,11 @@ static int handle_it_packet(struct context *context,
 
        sync_it_packet_for_cpu(context, d);
 
-       if (ctx->header_length + 4 > PAGE_SIZE)
+       if (ctx->header_length + 4 > PAGE_SIZE) {
+               if (ctx->base.drop_overflow_headers)
+                       return 1;
                flush_iso_completions(ctx);
+       }
 
        ctx_hdr = ctx->header + ctx->header_length;
        ctx->last_timestamp = le16_to_cpu(last->res_count);
index eb760a2..232fa8f 100644 (file)
@@ -419,6 +419,13 @@ static void __init dmi_format_ids(char *buf, size_t len)
                            dmi_get_system_info(DMI_BIOS_DATE));
 }
 
+/*
+ * Check for DMI/SMBIOS headers in the system firmware image.  Any
+ * SMBIOS header must start 16 bytes before the DMI header, so take a
+ * 32 byte buffer and check for DMI at offset 16 and SMBIOS at offset
+ * 0.  If the DMI header is present, set dmi_ver accordingly (SMBIOS
+ * takes precedence) and return 0.  Otherwise return 1.
+ */
 static int __init dmi_present(const u8 *buf)
 {
        int smbios_ver;
@@ -506,6 +513,13 @@ void __init dmi_scan_machine(void)
                if (p == NULL)
                        goto error;
 
+               /*
+                * Iterate over all possible DMI header addresses q.
+                * Maintain the 32 bytes around q in buf.  On the
+                * first iteration, substitute zero for the
+                * out-of-range bytes so there is no chance of falsely
+                * detecting an SMBIOS header.
+                */
                memset(buf, 0, 16);
                for (q = p; q < p + 0x10000; q += 16) {
                        memcpy_fromio(buf + 16, q, 16);
index e3ceaac..73b7396 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
+#include <linux/err.h>
 
 #include <mach/msm_gpiomux.h>
 
index c57244e..dfeb3a3 100644 (file)
@@ -1037,18 +1037,6 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start,
                               IRQ_NOREQUEST | IRQ_NOPROBE, 0);
 }
 
-#if defined(CONFIG_OF_GPIO)
-static inline bool omap_gpio_chip_boot_dt(struct gpio_chip *chip)
-{
-       return chip->of_node != NULL;
-}
-#else
-static inline bool omap_gpio_chip_boot_dt(struct gpio_chip *chip)
-{
-       return false;
-}
-#endif
-
 static void omap_gpio_chip_init(struct gpio_bank *bank)
 {
        int j;
@@ -1080,68 +1068,24 @@ static void omap_gpio_chip_init(struct gpio_bank *bank)
 
        gpiochip_add(&bank->chip);
 
-       /*
-        * REVISIT these explicit calls to irq_create_mapping()
-        * to do the GPIO to IRQ domain mapping for each GPIO in
-        * the bank can be removed once all OMAP platforms have
-        * been migrated to Device Tree boot only.
-        * Since in DT boot irq_create_mapping() is called from
-        * irq_create_of_mapping() only for the GPIO lines that
-        * are used as interrupts.
-        */
-       if (!omap_gpio_chip_boot_dt(&bank->chip))
-               for (j = 0; j < bank->width; j++)
-                       irq_create_mapping(bank->domain, j);
+       for (j = 0; j < bank->width; j++) {
+               int irq = irq_create_mapping(bank->domain, j);
+               irq_set_lockdep_class(irq, &gpio_lock_class);
+               irq_set_chip_data(irq, bank);
+               if (bank->is_mpuio) {
+                       omap_mpuio_alloc_gc(bank, irq, bank->width);
+               } else {
+                       irq_set_chip_and_handler(irq, &gpio_irq_chip,
+                                                handle_simple_irq);
+                       set_irq_flags(irq, IRQF_VALID);
+               }
+       }
        irq_set_chained_handler(bank->irq, gpio_irq_handler);
        irq_set_handler_data(bank->irq, bank);
 }
 
 static const struct of_device_id omap_gpio_match[];
 
-static int omap_gpio_irq_map(struct irq_domain *d, unsigned int virq,
-                            irq_hw_number_t hwirq)
-{
-       struct gpio_bank *bank = d->host_data;
-       int gpio;
-       int ret;
-
-       if (!bank)
-               return -EINVAL;
-
-       irq_set_lockdep_class(virq, &gpio_lock_class);
-       irq_set_chip_data(virq, bank);
-       if (bank->is_mpuio) {
-               omap_mpuio_alloc_gc(bank, virq, bank->width);
-       } else {
-               irq_set_chip_and_handler(virq, &gpio_irq_chip,
-                                        handle_simple_irq);
-               set_irq_flags(virq, IRQF_VALID);
-       }
-
-       /*
-        * REVISIT most GPIO IRQ chip drivers need to call
-        * gpio_request() before a GPIO line can be used as an
-        * IRQ. Ideally this should be handled by the IRQ core
-        * but until then this has to be done on a per driver
-        * basis. Remove this once this is managed by the core.
-        */
-       if (omap_gpio_chip_boot_dt(&bank->chip)) {
-               gpio = irq_to_gpio(bank, hwirq);
-               ret = gpio_request_one(gpio, GPIOF_IN, NULL);
-               if (ret) {
-                       dev_err(bank->dev, "Could not request GPIO%d\n", gpio);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static struct irq_domain_ops omap_gpio_irq_ops = {
-       .xlate  = irq_domain_xlate_onetwocell,
-       .map    = omap_gpio_irq_map,
-};
-
 static int omap_gpio_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -1207,10 +1151,10 @@ static int omap_gpio_probe(struct platform_device *pdev)
        }
 
        bank->domain = irq_domain_add_legacy(node, bank->width, irq_base,
-                                            0, &omap_gpio_irq_ops, bank);
+                                            0, &irq_domain_simple_ops, NULL);
 #else
        bank->domain = irq_domain_add_linear(node, bank->width,
-                                            &omap_gpio_irq_ops, bank);
+                                            &irq_domain_simple_ops, NULL);
 #endif
        if (!bank->domain) {
                dev_err(dev, "Couldn't register an IRQ domain\n");
index 98d6708..6e8887f 100644 (file)
@@ -323,6 +323,7 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
 
        astbo->gem.driver_private = NULL;
        astbo->bo.bdev = &ast->ttm.bdev;
+       astbo->bo.bdev->dev_mapping = dev->dev_mapping;
 
        ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
index 0047012..69fd8f1 100644 (file)
@@ -328,6 +328,7 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
 
        cirrusbo->gem.driver_private = NULL;
        cirrusbo->bo.bdev = &cirrus->ttm.bdev;
+       cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping;
 
        cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
index 8bcce78..f92da0a 100644 (file)
@@ -708,7 +708,10 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
        /* Subtract time delta from raw timestamp to get final
         * vblank_time timestamp for end of vblank.
         */
-       etime = ktime_sub_ns(etime, delta_ns);
+       if (delta_ns < 0)
+               etime = ktime_add_ns(etime, -delta_ns);
+       else
+               etime = ktime_sub_ns(etime, delta_ns);
        *vblank_time = ktime_to_timeval(etime);
 
        DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
index 95c75ed..30ef41b 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 
 #include "exynos_drm_drv.h"
index 61b094f..6e047bd 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/syscon.h>
 #include <linux/regmap.h>
index 3e106be..1c263da 100644 (file)
@@ -14,7 +14,6 @@
 #include <drm/drmP.h>
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/of_device.h>
@@ -130,7 +129,6 @@ static const struct of_device_id fimd_driver_dt_match[] = {
          .data = &exynos5_fimd_driver_data },
        {},
 };
-MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
 #endif
 
 static inline struct fimd_driver_data *drm_fimd_get_driver_data(
@@ -1082,7 +1080,6 @@ static struct platform_device_id fimd_driver_ids[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(platform, fimd_driver_ids);
 
 static const struct dev_pm_ops fimd_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
index 42a5a54..eddea49 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
@@ -806,9 +805,20 @@ static void g2d_dma_start(struct g2d_data *g2d,
        struct g2d_cmdlist_node *node =
                                list_first_entry(&runqueue_node->run_cmdlist,
                                                struct g2d_cmdlist_node, list);
+       int ret;
+
+       ret = pm_runtime_get_sync(g2d->dev);
+       if (ret < 0) {
+               dev_warn(g2d->dev, "failed pm power on.\n");
+               return;
+       }
 
-       pm_runtime_get_sync(g2d->dev);
-       clk_enable(g2d->gate_clk);
+       ret = clk_prepare_enable(g2d->gate_clk);
+       if (ret < 0) {
+               dev_warn(g2d->dev, "failed to enable clock.\n");
+               pm_runtime_put_sync(g2d->dev);
+               return;
+       }
 
        writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
        writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
@@ -861,7 +871,7 @@ static void g2d_runqueue_worker(struct work_struct *work)
                                            runqueue_work);
 
        mutex_lock(&g2d->runqueue_mutex);
-       clk_disable(g2d->gate_clk);
+       clk_disable_unprepare(g2d->gate_clk);
        pm_runtime_put_sync(g2d->dev);
 
        complete(&g2d->runqueue_node->complete);
@@ -1521,7 +1531,6 @@ static const struct of_device_id exynos_g2d_match[] = {
        { .compatible = "samsung,exynos5250-g2d" },
        {},
 };
-MODULE_DEVICE_TABLE(of, exynos_g2d_match);
 #endif
 
 struct platform_driver g2d_driver = {
index 472e3b2..90b8a1a 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/pm_runtime.h>
index aaa550d..8d3bc01 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/wait.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
index b1ef8e7..d2b6ab4 100644 (file)
@@ -12,7 +12,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/types.h>
 #include <linux/clk.h>
@@ -342,10 +341,10 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
                 */
                ippdrv = ipp_find_obj(&ctx->ipp_idr, &ctx->ipp_lock,
                                                prop_list->ipp_id);
-               if (!ippdrv) {
+               if (IS_ERR(ippdrv)) {
                        DRM_ERROR("not found ipp%d driver.\n",
                                        prop_list->ipp_id);
-                       return -EINVAL;
+                       return PTR_ERR(ippdrv);
                }
 
                prop_list = ippdrv->prop_list;
@@ -970,9 +969,9 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
        /* find command node */
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                qbuf->prop_id);
-       if (!c_node) {
+       if (IS_ERR(c_node)) {
                DRM_ERROR("failed to get command node.\n");
-               return -EFAULT;
+               return PTR_ERR(c_node);
        }
 
        /* buffer control */
@@ -1106,9 +1105,9 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
 
        c_node = ipp_find_obj(&ctx->prop_idr, &ctx->prop_lock,
                cmd_ctrl->prop_id);
-       if (!c_node) {
+       if (IS_ERR(c_node)) {
                DRM_ERROR("invalid command node list.\n");
-               return -EINVAL;
+               return PTR_ERR(c_node);
        }
 
        if (!exynos_drm_ipp_check_valid(ippdrv->dev, cmd_ctrl->ctrl,
index 427640a..49669aa 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
index 41cc74d..c57c565 100644 (file)
@@ -13,7 +13,6 @@
 #include <drm/drmP.h>
 
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 
 #include <drm/exynos_drm.h>
index 62ef597..2f5c694 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index ef04255..6e320ae 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 #include "exynos_drm_drv.h"
 #include "exynos_hdmi.h"
index 42ffb71..c9a137c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index 66c6380..f466980 100644 (file)
@@ -1594,6 +1594,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        intel_detect_pch(dev);
 
        intel_irq_init(dev);
+       intel_pm_init(dev);
        intel_gt_sanitize(dev);
        intel_gt_init(dev);
 
index d2ee334..1929bff 100644 (file)
@@ -1582,6 +1582,7 @@ void i915_hangcheck_elapsed(unsigned long data);
 void i915_handle_error(struct drm_device *dev, bool wedged);
 
 extern void intel_irq_init(struct drm_device *dev);
+extern void intel_pm_init(struct drm_device *dev);
 extern void intel_hpd_init(struct drm_device *dev);
 extern void intel_gt_init(struct drm_device *dev);
 extern void intel_gt_sanitize(struct drm_device *dev);
index f2326fc..6f51429 100644 (file)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 
 #define PORT_HOTPLUG_STAT      (dev_priv->info->display_mmio_offset + 0x61114)
-/* HDMI/DP bits are gen4+ */
-#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 29)
+/*
+ * HDMI/DP bits are gen4+
+ *
+ * WARNING: Bspec for hpd status bits on gen4 seems to be completely confused.
+ * Please check the detailed lore in the commit message for for experimental
+ * evidence.
+ */
+#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 29)
 #define   PORTC_HOTPLUG_LIVE_STATUS               (1 << 28)
-#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 27)
+#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 27)
 #define   PORTD_HOTPLUG_INT_STATUS             (3 << 21)
 #define   PORTC_HOTPLUG_INT_STATUS             (3 << 19)
 #define   PORTB_HOTPLUG_INT_STATUS             (3 << 17)
index 5fb3058..e38b457 100644 (file)
@@ -8269,9 +8269,11 @@ check_crtc_state(struct drm_device *dev)
 
                list_for_each_entry(encoder, &dev->mode_config.encoder_list,
                                    base.head) {
+                       enum pipe pipe;
                        if (encoder->base.crtc != &crtc->base)
                                continue;
-                       if (encoder->get_config)
+                       if (encoder->get_config &&
+                           encoder->get_hw_state(encoder, &pipe))
                                encoder->get_config(encoder, &pipe_config);
                }
 
index 67e2c1f..5950888 100644 (file)
@@ -497,8 +497,11 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level, u32 max)
                goto out;
        }
 
-       /* scale to hardware */
-       level = level * freq / max;
+       /* scale to hardware, but be careful to not overflow */
+       if (freq < max)
+               level = level * freq / max;
+       else
+               level = freq / max * level;
 
        dev_priv->backlight.level = level;
        if (dev_priv->backlight.device)
@@ -515,6 +518,17 @@ void intel_panel_disable_backlight(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
+       /*
+        * Do not disable backlight on the vgaswitcheroo path. When switching
+        * away from i915, the other client may depend on i915 to handle the
+        * backlight. This will leave the backlight on unnecessarily when
+        * another client is not activated.
+        */
+       if (dev->switch_power_state == DRM_SWITCH_POWER_CHANGING) {
+               DRM_DEBUG_DRIVER("Skipping backlight disable on vga switch\n");
+               return;
+       }
+
        spin_lock_irqsave(&dev_priv->backlight.lock, flags);
 
        dev_priv->backlight.enabled = false;
index 51a2a60..b0e4a0b 100644 (file)
@@ -5063,8 +5063,26 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable)
                }
        } else {
                if (enable_requested) {
+                       unsigned long irqflags;
+                       enum pipe p;
+
                        I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
+                       POSTING_READ(HSW_PWR_WELL_DRIVER);
                        DRM_DEBUG_KMS("Requesting to disable the power well\n");
+
+                       /*
+                        * After this, the registers on the pipes that are part
+                        * of the power well will become zero, so we have to
+                        * adjust our counters according to that.
+                        *
+                        * FIXME: Should we do this in general in
+                        * drm_vblank_post_modeset?
+                        */
+                       spin_lock_irqsave(&dev->vbl_lock, irqflags);
+                       for_each_pipe(p)
+                               if (p != PIPE_A)
+                                       dev->last_vblank[p] = 0;
+                       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
                }
        }
 }
@@ -5536,6 +5554,12 @@ void intel_gt_init(struct drm_device *dev)
                dev_priv->gt.force_wake_get = __gen6_gt_force_wake_get;
                dev_priv->gt.force_wake_put = __gen6_gt_force_wake_put;
        }
+}
+
+void intel_pm_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
                          intel_gen6_powersave_work);
 }
index 251784a..503a414 100644 (file)
@@ -29,6 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
        struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = dev->dev_private;
+       struct drm_framebuffer *fb = crtc->fb;
        int i;
 
        if (!crtc->enabled)
@@ -36,6 +37,28 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
 
        WREG8(DAC_INDEX + MGA1064_INDEX, 0);
 
+       if (fb && fb->bits_per_pixel == 16) {
+               int inc = (fb->depth == 15) ? 8 : 4;
+               u8 r, b;
+               for (i = 0; i < MGAG200_LUT_SIZE; i += inc) {
+                       if (fb->depth == 16) {
+                               if (i > (MGAG200_LUT_SIZE >> 1)) {
+                                       r = b = 0;
+                               } else {
+                                       r = mga_crtc->lut_r[i << 1];
+                                       b = mga_crtc->lut_b[i << 1];
+                               }
+                       } else {
+                               r = mga_crtc->lut_r[i];
+                               b = mga_crtc->lut_b[i];
+                       }
+                       /* VGA registers */
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, r);
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_g[i]);
+                       WREG8(DAC_INDEX + MGA1064_COL_PAL, b);
+               }
+               return;
+       }
        for (i = 0; i < MGAG200_LUT_SIZE; i++) {
                /* VGA registers */
                WREG8(DAC_INDEX + MGA1064_COL_PAL, mga_crtc->lut_r[i]);
@@ -877,7 +900,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
 
        pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
        if (crtc->fb->bits_per_pixel == 24)
-               pitch = pitch >> (4 - bppshift);
+               pitch = (pitch * 3) >> (4 - bppshift);
        else
                pitch = pitch >> (4 - bppshift);
 
@@ -1251,6 +1274,24 @@ static void mga_crtc_destroy(struct drm_crtc *crtc)
        kfree(mga_crtc);
 }
 
+static void mga_crtc_disable(struct drm_crtc *crtc)
+{
+       int ret;
+       DRM_DEBUG_KMS("\n");
+       mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+       if (crtc->fb) {
+               struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
+               struct drm_gem_object *obj = mga_fb->obj;
+               struct mgag200_bo *bo = gem_to_mga_bo(obj);
+               ret = mgag200_bo_reserve(bo, false);
+               if (ret)
+                       return;
+               mgag200_bo_push_sysram(bo);
+               mgag200_bo_unreserve(bo);
+       }
+       crtc->fb = NULL;
+}
+
 /* These provide the minimum set of functions required to handle a CRTC */
 static const struct drm_crtc_funcs mga_crtc_funcs = {
        .cursor_set = mga_crtc_cursor_set,
@@ -1261,6 +1302,7 @@ static const struct drm_crtc_funcs mga_crtc_funcs = {
 };
 
 static const struct drm_crtc_helper_funcs mga_helper_funcs = {
+       .disable = mga_crtc_disable,
        .dpms = mga_crtc_dpms,
        .mode_fixup = mga_crtc_mode_fixup,
        .mode_set = mga_crtc_mode_set,
@@ -1581,6 +1623,8 @@ static struct drm_connector *mga_vga_init(struct drm_device *dev)
 
        drm_connector_helper_add(connector, &mga_vga_connector_helper_funcs);
 
+       drm_sysfs_connector_add(connector);
+
        mga_connector->i2c = mgag200_i2c_create(dev);
        if (!mga_connector->i2c)
                DRM_ERROR("failed to add ddc bus\n");
index 3acb2b0..d70e4a9 100644 (file)
@@ -323,6 +323,7 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align,
 
        mgabo->gem.driver_private = NULL;
        mgabo->bo.bdev = &mdev->ttm.bdev;
+       mgabo->bo.bdev->dev_mapping = dev->dev_mapping;
 
        mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
@@ -353,6 +354,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr)
                bo->pin_count++;
                if (gpu_addr)
                        *gpu_addr = mgag200_bo_gpu_offset(bo);
+               return 0;
        }
 
        mgag200_ttm_placement(bo, pl_flag);
index 373dbcc..a19e7d7 100644 (file)
@@ -36,6 +36,8 @@ nva3_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x61c440 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x61c440 + soff, (i << 8));
                nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index dc57e24..7176393 100644 (file)
@@ -41,6 +41,8 @@ nvd0_hda_eld(struct nv50_disp_priv *priv, int or, u8 *data, u32 size)
        if (data && data[0]) {
                for (i = 0; i < size; i++)
                        nv_wr32(priv, 0x10ec00 + soff, (i << 8) | data[i]);
+               for (; i < 0x60; i++)
+                       nv_wr32(priv, 0x10ec00 + soff, (i << 8));
                nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
        } else
        if (data) {
index ab1e918..526b752 100644 (file)
@@ -47,14 +47,8 @@ int
 nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
 {
        struct nv50_disp_priv *priv = (void *)object->engine;
-       struct nouveau_bios *bios = nouveau_bios(priv);
-       const u16 type = (mthd & NV50_DISP_SOR_MTHD_TYPE) >> 12;
        const u8  head = (mthd & NV50_DISP_SOR_MTHD_HEAD) >> 3;
-       const u8  link = (mthd & NV50_DISP_SOR_MTHD_LINK) >> 2;
        const u8    or = (mthd & NV50_DISP_SOR_MTHD_OR);
-       const u16 mask = (0x0100 << head) | (0x0040 << link) | (0x0001 << or);
-       struct dcb_output outp;
-       u8  ver, hdr;
        u32 data;
        int ret = -EINVAL;
 
@@ -62,8 +56,6 @@ nv50_sor_mthd(struct nouveau_object *object, u32 mthd, void *args, u32 size)
                return -EINVAL;
        data = *(u32 *)args;
 
-       if (type && !dcb_outp_match(bios, type, mask, &ver, &hdr, &outp))
-               return -ENODEV;
 
        switch (mthd & ~0x3f) {
        case NV50_DISP_SOR_PWR:
index 49ecbb8..c190043 100644 (file)
@@ -265,8 +265,8 @@ nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 int
 nv31_mpeg_init(struct nouveau_object *object)
 {
-       struct nouveau_engine *engine = nv_engine(object->engine);
-       struct nv31_mpeg_priv *priv = (void *)engine;
+       struct nouveau_engine *engine = nv_engine(object);
+       struct nv31_mpeg_priv *priv = (void *)object;
        struct nouveau_fb *pfb = nouveau_fb(object);
        int ret, i;
 
@@ -284,7 +284,10 @@ nv31_mpeg_init(struct nouveau_object *object)
        /* PMPEG init */
        nv_wr32(priv, 0x00b32c, 0x00000000);
        nv_wr32(priv, 0x00b314, 0x00000100);
-       nv_wr32(priv, 0x00b220, nv44_graph_class(priv) ? 0x00000044 : 0x00000031);
+       if (nv_device(priv)->chipset >= 0x40 && nv44_graph_class(priv))
+               nv_wr32(priv, 0x00b220, 0x00000044);
+       else
+               nv_wr32(priv, 0x00b220, 0x00000031);
        nv_wr32(priv, 0x00b300, 0x02001ec1);
        nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
 
index f7c581a..dd61960 100644 (file)
@@ -61,6 +61,7 @@ nv40_mpeg_context_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
+       nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
        return 0;
 }
 
index 0639bc5..5f6ede7 100644 (file)
@@ -118,7 +118,13 @@ _nouveau_xtensa_init(struct nouveau_object *object)
                        return ret;
                }
 
-               ret = nouveau_gpuobj_new(object, NULL, fw->size, 0x1000, 0,
+               if (fw->size > 0x40000) {
+                       nv_warn(xtensa, "firmware %s too large\n", name);
+                       release_firmware(fw);
+                       return -EINVAL;
+               }
+
+               ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
                                         &xtensa->gpu_fw);
                if (ret) {
                        release_firmware(fw);
index f2e87b1..fcf57fa 100644 (file)
@@ -55,7 +55,7 @@ struct nouveau_vma {
 struct nouveau_vm {
        struct nouveau_vmmgr *vmm;
        struct nouveau_mm mm;
-       int refcount;
+       struct kref refcount;
 
        struct list_head pgd_list;
        atomic_t engref[NVDEV_SUBDEV_NR];
index 6c974dd..db9d6dd 100644 (file)
@@ -81,7 +81,7 @@ void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
 void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
                       u32 pitch, u32 flags, struct nouveau_fb_tile *);
 
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
+void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
 extern int nv50_fb_memtype[0x80];
 
 #endif
index af5aa7e..903baff 100644 (file)
 #include "priv.h"
 
 void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
 {
        struct nouveau_mm_node *this;
-       struct nouveau_mem *mem;
 
-       mem = *pmem;
-       *pmem = NULL;
-       if (unlikely(mem == NULL))
-               return;
-
-       mutex_lock(&pfb->base.mutex);
        while (!list_empty(&mem->regions)) {
                this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
 
@@ -46,6 +39,19 @@ nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
        }
 
        nouveau_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
+{
+       struct nouveau_mem *mem = *pmem;
+
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
+
+       mutex_lock(&pfb->base.mutex);
+       __nv50_ram_put(pfb, mem);
        mutex_unlock(&pfb->base.mutex);
 
        kfree(mem);
index 9c3634a..cf97c4d 100644 (file)
@@ -33,11 +33,19 @@ void
 nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
 {
        struct nouveau_ltcg *ltcg = nouveau_ltcg(pfb);
+       struct nouveau_mem *mem = *pmem;
 
-       if ((*pmem)->tag)
-               ltcg->tags_free(ltcg, &(*pmem)->tag);
+       *pmem = NULL;
+       if (unlikely(mem == NULL))
+               return;
 
-       nv50_ram_put(pfb, pmem);
+       mutex_lock(&pfb->base.mutex);
+       if (mem->tag)
+               ltcg->tags_free(ltcg, &mem->tag);
+       __nv50_ram_put(pfb, mem);
+       mutex_unlock(&pfb->base.mutex);
+
+       kfree(mem);
 }
 
 int
index bf489dc..c4c1d41 100644 (file)
@@ -103,7 +103,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        int i;
 
        intr0 = nv_rd32(priv, 0xe054) & nv_rd32(priv, 0xe050);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                intr1 = nv_rd32(priv, 0xe074) & nv_rd32(priv, 0xe070);
 
        hi = (intr0 & 0x0000ffff) | (intr1 << 16);
@@ -115,7 +115,7 @@ nv50_gpio_intr(struct nouveau_subdev *subdev)
        }
 
        nv_wr32(priv, 0xe054, intr0);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe074, intr1);
 }
 
@@ -146,7 +146,7 @@ nv50_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int ret;
 
        ret = nouveau_gpio_create(parent, engine, oclass,
-                                 nv_device(parent)->chipset >= 0x90 ? 32 : 16,
+                                 nv_device(parent)->chipset > 0x92 ? 32 : 16,
                                  &priv);
        *pobject = nv_object(priv);
        if (ret)
@@ -182,7 +182,7 @@ nv50_gpio_init(struct nouveau_object *object)
        /* disable, and ack any pending gpio interrupts */
        nv_wr32(priv, 0xe050, 0x00000000);
        nv_wr32(priv, 0xe054, 0xffffffff);
-       if (nv_device(priv)->chipset >= 0x90) {
+       if (nv_device(priv)->chipset > 0x92) {
                nv_wr32(priv, 0xe070, 0x00000000);
                nv_wr32(priv, 0xe074, 0xffffffff);
        }
@@ -195,7 +195,7 @@ nv50_gpio_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv50_gpio_priv *priv = (void *)object;
        nv_wr32(priv, 0xe050, 0x00000000);
-       if (nv_device(priv)->chipset >= 0x90)
+       if (nv_device(priv)->chipset > 0x92)
                nv_wr32(priv, 0xe070, 0x00000000);
        return nouveau_gpio_fini(&priv->base, suspend);
 }
index 0cb322a..f25fc5f 100644 (file)
@@ -41,7 +41,7 @@ nv50_mc_intr[] = {
        { 0x04000000, NVDEV_ENGINE_DISP },
        { 0x10000000, NVDEV_SUBDEV_BUS },
        { 0x80000000, NVDEV_ENGINE_SW },
-       { 0x0000d101, NVDEV_SUBDEV_FB },
+       { 0x0002d101, NVDEV_SUBDEV_FB },
        {},
 };
 
index 67fcb6c..ef3133e 100644 (file)
@@ -361,7 +361,7 @@ nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
 
        INIT_LIST_HEAD(&vm->pgd_list);
        vm->vmm = vmm;
-       vm->refcount = 1;
+       kref_init(&vm->refcount);
        vm->fpde = offset >> (vmm->pgt_bits + 12);
        vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
 
@@ -441,8 +441,9 @@ nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
 }
 
 static void
-nouveau_vm_del(struct nouveau_vm *vm)
+nouveau_vm_del(struct kref *kref)
 {
+       struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
        struct nouveau_vm_pgd *vpgd, *tmp;
 
        list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
@@ -458,27 +459,19 @@ int
 nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
               struct nouveau_gpuobj *pgd)
 {
-       struct nouveau_vm *vm;
-       int ret;
-
-       vm = ref;
-       if (vm) {
-               ret = nouveau_vm_link(vm, pgd);
+       if (ref) {
+               int ret = nouveau_vm_link(ref, pgd);
                if (ret)
                        return ret;
 
-               vm->refcount++;
+               kref_get(&ref->refcount);
        }
 
-       vm = *ptr;
-       *ptr = ref;
-
-       if (vm) {
-               nouveau_vm_unlink(vm, pgd);
-
-               if (--vm->refcount == 0)
-                       nouveau_vm_del(vm);
+       if (*ptr) {
+               nouveau_vm_unlink(*ptr, pgd);
+               kref_put(&(*ptr)->refcount, nouveau_vm_del);
        }
 
+       *ptr = ref;
        return 0;
 }
index 4e7ee5f..af20fba 100644 (file)
@@ -198,7 +198,12 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
        size_t acc_size;
        int ret;
        int type = ttm_bo_type_device;
-       int max_size = INT_MAX & ~((1 << drm->client.base.vm->vmm->lpg_shift) - 1);
+       int lpg_shift = 12;
+       int max_size;
+
+       if (drm->client.base.vm)
+               lpg_shift = drm->client.base.vm->vmm->lpg_shift;
+       max_size = INT_MAX & ~((1 << lpg_shift) - 1);
 
        if (size <= 0 || size > max_size) {
                nv_warn(drm, "skipped size %x\n", (u32)size);
index 4c1bc06..8f6d63d 100644 (file)
@@ -398,7 +398,8 @@ void
 nouveau_fbcon_output_poll_changed(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       drm_fb_helper_hotplug_event(&drm->fbcon->helper);
+       if (drm->fbcon)
+               drm_fb_helper_hotplug_event(&drm->fbcon->helper);
 }
 
 static int
index 8e47a9b..22aa996 100644 (file)
@@ -76,7 +76,7 @@ nv17_fence_context_new(struct nouveau_channel *chan)
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
        u32 start = mem->start * PAGE_SIZE;
-       u32 limit = mem->start + mem->size - 1;
+       u32 limit = start + mem->size - 1;
        int ret = 0;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
index f9701e5..0ee3638 100644 (file)
@@ -39,6 +39,8 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        struct nv10_fence_chan *fctx;
        struct ttm_mem_reg *mem = &priv->bo->bo.mem;
        struct nouveau_object *object;
+       u32 start = mem->start * PAGE_SIZE;
+       u32 limit = start + mem->size - 1;
        int ret, i;
 
        fctx = chan->fence = kzalloc(sizeof(*fctx), GFP_KERNEL);
@@ -51,26 +53,28 @@ nv50_fence_context_new(struct nouveau_channel *chan)
        fctx->base.sync = nv17_fence_sync;
 
        ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
-                                NvSema, 0x0002,
+                                NvSema, 0x003d,
                                 &(struct nv_dma_class) {
                                        .flags = NV_DMA_TARGET_VRAM |
                                                 NV_DMA_ACCESS_RDWR,
-                                       .start = mem->start * PAGE_SIZE,
-                                       .limit = mem->size - 1,
+                                       .start = start,
+                                       .limit = limit,
                                 }, sizeof(struct nv_dma_class),
                                 &object);
 
        /* dma objects for display sync channel semaphore blocks */
        for (i = 0; !ret && i < dev->mode_config.num_crtc; i++) {
                struct nouveau_bo *bo = nv50_display_crtc_sema(dev, i);
+               u32 start = bo->bo.mem.start * PAGE_SIZE;
+               u32 limit = start + bo->bo.mem.size - 1;
 
                ret = nouveau_object_new(nv_object(chan->cli), chan->handle,
                                         NvEvoSema0 + i, 0x003d,
                                         &(struct nv_dma_class) {
                                                .flags = NV_DMA_TARGET_VRAM |
                                                         NV_DMA_ACCESS_RDWR,
-                                               .start = bo->bo.offset,
-                                               .limit = bo->bo.offset + 0xfff,
+                                               .start = start,
+                                               .limit = limit,
                                         }, sizeof(struct nv_dma_class),
                                         &object);
        }
index fb441a7..15da7ef 100644 (file)
@@ -1222,12 +1222,17 @@ int atom_execute_table(struct atom_context *ctx, int index, uint32_t * params)
        int r;
 
        mutex_lock(&ctx->mutex);
+       /* reset data block */
+       ctx->data_block = 0;
        /* reset reg block */
        ctx->reg_block = 0;
        /* reset fb window */
        ctx->fb_base = 0;
        /* reset io mode */
        ctx->io_mode = ATOM_IO_MM;
+       /* reset divmul */
+       ctx->divmul[0] = 0;
+       ctx->divmul[1] = 0;
        r = atom_execute_table_locked(ctx, index, params);
        mutex_unlock(&ctx->mutex);
        return r;
index 0bfd55e..9953e1f 100644 (file)
@@ -2548,9 +2548,6 @@ int btc_dpm_init(struct radeon_device *rdev)
 {
        struct rv7xx_power_info *pi;
        struct evergreen_power_info *eg_pi;
-       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
-       u16 data_offset, size;
-       u8 frev, crev;
        struct atom_clock_dividers dividers;
        int ret;
 
@@ -2633,16 +2630,7 @@ int btc_dpm_init(struct radeon_device *rdev)
        eg_pi->vddci_control =
                radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
 
-       if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
-                                   &frev, &crev, &data_offset)) {
-               pi->sclk_ss = true;
-               pi->mclk_ss = true;
-               pi->dynamic_ss = true;
-       } else {
-               pi->sclk_ss = false;
-               pi->mclk_ss = false;
-               pi->dynamic_ss = true;
-       }
+       rv770_get_engine_memory_ss(rdev);
 
        pi->asi = RV770_ASI_DFLT;
        pi->pasi = CYPRESS_HASI_DFLT;
@@ -2659,8 +2647,7 @@ int btc_dpm_init(struct radeon_device *rdev)
 
        pi->dynamic_pcie_gen2 = true;
 
-       if (pi->gfx_clock_gating &&
-           (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+       if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
                pi->thermal_protection = true;
        else
                pi->thermal_protection = false;
index 6dacec4..8928bd1 100644 (file)
@@ -2587,9 +2587,11 @@ u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
        if (rdev->wb.enabled) {
                rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
        } else {
+               mutex_lock(&rdev->srbm_mutex);
                cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
                rptr = RREG32(CP_HQD_PQ_RPTR);
                cik_srbm_select(rdev, 0, 0, 0, 0);
+               mutex_unlock(&rdev->srbm_mutex);
        }
        rptr = (rptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
 
@@ -2604,9 +2606,11 @@ u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
        if (rdev->wb.enabled) {
                wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
        } else {
+               mutex_lock(&rdev->srbm_mutex);
                cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
                wptr = RREG32(CP_HQD_PQ_WPTR);
                cik_srbm_select(rdev, 0, 0, 0, 0);
+               mutex_unlock(&rdev->srbm_mutex);
        }
        wptr = (wptr & ring->ptr_reg_mask) >> ring->ptr_reg_shift;
 
@@ -2897,6 +2901,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
        WREG32(CP_CPF_DEBUG, tmp);
 
        /* init the pipes */
+       mutex_lock(&rdev->srbm_mutex);
        for (i = 0; i < (rdev->mec.num_pipe * rdev->mec.num_mec); i++) {
                int me = (i < 4) ? 1 : 2;
                int pipe = (i < 4) ? i : (i - 4);
@@ -2919,6 +2924,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                WREG32(CP_HPD_EOP_CONTROL, tmp);
        }
        cik_srbm_select(rdev, 0, 0, 0, 0);
+       mutex_unlock(&rdev->srbm_mutex);
 
        /* init the queues.  Just two for now. */
        for (i = 0; i < 2; i++) {
@@ -2972,6 +2978,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                mqd->static_thread_mgmt23[0] = 0xffffffff;
                mqd->static_thread_mgmt23[1] = 0xffffffff;
 
+               mutex_lock(&rdev->srbm_mutex);
                cik_srbm_select(rdev, rdev->ring[idx].me,
                                rdev->ring[idx].pipe,
                                rdev->ring[idx].queue, 0);
@@ -3099,6 +3106,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                WREG32(CP_HQD_ACTIVE, mqd->queue_state.cp_hqd_active);
 
                cik_srbm_select(rdev, 0, 0, 0, 0);
+               mutex_unlock(&rdev->srbm_mutex);
 
                radeon_bo_kunmap(rdev->ring[idx].mqd_obj);
                radeon_bo_unreserve(rdev->ring[idx].mqd_obj);
@@ -4320,6 +4328,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
 
        /* XXX SH_MEM regs */
        /* where to put LDS, scratch, GPUVM in FSA64 space */
+       mutex_lock(&rdev->srbm_mutex);
        for (i = 0; i < 16; i++) {
                cik_srbm_select(rdev, 0, 0, 0, i);
                /* CP and shaders */
@@ -4335,6 +4344,7 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
                /* XXX SDMA RLC - todo */
        }
        cik_srbm_select(rdev, 0, 0, 0, 0);
+       mutex_unlock(&rdev->srbm_mutex);
 
        cik_pcie_gart_tlb_flush(rdev);
        DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
@@ -5954,6 +5964,8 @@ static int cik_startup(struct radeon_device *rdev)
        struct radeon_ring *ring;
        int r;
 
+       cik_mc_program(rdev);
+
        if (rdev->flags & RADEON_IS_IGP) {
                if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
                    !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
@@ -5985,7 +5997,6 @@ static int cik_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       cik_mc_program(rdev);
        r = cik_pcie_gart_enable(rdev);
        if (r)
                return r;
@@ -6194,7 +6205,7 @@ int cik_suspend(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        cik_cp_enable(rdev, false);
        cik_sdma_enable(rdev, false);
-       r600_uvd_rbc_stop(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_suspend(rdev);
        cik_irq_suspend(rdev);
        radeon_wb_disable(rdev);
@@ -6358,6 +6369,7 @@ void cik_fini(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_fini(rdev);
        cik_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
@@ -6978,7 +6990,7 @@ int cik_uvd_resume(struct radeon_device *rdev)
 
        /* programm the VCPU memory controller bits 0-27 */
        addr = rdev->uvd.gpu_addr >> 3;
-       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
+       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
        WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
        WREG32(UVD_VCPU_CACHE_SIZE0, size);
 
index 9bcdd17..7e5d0b5 100644 (file)
@@ -2038,9 +2038,6 @@ int cypress_dpm_init(struct radeon_device *rdev)
 {
        struct rv7xx_power_info *pi;
        struct evergreen_power_info *eg_pi;
-       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
-       uint16_t data_offset, size;
-       uint8_t frev, crev;
        struct atom_clock_dividers dividers;
        int ret;
 
@@ -2092,16 +2089,7 @@ int cypress_dpm_init(struct radeon_device *rdev)
        eg_pi->vddci_control =
                radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
 
-       if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
-                                   &frev, &crev, &data_offset)) {
-               pi->sclk_ss = true;
-               pi->mclk_ss = true;
-               pi->dynamic_ss = true;
-       } else {
-               pi->sclk_ss = false;
-               pi->mclk_ss = false;
-               pi->dynamic_ss = true;
-       }
+       rv770_get_engine_memory_ss(rdev);
 
        pi->asi = RV770_ASI_DFLT;
        pi->pasi = CYPRESS_HASI_DFLT;
@@ -2122,8 +2110,7 @@ int cypress_dpm_init(struct radeon_device *rdev)
 
        pi->dynamic_pcie_gen2 = true;
 
-       if (pi->gfx_clock_gating &&
-           (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+       if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
                pi->thermal_protection = true;
        else
                pi->thermal_protection = false;
index 038dcac..d5b49e3 100644 (file)
@@ -5106,6 +5106,8 @@ static int evergreen_startup(struct radeon_device *rdev)
        /* enable aspm */
        evergreen_program_aspm(rdev);
 
+       evergreen_mc_program(rdev);
+
        if (ASIC_IS_DCE5(rdev)) {
                if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
                        r = ni_init_microcode(rdev);
@@ -5133,7 +5135,6 @@ static int evergreen_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       evergreen_mc_program(rdev);
        if (rdev->flags & RADEON_IS_AGP) {
                evergreen_agp_enable(rdev);
        } else {
@@ -5291,10 +5292,10 @@ int evergreen_resume(struct radeon_device *rdev)
 int evergreen_suspend(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_suspend(rdev);
        r700_cp_stop(rdev);
        r600_dma_stop(rdev);
-       r600_uvd_rbc_stop(rdev);
        evergreen_irq_suspend(rdev);
        radeon_wb_disable(rdev);
        evergreen_pcie_gart_disable(rdev);
@@ -5429,6 +5430,7 @@ void evergreen_fini(struct radeon_device *rdev)
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
        evergreen_pcie_gart_fini(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
index b0d3fb3..b0e2800 100644 (file)
@@ -148,18 +148,40 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
        u32 base_rate = 24000;
+       u32 max_ratio = clock / base_rate;
+       u32 dto_phase;
+       u32 dto_modulo = clock;
+       u32 wallclock_ratio;
+       u32 dto_cntl;
 
        if (!dig || !dig->afmt)
                return;
 
+       if (max_ratio >= 8) {
+               dto_phase = 192 * 1000;
+               wallclock_ratio = 3;
+       } else if (max_ratio >= 4) {
+               dto_phase = 96 * 1000;
+               wallclock_ratio = 2;
+       } else if (max_ratio >= 2) {
+               dto_phase = 48 * 1000;
+               wallclock_ratio = 1;
+       } else {
+               dto_phase = 24 * 1000;
+               wallclock_ratio = 0;
+       }
+       dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+       dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+       WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+
        /* XXX two dtos; generally use dto0 for hdmi */
        /* Express [24MHz / target pixel clock] as an exact rational
         * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
-       WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
-       WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
        WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
+       WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+       WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
 }
 
 
index a7baf67..0d582ac 100644 (file)
 #define DCCG_AUDIO_DTO0_MODULE            0x05b4
 #define DCCG_AUDIO_DTO0_LOAD              0x05b8
 #define DCCG_AUDIO_DTO0_CNTL              0x05bc
+#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0)
+#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7
+#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0
 
 #define DCCG_AUDIO_DTO1_PHASE             0x05c0
 #define DCCG_AUDIO_DTO1_MODULE            0x05c4
index 56bd4f3..ccb4f8b 100644 (file)
@@ -794,9 +794,13 @@ int ni_init_microcode(struct radeon_device *rdev)
        if ((rdev->family >= CHIP_BARTS) && (rdev->family <= CHIP_CAYMAN)) {
                snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
                err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
-               if (err)
-                       goto out;
-               if (rdev->smc_fw->size != smc_req_size) {
+               if (err) {
+                       printk(KERN_ERR
+                              "smc: error loading firmware \"%s\"\n",
+                              fw_name);
+                       release_firmware(rdev->smc_fw);
+                       rdev->smc_fw = NULL;
+               } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "ni_mc: Bogus length %zu in firmware \"%s\"\n",
                               rdev->mc_fw->size, fw_name);
@@ -2079,6 +2083,8 @@ static int cayman_startup(struct radeon_device *rdev)
        /* enable aspm */
        evergreen_program_aspm(rdev);
 
+       evergreen_mc_program(rdev);
+
        if (rdev->flags & RADEON_IS_IGP) {
                if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
                        r = ni_init_microcode(rdev);
@@ -2107,7 +2113,6 @@ static int cayman_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       evergreen_mc_program(rdev);
        r = cayman_pcie_gart_enable(rdev);
        if (r)
                return r;
@@ -2286,7 +2291,7 @@ int cayman_suspend(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        cayman_cp_enable(rdev, false);
        cayman_dma_stop(rdev);
-       r600_uvd_rbc_stop(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_suspend(rdev);
        evergreen_irq_suspend(rdev);
        radeon_wb_disable(rdev);
@@ -2418,6 +2423,7 @@ void cayman_fini(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_fini(rdev);
        cayman_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
index 559cf24..f0f5f74 100644 (file)
@@ -1054,10 +1054,6 @@ static int ni_restrict_performance_levels_before_switch(struct radeon_device *rd
 int ni_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level)
 {
-       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
-       struct ni_ps *ps = ni_get_ps(rps);
-       u32 levels;
-
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
@@ -1068,8 +1064,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev,
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               levels = ps->performance_level_count - 1;
-               if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+               if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
                        return -EINVAL;
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
                if (ni_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
@@ -4072,9 +4067,6 @@ int ni_dpm_init(struct radeon_device *rdev)
        struct rv7xx_power_info *pi;
        struct evergreen_power_info *eg_pi;
        struct ni_power_info *ni_pi;
-       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
-       u16 data_offset, size;
-       u8 frev, crev;
        struct atom_clock_dividers dividers;
        int ret;
 
@@ -4167,16 +4159,7 @@ int ni_dpm_init(struct radeon_device *rdev)
        eg_pi->vddci_control =
                radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDCI, 0);
 
-       if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
-                                   &frev, &crev, &data_offset)) {
-               pi->sclk_ss = true;
-               pi->mclk_ss = true;
-               pi->dynamic_ss = true;
-       } else {
-               pi->sclk_ss = false;
-               pi->mclk_ss = false;
-               pi->dynamic_ss = true;
-       }
+       rv770_get_engine_memory_ss(rdev);
 
        pi->asi = RV770_ASI_DFLT;
        pi->pasi = CYPRESS_HASI_DFLT;
@@ -4193,8 +4176,7 @@ int ni_dpm_init(struct radeon_device *rdev)
 
        pi->dynamic_pcie_gen2 = true;
 
-       if (pi->gfx_clock_gating &&
-           (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+       if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
                pi->thermal_protection = true;
        else
                pi->thermal_protection = false;
index 10f712e..e66e720 100644 (file)
@@ -2299,9 +2299,13 @@ int r600_init_microcode(struct radeon_device *rdev)
        if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_HEMLOCK)) {
                snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", smc_chip_name);
                err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
-               if (err)
-                       goto out;
-               if (rdev->smc_fw->size != smc_req_size) {
+               if (err) {
+                       printk(KERN_ERR
+                              "smc: error loading firmware \"%s\"\n",
+                              fw_name);
+                       release_firmware(rdev->smc_fw);
+                       rdev->smc_fw = NULL;
+               } else if (rdev->smc_fw->size != smc_req_size) {
                        printk(KERN_ERR
                               "smc: Bogus length %zu in firmware \"%s\"\n",
                               rdev->smc_fw->size, fw_name);
@@ -2697,12 +2701,29 @@ int r600_uvd_rbc_start(struct radeon_device *rdev)
        return 0;
 }
 
-void r600_uvd_rbc_stop(struct radeon_device *rdev)
+void r600_uvd_stop(struct radeon_device *rdev)
 {
        struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
 
        /* force RBC into idle state */
        WREG32(UVD_RBC_RB_CNTL, 0x11010101);
+
+       /* Stall UMC and register bus before resetting VCPU */
+       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
+       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
+       mdelay(1);
+
+       /* put VCPU into reset */
+       WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
+       mdelay(5);
+
+       /* disable VCPU clock */
+       WREG32(UVD_VCPU_CNTL, 0x0);
+
+       /* Unstall UMC and register bus */
+       WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
+       WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
+
        ring->ready = false;
 }
 
@@ -2722,6 +2743,11 @@ int r600_uvd_init(struct radeon_device *rdev)
        /* disable interupt */
        WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
 
+       /* Stall UMC and register bus before resetting VCPU */
+       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
+       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
+       mdelay(1);
+
        /* put LMI, VCPU, RBC etc... into reset */
        WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
               LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
@@ -2751,10 +2777,6 @@ int r600_uvd_init(struct radeon_device *rdev)
        WREG32(UVD_MPC_SET_ALU, 0);
        WREG32(UVD_MPC_SET_MUX, 0x88);
 
-       /* Stall UMC */
-       WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
-       WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
-
        /* take all subblocks out of reset, except VCPU */
        WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
        mdelay(5);
@@ -3312,6 +3334,8 @@ static int r600_startup(struct radeon_device *rdev)
        /* enable pcie gen2 link */
        r600_pcie_gen2_enable(rdev);
 
+       r600_mc_program(rdev);
+
        if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
                r = r600_init_microcode(rdev);
                if (r) {
@@ -3324,7 +3348,6 @@ static int r600_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r600_mc_program(rdev);
        if (rdev->flags & RADEON_IS_AGP) {
                r600_agp_enable(rdev);
        } else {
index f48240b..f264df5 100644 (file)
@@ -226,10 +226,29 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        u32 base_rate = 24000;
+       u32 max_ratio = clock / base_rate;
+       u32 dto_phase;
+       u32 dto_modulo = clock;
+       u32 wallclock_ratio;
+       u32 dto_cntl;
 
        if (!dig || !dig->afmt)
                return;
 
+       if (max_ratio >= 8) {
+               dto_phase = 192 * 1000;
+               wallclock_ratio = 3;
+       } else if (max_ratio >= 4) {
+               dto_phase = 96 * 1000;
+               wallclock_ratio = 2;
+       } else if (max_ratio >= 2) {
+               dto_phase = 48 * 1000;
+               wallclock_ratio = 1;
+       } else {
+               dto_phase = 24 * 1000;
+               wallclock_ratio = 0;
+       }
+
        /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
         * doesn't matter which one you use.  Just use the first one.
         */
@@ -242,9 +261,21 @@ void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
                /* according to the reg specs, this should DCE3.2 only, but in
                 * practice it seems to cover DCE3.0 as well.
                 */
-               WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
-               WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
-               WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+               if (dig->dig_encoder == 0) {
+                       dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+                       dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+                       WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+                       WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+                       WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
+                       WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+               } else {
+                       dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+                       dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+                       WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
+                       WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
+                       WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
+                       WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
+               }
        } else {
                /* according to the reg specs, this should be DCE2.0 and DCE3.0 */
                WREG32(AUDIO_DTO, AUDIO_DTO_PHASE(base_rate / 10) |
index 8e3fe81..7c78083 100644 (file)
 #define DCCG_AUDIO_DTO0_LOAD              0x051c
 #       define DTO_LOAD                   (1 << 31)
 #define DCCG_AUDIO_DTO0_CNTL              0x0520
+#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO(x) (((x) & 7) << 0)
+#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK 7
+#       define DCCG_AUDIO_DTO_WALLCLOCK_RATIO_SHIFT 0
 
 #define DCCG_AUDIO_DTO1_PHASE             0x0524
 #define DCCG_AUDIO_DTO1_MODULE            0x0528
index 2f08219..274b8e1 100644 (file)
@@ -1468,7 +1468,6 @@ struct radeon_uvd {
        void                    *cpu_addr;
        uint64_t                gpu_addr;
        void                    *saved_bo;
-       unsigned                fw_size;
        atomic_t                handles[RADEON_MAX_UVD_HANDLES];
        struct drm_file         *filp[RADEON_MAX_UVD_HANDLES];
        struct delayed_work     idle_work;
@@ -2066,6 +2065,7 @@ struct radeon_device {
        const struct firmware *mec_fw;  /* CIK MEC firmware */
        const struct firmware *sdma_fw; /* CIK SDMA firmware */
        const struct firmware *smc_fw;  /* SMC firmware */
+       const struct firmware *uvd_fw;  /* UVD firmware */
        struct r600_blit r600_blit;
        struct r600_vram_scratch vram_scratch;
        int msi_enabled; /* msi enabled */
@@ -2095,6 +2095,8 @@ struct radeon_device {
        /* ACPI interface */
        struct radeon_atif              atif;
        struct radeon_atcs              atcs;
+       /* srbm instance registers */
+       struct mutex                    srbm_mutex;
 };
 
 int radeon_device_init(struct radeon_device *rdev,
index 902479f..3d61d5a 100644 (file)
@@ -441,7 +441,7 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
 /* uvd */
 int r600_uvd_init(struct radeon_device *rdev);
 int r600_uvd_rbc_start(struct radeon_device *rdev);
-void r600_uvd_rbc_stop(struct radeon_device *rdev);
+void r600_uvd_stop(struct radeon_device *rdev);
 int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
 void r600_uvd_fence_emit(struct radeon_device *rdev,
                         struct radeon_fence *fence);
index e3f3e88..4ccd61f 100644 (file)
@@ -2782,7 +2782,7 @@ int radeon_atom_get_clock_dividers(struct radeon_device *rdev,
                                                             ATOM_PLL_CNTL_FLAG_PLL_POST_DIV_EN) ? true : false;
                                dividers->enable_dithen = (args.v3.ucCntlFlag &
                                                           ATOM_PLL_CNTL_FLAG_FRACTION_DISABLE) ? false : true;
-                               dividers->fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
+                               dividers->whole_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDiv);
                                dividers->frac_fb_div = le16_to_cpu(args.v3.ulFbDiv.usFbDivFrac);
                                dividers->ref_div = args.v3.ucRefDiv;
                                dividers->vco_mode = (args.v3.ucCntlFlag &
index 82335e3..63398ae 100644 (file)
@@ -1163,6 +1163,7 @@ int radeon_device_init(struct radeon_device *rdev,
        mutex_init(&rdev->gem.mutex);
        mutex_init(&rdev->pm.mutex);
        mutex_init(&rdev->gpu_clock_mutex);
+       mutex_init(&rdev->srbm_mutex);
        init_rwsem(&rdev->pm.mclk_lock);
        init_rwsem(&rdev->exclusive_lock);
        init_waitqueue_head(&rdev->irq.vblank_queue);
@@ -1519,6 +1520,7 @@ int radeon_gpu_reset(struct radeon_device *rdev)
        radeon_save_bios_scratch_regs(rdev);
        /* block TTM */
        resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
+       radeon_pm_suspend(rdev);
        radeon_suspend(rdev);
 
        for (i = 0; i < RADEON_NUM_RINGS; ++i) {
@@ -1564,6 +1566,7 @@ retry:
                }
        }
 
+       radeon_pm_resume(rdev);
        drm_helper_resume_force_mode(rdev->ddev);
 
        ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
index 7ddb0ef..ddb8f8e 100644 (file)
@@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
 
                } else {
                        /* put fence directly behind firmware */
-                       index = ALIGN(rdev->uvd.fw_size, 8);
+                       index = ALIGN(rdev->uvd_fw->size, 8);
                        rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index;
                        rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index;
                }
index 6a51d94..b990b1a 100644 (file)
@@ -207,7 +207,6 @@ void radeon_gart_table_vram_free(struct radeon_device *rdev)
        if (rdev->gart.robj == NULL) {
                return;
        }
-       radeon_gart_table_vram_unpin(rdev);
        radeon_bo_unref(&rdev->gart.robj);
 }
 
index f374c46..c557850 100644 (file)
@@ -1176,7 +1176,14 @@ int radeon_pm_init(struct radeon_device *rdev)
        case CHIP_VERDE:
        case CHIP_OLAND:
        case CHIP_HAINAN:
-               if (radeon_dpm == 1)
+               /* DPM requires the RLC, RV770+ dGPU requires SMC */
+               if (!rdev->rlc_fw)
+                       rdev->pm.pm_method = PM_METHOD_PROFILE;
+               else if ((rdev->family >= CHIP_RV770) &&
+                        (!(rdev->flags & RADEON_IS_IGP)) &&
+                        (!rdev->smc_fw))
+                       rdev->pm.pm_method = PM_METHOD_PROFILE;
+               else if (radeon_dpm == 1)
                        rdev->pm.pm_method = PM_METHOD_DPM;
                else
                        rdev->pm.pm_method = PM_METHOD_PROFILE;
index 414fd14..f1c1575 100644 (file)
@@ -56,7 +56,6 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work);
 
 int radeon_uvd_init(struct radeon_device *rdev)
 {
-       const struct firmware *fw;
        unsigned long bo_size;
        const char *fw_name;
        int i, r;
@@ -105,14 +104,14 @@ int radeon_uvd_init(struct radeon_device *rdev)
                return -EINVAL;
        }
 
-       r = request_firmware(&fw, fw_name, rdev->dev);
+       r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev);
        if (r) {
                dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
                        fw_name);
                return r;
        }
 
-       bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) +
+       bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
                  RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
        r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
                             RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
@@ -145,12 +144,6 @@ int radeon_uvd_init(struct radeon_device *rdev)
 
        radeon_bo_unreserve(rdev->uvd.vcpu_bo);
 
-       rdev->uvd.fw_size = fw->size;
-       memset(rdev->uvd.cpu_addr, 0, bo_size);
-       memcpy(rdev->uvd.cpu_addr, fw->data, fw->size);
-
-       release_firmware(fw);
-
        for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
                atomic_set(&rdev->uvd.handles[i], 0);
                rdev->uvd.filp[i] = NULL;
@@ -174,33 +167,60 @@ void radeon_uvd_fini(struct radeon_device *rdev)
        }
 
        radeon_bo_unref(&rdev->uvd.vcpu_bo);
+
+       release_firmware(rdev->uvd_fw);
 }
 
 int radeon_uvd_suspend(struct radeon_device *rdev)
 {
        unsigned size;
+       void *ptr;
+       int i;
 
        if (rdev->uvd.vcpu_bo == NULL)
                return 0;
 
+       for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i)
+               if (atomic_read(&rdev->uvd.handles[i]))
+                       break;
+
+       if (i == RADEON_MAX_UVD_HANDLES)
+               return 0;
+
        size = radeon_bo_size(rdev->uvd.vcpu_bo);
+       size -= rdev->uvd_fw->size;
+
+       ptr = rdev->uvd.cpu_addr;
+       ptr += rdev->uvd_fw->size;
+
        rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
-       memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
+       memcpy(rdev->uvd.saved_bo, ptr, size);
 
        return 0;
 }
 
 int radeon_uvd_resume(struct radeon_device *rdev)
 {
+       unsigned size;
+       void *ptr;
+
        if (rdev->uvd.vcpu_bo == NULL)
                return -EINVAL;
 
+       memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
+
+       size = radeon_bo_size(rdev->uvd.vcpu_bo);
+       size -= rdev->uvd_fw->size;
+
+       ptr = rdev->uvd.cpu_addr;
+       ptr += rdev->uvd_fw->size;
+
        if (rdev->uvd.saved_bo != NULL) {
-               unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
-               memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
+               memcpy(ptr, rdev->uvd.saved_bo, size);
                kfree(rdev->uvd.saved_bo);
                rdev->uvd.saved_bo = NULL;
-       }
+       } else
+               memset(ptr, 0, size);
 
        return 0;
 }
@@ -215,8 +235,8 @@ void radeon_uvd_free_handles(struct radeon_device *rdev, struct drm_file *filp)
 {
        int i, r;
        for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
-               if (rdev->uvd.filp[i] == filp) {
-                       uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
+               uint32_t handle = atomic_read(&rdev->uvd.handles[i]);
+               if (handle != 0 && rdev->uvd.filp[i] == filp) {
                        struct radeon_fence *fence;
 
                        r = radeon_uvd_get_destroy_msg(rdev,
@@ -337,8 +357,10 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
        }
 
        r = radeon_bo_kmap(bo, &ptr);
-       if (r)
+       if (r) {
+               DRM_ERROR("Failed mapping the UVD message (%d)!\n", r);
                return r;
+       }
 
        msg = ptr + offset;
 
@@ -364,8 +386,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
                radeon_bo_kunmap(bo);
                return 0;
        } else {
-               /* it's a create msg, no special handling needed */
                radeon_bo_kunmap(bo);
+
+               if (msg_type != 0) {
+                       DRM_ERROR("Illegal UVD message type (%d)!\n", msg_type);
+                       return -EINVAL;
+               }
+
+               /* it's a create msg, no special handling needed */
        }
 
        /* create or decode, validate the handle */
@@ -388,7 +416,7 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo,
 
 static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
                               int data0, int data1,
-                              unsigned buf_sizes[])
+                              unsigned buf_sizes[], bool *has_msg_cmd)
 {
        struct radeon_cs_chunk *relocs_chunk;
        struct radeon_cs_reloc *reloc;
@@ -417,7 +445,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
 
        if (cmd < 0x4) {
                if ((end - start) < buf_sizes[cmd]) {
-                       DRM_ERROR("buffer to small (%d / %d)!\n",
+                       DRM_ERROR("buffer (%d) to small (%d / %d)!\n", cmd,
                                  (unsigned)(end - start), buf_sizes[cmd]);
                        return -EINVAL;
                }
@@ -442,9 +470,17 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
        }
 
        if (cmd == 0) {
+               if (*has_msg_cmd) {
+                       DRM_ERROR("More than one message in a UVD-IB!\n");
+                       return -EINVAL;
+               }
+               *has_msg_cmd = true;
                r = radeon_uvd_cs_msg(p, reloc->robj, offset, buf_sizes);
                if (r)
                        return r;
+       } else if (!*has_msg_cmd) {
+               DRM_ERROR("Message needed before other commands are send!\n");
+               return -EINVAL;
        }
 
        return 0;
@@ -453,7 +489,8 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
 static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
                             struct radeon_cs_packet *pkt,
                             int *data0, int *data1,
-                            unsigned buf_sizes[])
+                            unsigned buf_sizes[],
+                            bool *has_msg_cmd)
 {
        int i, r;
 
@@ -467,7 +504,8 @@ static int radeon_uvd_cs_reg(struct radeon_cs_parser *p,
                        *data1 = p->idx;
                        break;
                case UVD_GPCOM_VCPU_CMD:
-                       r = radeon_uvd_cs_reloc(p, *data0, *data1, buf_sizes);
+                       r = radeon_uvd_cs_reloc(p, *data0, *data1,
+                                               buf_sizes, has_msg_cmd);
                        if (r)
                                return r;
                        break;
@@ -488,6 +526,9 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
        struct radeon_cs_packet pkt;
        int r, data0 = 0, data1 = 0;
 
+       /* does the IB has a msg command */
+       bool has_msg_cmd = false;
+
        /* minimum buffer sizes */
        unsigned buf_sizes[] = {
                [0x00000000]    =       2048,
@@ -514,8 +555,8 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
                        return r;
                switch (pkt.type) {
                case RADEON_PACKET_TYPE0:
-                       r = radeon_uvd_cs_reg(p, &pkt, &data0,
-                                             &data1, buf_sizes);
+                       r = radeon_uvd_cs_reg(p, &pkt, &data0, &data1,
+                                             buf_sizes, &has_msg_cmd);
                        if (r)
                                return r;
                        break;
@@ -527,6 +568,12 @@ int radeon_uvd_cs_parse(struct radeon_cs_parser *p)
                        return -EINVAL;
                }
        } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
+
+       if (!has_msg_cmd) {
+               DRM_ERROR("UVD-IBs need a msg command!\n");
+               return -EINVAL;
+       }
+
        return 0;
 }
 
index 363018c..bdd888b 100644 (file)
@@ -1944,9 +1944,7 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev)
 
 int rv6xx_dpm_init(struct radeon_device *rdev)
 {
-       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
-       uint16_t data_offset, size;
-       uint8_t frev, crev;
+       struct radeon_atom_ss ss;
        struct atom_clock_dividers dividers;
        struct rv6xx_power_info *pi;
        int ret;
@@ -1989,16 +1987,18 @@ int rv6xx_dpm_init(struct radeon_device *rdev)
 
        pi->gfx_clock_gating = true;
 
-       if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
-                                   &frev, &crev, &data_offset)) {
-               pi->sclk_ss = true;
-               pi->mclk_ss = true;
+       pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                      ASIC_INTERNAL_ENGINE_SS, 0);
+       pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                      ASIC_INTERNAL_MEMORY_SS, 0);
+
+       /* Disable sclk ss, causes hangs on a lot of systems */
+       pi->sclk_ss = false;
+
+       if (pi->sclk_ss || pi->mclk_ss)
                pi->dynamic_ss = true;
-       } else {
-               pi->sclk_ss = false;
-               pi->mclk_ss = false;
+       else
                pi->dynamic_ss = false;
-       }
 
        pi->dynamic_pcie_gen2 = true;
 
index 30ea14e..bcc68ec 100644 (file)
@@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev)
 
        /* programm the VCPU memory controller bits 0-27 */
        addr = rdev->uvd.gpu_addr >> 3;
-       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
+       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
        WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
        WREG32(UVD_VCPU_CACHE_SIZE0, size);
 
@@ -1829,6 +1829,8 @@ static int rv770_startup(struct radeon_device *rdev)
        /* enable pcie gen2 link */
        rv770_pcie_gen2_enable(rdev);
 
+       rv770_mc_program(rdev);
+
        if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
                r = r600_init_microcode(rdev);
                if (r) {
@@ -1841,7 +1843,6 @@ static int rv770_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       rv770_mc_program(rdev);
        if (rdev->flags & RADEON_IS_AGP) {
                rv770_agp_enable(rdev);
        } else {
@@ -1983,6 +1984,7 @@ int rv770_resume(struct radeon_device *rdev)
 int rv770_suspend(struct radeon_device *rdev)
 {
        r600_audio_fini(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_suspend(rdev);
        r700_cp_stop(rdev);
        r600_dma_stop(rdev);
@@ -2098,6 +2100,7 @@ void rv770_fini(struct radeon_device *rdev)
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
        rv770_pcie_gart_fini(rdev);
+       r600_uvd_stop(rdev);
        radeon_uvd_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
index 2d34792..094c67a 100644 (file)
@@ -2319,12 +2319,25 @@ int rv7xx_parse_power_table(struct radeon_device *rdev)
        return 0;
 }
 
+void rv770_get_engine_memory_ss(struct radeon_device *rdev)
+{
+       struct rv7xx_power_info *pi = rv770_get_pi(rdev);
+       struct radeon_atom_ss ss;
+
+       pi->sclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                      ASIC_INTERNAL_ENGINE_SS, 0);
+       pi->mclk_ss = radeon_atombios_get_asic_ss_info(rdev, &ss,
+                                                      ASIC_INTERNAL_MEMORY_SS, 0);
+
+       if (pi->sclk_ss || pi->mclk_ss)
+               pi->dynamic_ss = true;
+       else
+               pi->dynamic_ss = false;
+}
+
 int rv770_dpm_init(struct radeon_device *rdev)
 {
        struct rv7xx_power_info *pi;
-       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
-       uint16_t data_offset, size;
-       uint8_t frev, crev;
        struct atom_clock_dividers dividers;
        int ret;
 
@@ -2369,16 +2382,7 @@ int rv770_dpm_init(struct radeon_device *rdev)
        pi->mvdd_control =
                radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_MVDDC, 0);
 
-       if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
-                                   &frev, &crev, &data_offset)) {
-               pi->sclk_ss = true;
-               pi->mclk_ss = true;
-               pi->dynamic_ss = true;
-       } else {
-               pi->sclk_ss = false;
-               pi->mclk_ss = false;
-               pi->dynamic_ss = false;
-       }
+       rv770_get_engine_memory_ss(rdev);
 
        pi->asi = RV770_ASI_DFLT;
        pi->pasi = RV770_HASI_DFLT;
@@ -2393,8 +2397,7 @@ int rv770_dpm_init(struct radeon_device *rdev)
 
        pi->dynamic_pcie_gen2 = true;
 
-       if (pi->gfx_clock_gating &&
-           (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+       if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
                pi->thermal_protection = true;
        else
                pi->thermal_protection = false;
index 96b1b2a..9244eff 100644 (file)
@@ -275,6 +275,7 @@ void rv770_set_uvd_clock_before_set_eng_clock(struct radeon_device *rdev,
 void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
                                             struct radeon_ps *new_ps,
                                             struct radeon_ps *old_ps);
+void rv770_get_engine_memory_ss(struct radeon_device *rdev);
 
 /* smc */
 int rv770_read_smc_soft_register(struct radeon_device *rdev,
index d325280..daa8d2d 100644 (file)
@@ -1663,9 +1663,13 @@ static int si_init_microcode(struct radeon_device *rdev)
 
        snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", chip_name);
        err = request_firmware(&rdev->smc_fw, fw_name, rdev->dev);
-       if (err)
-               goto out;
-       if (rdev->smc_fw->size != smc_req_size) {
+       if (err) {
+               printk(KERN_ERR
+                      "smc: error loading firmware \"%s\"\n",
+                      fw_name);
+               release_firmware(rdev->smc_fw);
+               rdev->smc_fw = NULL;
+       } else if (rdev->smc_fw->size != smc_req_size) {
                printk(KERN_ERR
                       "si_smc: Bogus length %zu in firmware \"%s\"\n",
                       rdev->smc_fw->size, fw_name);
@@ -5215,14 +5219,12 @@ static void si_enable_mc_ls(struct radeon_device *rdev,
 
 static void si_init_cg(struct radeon_device *rdev)
 {
-       bool has_uvd = true;
-
        si_enable_mgcg(rdev, true);
-       si_enable_cgcg(rdev, true);
+       si_enable_cgcg(rdev, false);
        /* disable MC LS on Tahiti */
        if (rdev->family == CHIP_TAHITI)
                si_enable_mc_ls(rdev, false);
-       if (has_uvd) {
+       if (rdev->has_uvd) {
                si_enable_uvd_mgcg(rdev, true);
                si_init_uvd_internal_cg(rdev);
        }
@@ -5230,9 +5232,7 @@ static void si_init_cg(struct radeon_device *rdev)
 
 static void si_fini_cg(struct radeon_device *rdev)
 {
-       bool has_uvd = true;
-
-       if (has_uvd)
+       if (rdev->has_uvd)
                si_enable_uvd_mgcg(rdev, false);
        si_enable_cgcg(rdev, false);
        si_enable_mgcg(rdev, false);
@@ -5241,11 +5241,11 @@ static void si_fini_cg(struct radeon_device *rdev)
 static void si_init_pg(struct radeon_device *rdev)
 {
        bool has_pg = false;
-
+#if 0
        /* only cape verde supports PG */
        if (rdev->family == CHIP_VERDE)
                has_pg = true;
-
+#endif
        if (has_pg) {
                si_init_ao_cu_mask(rdev);
                si_init_dma_pg(rdev);
@@ -6422,6 +6422,8 @@ static int si_startup(struct radeon_device *rdev)
        /* enable aspm */
        si_program_aspm(rdev);
 
+       si_mc_program(rdev);
+
        if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
            !rdev->rlc_fw || !rdev->mc_fw) {
                r = si_init_microcode(rdev);
@@ -6441,7 +6443,6 @@ static int si_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       si_mc_program(rdev);
        r = si_pcie_gart_enable(rdev);
        if (r)
                return r;
@@ -6625,7 +6626,7 @@ int si_suspend(struct radeon_device *rdev)
        si_cp_enable(rdev, false);
        cayman_dma_stop(rdev);
        if (rdev->has_uvd) {
-               r600_uvd_rbc_stop(rdev);
+               r600_uvd_stop(rdev);
                radeon_uvd_suspend(rdev);
        }
        si_irq_suspend(rdev);
@@ -6767,8 +6768,10 @@ void si_fini(struct radeon_device *rdev)
        radeon_vm_manager_fini(rdev);
        radeon_ib_pool_fini(rdev);
        radeon_irq_kms_fini(rdev);
-       if (rdev->has_uvd)
+       if (rdev->has_uvd) {
+               r600_uvd_stop(rdev);
                radeon_uvd_fini(rdev);
+       }
        si_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
index 73aaa2e..88699e3 100644 (file)
@@ -37,8 +37,6 @@
 
 #define SMC_RAM_END                 0x20000
 
-#define DDR3_DRAM_ROWS              0x2000
-
 #define SCLK_MIN_DEEPSLEEP_FREQ     1350
 
 static const struct si_cac_config_reg cac_weights_tahiti[] =
@@ -1767,8 +1765,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
 {
        s64 kt, kv, leakage_w, i_leakage, vddc;
        s64 temperature, t_slope, t_intercept, av, bv, t_ref;
+       s64 tmp;
 
-       i_leakage = drm_int2fixp(ileakage / 100);
+       i_leakage = div64_s64(drm_int2fixp(ileakage), 100);
        vddc = div64_s64(drm_int2fixp(v), 1000);
        temperature = div64_s64(drm_int2fixp(t), 1000);
 
@@ -1778,8 +1777,9 @@ static void si_calculate_leakage_for_v_and_t_formula(const struct ni_leakage_coe
        bv = div64_s64(drm_int2fixp(coeff->bv), 100000000);
        t_ref = drm_int2fixp(coeff->t_ref);
 
-       kt = drm_fixp_div(drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, temperature)),
-                         drm_fixp_exp(drm_fixp_mul(drm_fixp_mul(t_slope, vddc) + t_intercept, t_ref)));
+       tmp = drm_fixp_mul(t_slope, vddc) + t_intercept;
+       kt = drm_fixp_exp(drm_fixp_mul(tmp, temperature));
+       kt = drm_fixp_div(kt, drm_fixp_exp(drm_fixp_mul(tmp, t_ref)));
        kv = drm_fixp_mul(av, drm_fixp_exp(drm_fixp_mul(bv, vddc)));
 
        leakage_w = drm_fixp_mul(drm_fixp_mul(drm_fixp_mul(i_leakage, kt), kv), vddc);
@@ -1931,6 +1931,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
                        si_pi->cac_override = cac_override_pitcairn;
                        si_pi->powertune_data = &powertune_data_pitcairn;
                        si_pi->dte_data = dte_data_pitcairn;
+                       break;
                }
        } else if (rdev->family == CHIP_VERDE) {
                si_pi->lcac_config = lcac_cape_verde;
@@ -1941,6 +1942,7 @@ static void si_initialize_powertune_defaults(struct radeon_device *rdev)
                case 0x683B:
                case 0x683F:
                case 0x6829:
+               case 0x6835:
                        si_pi->cac_weights = cac_weights_cape_verde_pro;
                        si_pi->dte_data = dte_data_cape_verde;
                        break;
@@ -2901,7 +2903,8 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
 {
        struct ni_ps *ps = ni_get_ps(rps);
        struct radeon_clock_and_voltage_limits *max_limits;
-       bool disable_mclk_switching;
+       bool disable_mclk_switching = false;
+       bool disable_sclk_switching = false;
        u32 mclk, sclk;
        u16 vddc, vddci;
        int i;
@@ -2909,8 +2912,11 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
            ni_dpm_vblank_too_short(rdev))
                disable_mclk_switching = true;
-       else
-               disable_mclk_switching = false;
+
+       if (rps->vclk || rps->dclk) {
+               disable_mclk_switching = true;
+               disable_sclk_switching = true;
+       }
 
        if (rdev->pm.dpm.ac_power)
                max_limits = &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
@@ -2938,27 +2944,43 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
 
        if (disable_mclk_switching) {
                mclk  = ps->performance_levels[ps->performance_level_count - 1].mclk;
-               sclk = ps->performance_levels[0].sclk;
-               vddc = ps->performance_levels[0].vddc;
                vddci = ps->performance_levels[ps->performance_level_count - 1].vddci;
        } else {
-               sclk = ps->performance_levels[0].sclk;
                mclk = ps->performance_levels[0].mclk;
-               vddc = ps->performance_levels[0].vddc;
                vddci = ps->performance_levels[0].vddci;
        }
 
+       if (disable_sclk_switching) {
+               sclk = ps->performance_levels[ps->performance_level_count - 1].sclk;
+               vddc = ps->performance_levels[ps->performance_level_count - 1].vddc;
+       } else {
+               sclk = ps->performance_levels[0].sclk;
+               vddc = ps->performance_levels[0].vddc;
+       }
+
        /* adjusted low state */
        ps->performance_levels[0].sclk = sclk;
        ps->performance_levels[0].mclk = mclk;
        ps->performance_levels[0].vddc = vddc;
        ps->performance_levels[0].vddci = vddci;
 
-       for (i = 1; i < ps->performance_level_count; i++) {
-               if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
-                       ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
-               if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
-                       ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+       if (disable_sclk_switching) {
+               sclk = ps->performance_levels[0].sclk;
+               for (i = 1; i < ps->performance_level_count; i++) {
+                       if (sclk < ps->performance_levels[i].sclk)
+                               sclk = ps->performance_levels[i].sclk;
+               }
+               for (i = 0; i < ps->performance_level_count; i++) {
+                       ps->performance_levels[i].sclk = sclk;
+                       ps->performance_levels[i].vddc = vddc;
+               }
+       } else {
+               for (i = 1; i < ps->performance_level_count; i++) {
+                       if (ps->performance_levels[i].sclk < ps->performance_levels[i - 1].sclk)
+                               ps->performance_levels[i].sclk = ps->performance_levels[i - 1].sclk;
+                       if (ps->performance_levels[i].vddc < ps->performance_levels[i - 1].vddc)
+                               ps->performance_levels[i].vddc = ps->performance_levels[i - 1].vddc;
+               }
        }
 
        if (disable_mclk_switching) {
@@ -3237,10 +3259,10 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
 {
        struct radeon_ps *rps = rdev->pm.dpm.current_ps;
        struct ni_ps *ps = ni_get_ps(rps);
-       u32 levels;
+       u32 levels = ps->performance_level_count;
 
        if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
                        return -EINVAL;
 
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 1) != PPSMC_Result_OK)
@@ -3249,14 +3271,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               levels = ps->performance_level_count - 1;
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 1) != PPSMC_Result_OK)
                        return -EINVAL;
        } else if (level == RADEON_DPM_FORCED_LEVEL_AUTO) {
                if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetForcedLevels, 0) != PPSMC_Result_OK)
                        return -EINVAL;
 
-               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, 0) != PPSMC_Result_OK)
+               if (si_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_SetEnabledLevels, levels) != PPSMC_Result_OK)
                        return -EINVAL;
        }
 
@@ -3620,8 +3641,12 @@ static void si_enable_display_gap(struct radeon_device *rdev)
 {
        u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
 
+       tmp &= ~(DISP1_GAP_MASK | DISP2_GAP_MASK);
+       tmp |= (DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE) |
+               DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE));
+
        tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
-       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE) |
+       tmp |= (DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK) |
                DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE));
        WREG32(CG_DISPLAY_GAP_CNTL, tmp);
 }
@@ -4036,16 +4061,15 @@ static int si_force_switch_to_arb_f0(struct radeon_device *rdev)
 static u32 si_calculate_memory_refresh_rate(struct radeon_device *rdev,
                                            u32 engine_clock)
 {
-       struct rv7xx_power_info *pi = rv770_get_pi(rdev);
        u32 dram_rows;
        u32 dram_refresh_rate;
        u32 mc_arb_rfsh_rate;
        u32 tmp = (RREG32(MC_ARB_RAMCFG) & NOOFROWS_MASK) >> NOOFROWS_SHIFT;
 
-       if (pi->mem_gddr5)
-               dram_rows = 1 << (tmp + 10);
+       if (tmp >= 4)
+               dram_rows = 16384;
        else
-               dram_rows = DDR3_DRAM_ROWS;
+               dram_rows = 1 << (tmp + 10);
 
        dram_refresh_rate = 1 << ((RREG32(MC_SEQ_MISC0) & 0x3) + 3);
        mc_arb_rfsh_rate = ((engine_clock * 10) * dram_refresh_rate / dram_rows - 32) / 64;
@@ -6013,16 +6037,11 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-#if 0
-       /* XXX */
        ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
        if (ret) {
                DRM_ERROR("si_dpm_force_performance_level failed\n");
                return ret;
        }
-#else
-       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
-#endif
 
        return 0;
 }
@@ -6254,9 +6273,6 @@ int si_dpm_init(struct radeon_device *rdev)
        struct evergreen_power_info *eg_pi;
        struct ni_power_info *ni_pi;
        struct si_power_info *si_pi;
-       int index = GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info);
-       u16 data_offset, size;
-       u8 frev, crev;
        struct atom_clock_dividers dividers;
        int ret;
        u32 mask;
@@ -6347,16 +6363,7 @@ int si_dpm_init(struct radeon_device *rdev)
        si_pi->vddc_phase_shed_control =
                radeon_atom_is_voltage_gpio(rdev, SET_VOLTAGE_TYPE_ASIC_VDDC, VOLTAGE_OBJ_PHASE_LUT);
 
-       if (atom_parse_data_header(rdev->mode_info.atom_context, index, &size,
-                                   &frev, &crev, &data_offset)) {
-               pi->sclk_ss = true;
-               pi->mclk_ss = true;
-               pi->dynamic_ss = true;
-       } else {
-               pi->sclk_ss = false;
-               pi->mclk_ss = false;
-               pi->dynamic_ss = true;
-       }
+       rv770_get_engine_memory_ss(rdev);
 
        pi->asi = RV770_ASI_DFLT;
        pi->pasi = CYPRESS_HASI_DFLT;
@@ -6367,8 +6374,7 @@ int si_dpm_init(struct radeon_device *rdev)
        eg_pi->sclk_deep_sleep = true;
        si_pi->sclk_deep_sleep_above_low = false;
 
-       if (pi->gfx_clock_gating &&
-           (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE))
+       if (rdev->pm.int_thermal_type != THERMAL_TYPE_NONE)
                pi->thermal_protection = true;
        else
                pi->thermal_protection = false;
index 5207591..cd33084 100644 (file)
@@ -192,6 +192,7 @@ static struct hid_ll_driver logi_dj_ll_driver;
 static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
                                        size_t count,
                                        unsigned char report_type);
+static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
 
 static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
                                                struct dj_report *dj_report)
@@ -232,6 +233,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
        if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
            SPFUNCTION_DEVICE_LIST_EMPTY) {
                dbg_hid("%s: device list is empty\n", __func__);
+               djrcv_dev->querying_devices = false;
                return;
        }
 
@@ -242,6 +244,12 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
                return;
        }
 
+       if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
+               /* The device is already known. No need to reallocate it. */
+               dbg_hid("%s: device is already known\n", __func__);
+               return;
+       }
+
        dj_hiddev = hid_allocate_device();
        if (IS_ERR(dj_hiddev)) {
                dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@@ -305,6 +313,7 @@ static void delayedwork_callback(struct work_struct *work)
        struct dj_report dj_report;
        unsigned long flags;
        int count;
+       int retval;
 
        dbg_hid("%s\n", __func__);
 
@@ -337,6 +346,25 @@ static void delayedwork_callback(struct work_struct *work)
                logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
                break;
        default:
+       /* A normal report (i. e. not belonging to a pair/unpair notification)
+        * arriving here, means that the report arrived but we did not have a
+        * paired dj_device associated to the report's device_index, this
+        * means that the original "device paired" notification corresponding
+        * to this dj_device never arrived to this driver. The reason is that
+        * hid-core discards all packets coming from a device while probe() is
+        * executing. */
+       if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
+               /* ok, we don't know the device, just re-ask the
+                * receiver for the list of connected devices. */
+               retval = logi_dj_recv_query_paired_devices(djrcv_dev);
+               if (!retval) {
+                       /* everything went fine, so just leave */
+                       break;
+               }
+               dev_err(&djrcv_dev->hdev->dev,
+                       "%s:logi_dj_recv_query_paired_devices "
+                       "error:%d\n", __func__, retval);
+               }
                dbg_hid("%s: unexpected report type\n", __func__);
        }
 }
@@ -367,6 +395,12 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
        if (!djdev) {
                dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
                        " is NULL, index %d\n", dj_report->device_index);
+               kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+               if (schedule_work(&djrcv_dev->work) == 0) {
+                       dbg_hid("%s: did not schedule the work item, was already "
+                       "queued\n", __func__);
+               }
                return;
        }
 
@@ -397,6 +431,12 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
        if (dj_device == NULL) {
                dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
                        " is NULL, index %d\n", dj_report->device_index);
+               kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
+
+               if (schedule_work(&djrcv_dev->work) == 0) {
+                       dbg_hid("%s: did not schedule the work item, was already "
+                       "queued\n", __func__);
+               }
                return;
        }
 
@@ -444,6 +484,10 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
        struct dj_report *dj_report;
        int retval;
 
+       /* no need to protect djrcv_dev->querying_devices */
+       if (djrcv_dev->querying_devices)
+               return 0;
+
        dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
        if (!dj_report)
                return -ENOMEM;
@@ -455,6 +499,7 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
        return retval;
 }
 
+
 static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
                                          unsigned timeout)
 {
index fd28a5e..4a40003 100644 (file)
@@ -101,6 +101,7 @@ struct dj_receiver_dev {
        struct work_struct work;
        struct kfifo notif_fifo;
        spinlock_t lock;
+       bool querying_devices;
 };
 
 struct dj_device {
index ecbc749..87fbe29 100644 (file)
@@ -369,7 +369,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi,
        if (sc->quirks & PS3REMOTE)
                return ps3remote_mapping(hdev, hi, field, usage, bit, max);
 
-       return -1;
+       /* Let hid-core decide for the others */
+       return 0;
 }
 
 /*
index a745163..6f1feb2 100644 (file)
@@ -518,7 +518,6 @@ int hidraw_connect(struct hid_device *hid)
                goto out;
        }
 
-       mutex_unlock(&minors_lock);
        init_waitqueue_head(&dev->wait);
        INIT_LIST_HEAD(&dev->list);
 
@@ -528,6 +527,7 @@ int hidraw_connect(struct hid_device *hid)
        dev->exist = 1;
        hid->hidraw = dev;
 
+       mutex_unlock(&minors_lock);
 out:
        return result;
 
index 0f34bca..6099f50 100644 (file)
@@ -215,7 +215,7 @@ static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg,
                                          u16 value)
 {
        return i2c_smbus_write_byte_data(client, reg, value & 0xFF)
-              && i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
+              || i2c_smbus_write_byte_data(client, reg + 1, value >> 8);
 }
 
 static void adt7470_init_client(struct i2c_client *client)
index 328fb03..a41b5f3 100644 (file)
@@ -605,12 +605,12 @@ static int max6697_init_chip(struct i2c_client *client)
                if (ret < 0)
                        return ret;
                ret = i2c_smbus_write_byte_data(client, MAX6581_REG_IDEALITY,
-                                               pdata->ideality_mask >> 1);
+                                               pdata->ideality_value);
                if (ret < 0)
                        return ret;
                ret = i2c_smbus_write_byte_data(client,
                                                MAX6581_REG_IDEALITY_SELECT,
-                                               pdata->ideality_value);
+                                               pdata->ideality_mask >> 1);
                if (ret < 0)
                        return ret;
        }
index ccec916..af8f65f 100644 (file)
@@ -246,9 +246,9 @@ static void kempld_i2c_device_init(struct kempld_i2c_data *i2c)
                bus_frequency = KEMPLD_I2C_FREQ_MAX;
 
        if (pld->info.spec_major == 1)
-               prescale = pld->pld_clock / bus_frequency * 5 - 1000;
+               prescale = pld->pld_clock / (bus_frequency * 5) - 1000;
        else
-               prescale = pld->pld_clock / bus_frequency * 4 - 3000;
+               prescale = pld->pld_clock / (bus_frequency * 4) - 3000;
 
        if (prescale < 0)
                prescale = 0;
index df8ff5a..e2e9a0d 100644 (file)
@@ -493,7 +493,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
         * based on this empirical measurement and a lot of previous frobbing.
         */
        i2c->cmd_err = 0;
-       if (msg->len < 8) {
+       if (0) {        /* disable PIO mode until a proper fix is made */
                ret = mxs_i2c_pio_setup_xfer(adap, msg, flags);
                if (ret)
                        mxs_i2c_reset(i2c);
index 0ad208a..3ceac3e 100644 (file)
@@ -60,7 +60,6 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
 {
        unsigned int stepconfig;
        int i, steps;
-       u32 step_en;
 
        /*
         * There are 16 configurable steps and 8 analog input
@@ -86,8 +85,7 @@ static void tiadc_step_config(struct tiadc_device *adc_dev)
                adc_dev->channel_step[i] = steps;
                steps++;
        }
-       step_en = get_adc_step_mask(adc_dev);
-       am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
+
 }
 
 static const char * const chan_name_ain[] = {
@@ -142,10 +140,22 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
                int *val, int *val2, long mask)
 {
        struct tiadc_device *adc_dev = iio_priv(indio_dev);
-       int i;
-       unsigned int fifo1count, read;
+       int i, map_val;
+       unsigned int fifo1count, read, stepid;
        u32 step = UINT_MAX;
        bool found = false;
+       u32 step_en;
+       unsigned long timeout = jiffies + usecs_to_jiffies
+                               (IDLE_TIMEOUT * adc_dev->channels);
+       step_en = get_adc_step_mask(adc_dev);
+       am335x_tsc_se_set(adc_dev->mfd_tscadc, step_en);
+
+       /* Wait for ADC sequencer to complete sampling */
+       while (tiadc_readl(adc_dev, REG_ADCFSM) & SEQ_STATUS) {
+               if (time_after(jiffies, timeout))
+                       return -EAGAIN;
+               }
+       map_val = chan->channel + TOTAL_CHANNELS;
 
        /*
         * When the sub-system is first enabled,
@@ -170,12 +180,16 @@ static int tiadc_read_raw(struct iio_dev *indio_dev,
        fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT);
        for (i = 0; i < fifo1count; i++) {
                read = tiadc_readl(adc_dev, REG_FIFO1);
-               if (read >> 16 == step) {
-                       *val = read & 0xfff;
+               stepid = read & FIFOREAD_CHNLID_MASK;
+               stepid = stepid >> 0x10;
+
+               if (stepid == map_val) {
+                       read = read & FIFOREAD_DATA_MASK;
                        found = true;
+                       *val = read;
                }
        }
-       am335x_tsc_se_update(adc_dev->mfd_tscadc);
+
        if (found == false)
                return -EBUSY;
        return IIO_VAL_INT;
index ea8a414..0dd9bb8 100644 (file)
@@ -127,12 +127,17 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name,
 void iio_trigger_poll(struct iio_trigger *trig, s64 time)
 {
        int i;
-       if (!trig->use_count)
-               for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
-                       if (trig->subirqs[i].enabled) {
-                               trig->use_count++;
+
+       if (!atomic_read(&trig->use_count)) {
+               atomic_set(&trig->use_count, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+
+               for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+                       if (trig->subirqs[i].enabled)
                                generic_handle_irq(trig->subirq_base + i);
-                       }
+                       else
+                               iio_trigger_notify_done(trig);
+               }
+       }
 }
 EXPORT_SYMBOL(iio_trigger_poll);
 
@@ -146,19 +151,24 @@ EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll);
 void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time)
 {
        int i;
-       if (!trig->use_count)
-               for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++)
-                       if (trig->subirqs[i].enabled) {
-                               trig->use_count++;
+
+       if (!atomic_read(&trig->use_count)) {
+               atomic_set(&trig->use_count, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+
+               for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+                       if (trig->subirqs[i].enabled)
                                handle_nested_irq(trig->subirq_base + i);
-                       }
+                       else
+                               iio_trigger_notify_done(trig);
+               }
+       }
 }
 EXPORT_SYMBOL(iio_trigger_poll_chained);
 
 void iio_trigger_notify_done(struct iio_trigger *trig)
 {
-       trig->use_count--;
-       if (trig->use_count == 0 && trig->ops && trig->ops->try_reenable)
+       if (atomic_dec_and_test(&trig->use_count) && trig->ops &&
+               trig->ops->try_reenable)
                if (trig->ops->try_reenable(trig))
                        /* Missed an interrupt so launch new poll now */
                        iio_trigger_poll(trig, 0);
index f1c279f..7c0f953 100644 (file)
@@ -423,7 +423,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
        struct sockaddr_ib *addr;
        union ib_gid gid, sgid, *dgid;
        u16 pkey, index;
-       u8 port, p;
+       u8 p;
        int i;
 
        cma_dev = NULL;
@@ -443,7 +443,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                if (!memcmp(&gid, dgid, sizeof(gid))) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
-                                       port = p;
+                                       id_priv->id.port_num = p;
                                        goto found;
                                }
 
@@ -451,7 +451,7 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
                                                 dgid->global.subnet_prefix)) {
                                        cma_dev = cur_dev;
                                        sgid = gid;
-                                       port = p;
+                                       id_priv->id.port_num = p;
                                }
                        }
                }
@@ -462,7 +462,6 @@ static int cma_resolve_ib_dev(struct rdma_id_private *id_priv)
 
 found:
        cma_attach_to_dev(id_priv, cma_dev);
-       id_priv->id.port_num = port;
        addr = (struct sockaddr_ib *) cma_src_addr(id_priv);
        memcpy(&addr->sib_addr, &sgid, sizeof sgid);
        cma_translate_ib(addr, &id_priv->id.route.addr.dev_addr);
@@ -880,7 +879,8 @@ static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id
 {
        struct cma_hdr *hdr;
 
-       if (listen_id->route.addr.src_addr.ss_family == AF_IB) {
+       if ((listen_id->route.addr.src_addr.ss_family == AF_IB) &&
+           (ib_event->event == IB_CM_REQ_RECEIVED)) {
                cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path);
                return 0;
        }
@@ -2677,29 +2677,32 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
 {
        struct ib_cm_sidr_req_param req;
        struct ib_cm_id *id;
+       void *private_data;
        int offset, ret;
 
+       memset(&req, 0, sizeof req);
        offset = cma_user_data_offset(id_priv);
        req.private_data_len = offset + conn_param->private_data_len;
        if (req.private_data_len < conn_param->private_data_len)
                return -EINVAL;
 
        if (req.private_data_len) {
-               req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
-               if (!req.private_data)
+               private_data = kzalloc(req.private_data_len, GFP_ATOMIC);
+               if (!private_data)
                        return -ENOMEM;
        } else {
-               req.private_data = NULL;
+               private_data = NULL;
        }
 
        if (conn_param->private_data && conn_param->private_data_len)
-               memcpy((void *) req.private_data + offset,
-                      conn_param->private_data, conn_param->private_data_len);
+               memcpy(private_data + offset, conn_param->private_data,
+                      conn_param->private_data_len);
 
-       if (req.private_data) {
-               ret = cma_format_hdr((void *) req.private_data, id_priv);
+       if (private_data) {
+               ret = cma_format_hdr(private_data, id_priv);
                if (ret)
                        goto out;
+               req.private_data = private_data;
        }
 
        id = ib_create_cm_id(id_priv->id.device, cma_sidr_rep_handler,
@@ -2721,7 +2724,7 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv,
                id_priv->cm_id.ib = NULL;
        }
 out:
-       kfree(req.private_data);
+       kfree(private_data);
        return ret;
 }
 
index dc3fd1e..4c837e6 100644 (file)
@@ -2663,6 +2663,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
        int ret, i;
        struct ib_qp_attr *attr;
        struct ib_qp *qp;
+       u16 pkey_index;
 
        attr = kmalloc(sizeof *attr, GFP_KERNEL);
        if (!attr) {
@@ -2670,6 +2671,11 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
                return -ENOMEM;
        }
 
+       ret = ib_find_pkey(port_priv->device, port_priv->port_num,
+                          IB_DEFAULT_PKEY_FULL, &pkey_index);
+       if (ret)
+               pkey_index = 0;
+
        for (i = 0; i < IB_MAD_QPS_CORE; i++) {
                qp = port_priv->qp_info[i].qp;
                if (!qp)
@@ -2680,7 +2686,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
                 * one is needed for the Reset to Init transition
                 */
                attr->qp_state = IB_QPS_INIT;
-               attr->pkey_index = 0;
+               attr->pkey_index = pkey_index;
                attr->qkey = (qp->qp_num == 0) ? 0 : IB_QP1_QKEY;
                ret = ib_modify_qp(qp, attr, IB_QP_STATE |
                                             IB_QP_PKEY_INDEX | IB_QP_QKEY);
index e87f220..d228383 100644 (file)
@@ -226,6 +226,7 @@ static struct ib_cq *iwch_create_cq(struct ib_device *ibdev, int entries, int ve
                        mm->len = PAGE_ALIGN(((1UL << uresp.size_log2) + 1) *
                                             sizeof(struct t3_cqe));
                        uresp.memsize = mm->len;
+                       uresp.reserved = 0;
                        resplen = sizeof uresp;
                }
                if (ib_copy_to_udata(udata, &uresp, resplen)) {
index 2320404..a4975e1 100644 (file)
@@ -1657,6 +1657,8 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
                if (mm5) {
                        uresp.ma_sync_key = ucontext->key;
                        ucontext->key += PAGE_SIZE;
+               } else {
+                       uresp.ma_sync_key =  0;
                }
                uresp.sq_key = ucontext->key;
                ucontext->key += PAGE_SIZE;
index 4d599ce..f2a3f48 100644 (file)
@@ -1511,8 +1511,14 @@ static int create_pv_sqp(struct mlx4_ib_demux_pv_ctx *ctx,
 
        memset(&attr, 0, sizeof attr);
        attr.qp_state = IB_QPS_INIT;
-       attr.pkey_index =
-               to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
+       ret = 0;
+       if (create_tun)
+               ret = find_slave_port_pkey_ix(to_mdev(ctx->ib_dev), ctx->slave,
+                                             ctx->port, IB_DEFAULT_PKEY_FULL,
+                                             &attr.pkey_index);
+       if (ret || !create_tun)
+               attr.pkey_index =
+                       to_mdev(ctx->ib_dev)->pkeys.virt2phys_pkey[ctx->slave][ctx->port - 1][0];
        attr.qkey = IB_QP1_QKEY;
        attr.port_num = ctx->port;
        ret = ib_modify_qp(tun_qp->qp, &attr, qp_attr_mask_INIT);
index 8000fff..3f831de 100644 (file)
@@ -619,7 +619,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev,
 
        resp.tot_uuars = req.total_num_uuars;
        resp.num_ports = dev->mdev.caps.num_ports;
-       err = ib_copy_to_udata(udata, &resp, sizeof(resp));
+       err = ib_copy_to_udata(udata, &resp,
+                              sizeof(resp) - sizeof(resp.reserved));
        if (err)
                goto out_uars;
 
@@ -1426,7 +1427,8 @@ static int init_one(struct pci_dev *pdev,
        if (err)
                goto err_eqs;
 
-       if (ib_register_device(&dev->ib_dev, NULL))
+       err = ib_register_device(&dev->ib_dev, NULL);
+       if (err)
                goto err_rsrc;
 
        err = create_umr_res(dev);
@@ -1434,8 +1436,9 @@ static int init_one(struct pci_dev *pdev,
                goto err_dev;
 
        for (i = 0; i < ARRAY_SIZE(mlx5_class_attributes); i++) {
-               if (device_create_file(&dev->ib_dev.dev,
-                                      mlx5_class_attributes[i]))
+               err = device_create_file(&dev->ib_dev.dev,
+                                        mlx5_class_attributes[i]);
+               if (err)
                        goto err_umrc;
        }
 
index 16ac54c..045f8cd 100644 (file)
@@ -199,7 +199,7 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,
 
 static int sq_overhead(enum ib_qp_type qp_type)
 {
-       int size;
+       int size = 0;
 
        switch (qp_type) {
        case IB_QPT_XRC_INI:
index 418004c..9020024 100644 (file)
@@ -3570,10 +3570,10 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
        tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
        iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
        nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
-                       " Tcp state = %d, iWARP state = %d\n",
+                       " Tcp state = %s, iWARP state = %s\n",
                        async_event_id,
                        le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
-                       tcp_state, iwarp_state);
+                       nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
 
        aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
        if (aeq_info & NES_AEQE_QP) {
index 8f67fe2..5b53ca5 100644 (file)
@@ -1384,6 +1384,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd,
 
                        if (ibpd->uobject) {
                                uresp.mmap_sq_db_index = nesqp->mmap_sq_db_index;
+                               uresp.mmap_rq_db_index = 0;
                                uresp.actual_sq_size = sq_size;
                                uresp.actual_rq_size = rq_size;
                                uresp.qp_id = nesqp->hwqp.qp_id;
@@ -1767,7 +1768,7 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, int entries,
                resp.cq_id = nescq->hw_cq.cq_number;
                resp.cq_size = nescq->hw_cq.cq_size;
                resp.mmap_db_index = 0;
-               if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+               if (ib_copy_to_udata(udata, &resp, sizeof resp - sizeof resp.reserved)) {
                        nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num);
                        kfree(nescq);
                        return ERR_PTR(-EFAULT);
index a877a8e..f4c587c 100644 (file)
@@ -29,7 +29,6 @@
 #include <net/netevent.h>
 
 #include <rdma/ib_addr.h>
-#include <rdma/ib_cache.h>
 
 #include "ocrdma.h"
 #include "ocrdma_verbs.h"
index dcfbab1..f36630e 100644 (file)
@@ -242,6 +242,7 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
        memset(ctx->ah_tbl.va, 0, map_len);
        ctx->ah_tbl.len = map_len;
 
+       memset(&resp, 0, sizeof(resp));
        resp.ah_tbl_len = ctx->ah_tbl.len;
        resp.ah_tbl_page = ctx->ah_tbl.pa;
 
@@ -253,7 +254,6 @@ struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,
        resp.wqe_size = dev->attr.wqe_size;
        resp.rqe_size = dev->attr.rqe_size;
        resp.dpp_wqe_size = dev->attr.wqe_size;
-       resp.rsvd = 0;
 
        memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver));
        status = ib_copy_to_udata(udata, &resp, sizeof(resp));
@@ -338,6 +338,7 @@ static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd,
        struct ocrdma_alloc_pd_uresp rsp;
        struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx);
 
+       memset(&rsp, 0, sizeof(rsp));
        rsp.id = pd->id;
        rsp.dpp_enabled = pd->dpp_enabled;
        db_page_addr = pd->dev->nic_info.unmapped_db +
@@ -692,6 +693,7 @@ static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,
        struct ocrdma_ucontext *uctx;
        struct ocrdma_create_cq_uresp uresp;
 
+       memset(&uresp, 0, sizeof(uresp));
        uresp.cq_id = cq->id;
        uresp.page_size = cq->len;
        uresp.num_pages = 1;
@@ -1460,6 +1462,7 @@ static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata)
        int status;
        struct ocrdma_create_srq_uresp uresp;
 
+       memset(&uresp, 0, sizeof(uresp));
        uresp.rq_dbid = srq->rq.dbid;
        uresp.num_rq_pages = 1;
        uresp.rq_page_addr[0] = srq->rq.pa;
index 21e8b09..016e742 100644 (file)
@@ -1596,6 +1596,8 @@ static void sdma_7322_p_errors(struct qib_pportdata *ppd, u64 errs)
        struct qib_devdata *dd = ppd->dd;
 
        errs &= QIB_E_P_SDMAERRS;
+       err_decode(ppd->cpspec->sdmamsgbuf, sizeof(ppd->cpspec->sdmamsgbuf),
+                  errs, qib_7322p_error_msgs);
 
        if (errs & QIB_E_P_SDMAUNEXPDATA)
                qib_dev_err(dd, "IB%u:%u SDmaUnexpData\n", dd->unit,
index 32162d3..9b5322d 100644 (file)
@@ -717,7 +717,7 @@ void dump_sdma_state(struct qib_pportdata *ppd)
        struct qib_sdma_txreq *txp, *txpnext;
        __le64 *descqp;
        u64 desc[2];
-       dma_addr_t addr;
+       u64 addr;
        u16 gen, dwlen, dwoffset;
        u16 head, tail, cnt;
 
index 2cfa76f..196b1d1 100644 (file)
@@ -932,12 +932,47 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
        return 0;
 }
 
+/*
+ * Takes whatever value which is in pkey index 0 and updates priv->pkey
+ * returns 0 if the pkey value was changed.
+ */
+static inline int update_parent_pkey(struct ipoib_dev_priv *priv)
+{
+       int result;
+       u16 prev_pkey;
+
+       prev_pkey = priv->pkey;
+       result = ib_query_pkey(priv->ca, priv->port, 0, &priv->pkey);
+       if (result) {
+               ipoib_warn(priv, "ib_query_pkey port %d failed (ret = %d)\n",
+                          priv->port, result);
+               return result;
+       }
+
+       priv->pkey |= 0x8000;
+
+       if (prev_pkey != priv->pkey) {
+               ipoib_dbg(priv, "pkey changed from 0x%x to 0x%x\n",
+                         prev_pkey, priv->pkey);
+               /*
+                * Update the pkey in the broadcast address, while making sure to set
+                * the full membership bit, so that we join the right broadcast group.
+                */
+               priv->dev->broadcast[8] = priv->pkey >> 8;
+               priv->dev->broadcast[9] = priv->pkey & 0xff;
+               return 0;
+       }
+
+       return 1;
+}
+
 static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
                                enum ipoib_flush_level level)
 {
        struct ipoib_dev_priv *cpriv;
        struct net_device *dev = priv->dev;
        u16 new_index;
+       int result;
 
        mutex_lock(&priv->vlan_mutex);
 
@@ -951,6 +986,10 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        mutex_unlock(&priv->vlan_mutex);
 
        if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags)) {
+               /* for non-child devices must check/update the pkey value here */
+               if (level == IPOIB_FLUSH_HEAVY &&
+                   !test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags))
+                       update_parent_pkey(priv);
                ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n");
                return;
        }
@@ -961,21 +1000,32 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
        }
 
        if (level == IPOIB_FLUSH_HEAVY) {
-               if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
-                       clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
-                       ipoib_ib_dev_down(dev, 0);
-                       ipoib_ib_dev_stop(dev, 0);
-                       if (ipoib_pkey_dev_delay_open(dev))
+               /* child devices chase their origin pkey value, while non-child
+                * (parent) devices should always takes what present in pkey index 0
+                */
+               if (test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
+                       if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) {
+                               clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
+                               ipoib_ib_dev_down(dev, 0);
+                               ipoib_ib_dev_stop(dev, 0);
+                               if (ipoib_pkey_dev_delay_open(dev))
+                                       return;
+                       }
+                       /* restart QP only if P_Key index is changed */
+                       if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
+                           new_index == priv->pkey_index) {
+                               ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
                                return;
+                       }
+                       priv->pkey_index = new_index;
+               } else {
+                       result = update_parent_pkey(priv);
+                       /* restart QP only if P_Key value changed */
+                       if (result) {
+                               ipoib_dbg(priv, "Not flushing - P_Key value not changed.\n");
+                               return;
+                       }
                }
-
-               /* restart QP only if P_Key index is changed */
-               if (test_and_set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags) &&
-                   new_index == priv->pkey_index) {
-                       ipoib_dbg(priv, "Not flushing - P_Key index not changed.\n");
-                       return;
-               }
-               priv->pkey_index = new_index;
        }
 
        if (level == IPOIB_FLUSH_LIGHT) {
index b6e049a..c6f71a8 100644 (file)
@@ -1461,7 +1461,7 @@ static ssize_t create_child(struct device *dev,
        if (sscanf(buf, "%i", &pkey) != 1)
                return -EINVAL;
 
-       if (pkey < 0 || pkey > 0xffff)
+       if (pkey <= 0 || pkey > 0xffff || pkey == 0x8000)
                return -EINVAL;
 
        /*
index 7468593..f81abe1 100644 (file)
@@ -119,6 +119,15 @@ static int ipoib_new_child_link(struct net *src_net, struct net_device *dev,
        } else
                child_pkey  = nla_get_u16(data[IFLA_IPOIB_PKEY]);
 
+       if (child_pkey == 0 || child_pkey == 0x8000)
+               return -EINVAL;
+
+       /*
+        * Set the full membership bit, so that we join the right
+        * broadcast group, etc.
+        */
+       child_pkey |= 0x8000;
+
        err = __ipoib_vlan_add(ppriv, netdev_priv(dev), child_pkey, IPOIB_RTNL_CHILD);
 
        if (!err && data)
index 0b9a79b..82fc86a 100644 (file)
@@ -439,15 +439,15 @@ static void backside_setup_pid(void)
 
 /* Slots fan */
 static const struct wf_pid_param slots_param = {
-       .interval       = 5,
-       .history_len    = 2,
-       .gd             = 30 << 20,
-       .gp             = 5 << 20,
-       .gr             = 0,
-       .itarget        = 40 << 16,
-       .additive       = 1,
-       .min            = 300,
-       .max            = 4000,
+       .interval       = 1,
+       .history_len    = 20,
+       .gd             = 0,
+       .gp             = 0,
+       .gr             = 0x00100000,
+       .itarget        = 3200000,
+       .additive       = 0,
+       .min            = 20,
+       .max            = 100,
 };
 
 static void slots_fan_tick(void)
index efdc873..a985702 100644 (file)
@@ -117,7 +117,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
        struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
+       int ret = -EINVAL;
 
        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
@@ -157,7 +157,7 @@ static int ml86v7667_s_ctrl(struct v4l2_ctrl *ctrl)
                break;
        }
 
-       return 0;
+       return ret;
 }
 
 static int ml86v7667_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
index df4ada8..bd9405d 100644 (file)
@@ -1987,7 +1987,7 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids);
 
 #ifdef CONFIG_OF
 static const struct of_device_id coda_dt_ids[] = {
-       { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] },
+       { .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
        { .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
        { /* sentinel */ }
 };
index 553d87e..fd6289d 100644 (file)
@@ -784,6 +784,7 @@ static int g2d_probe(struct platform_device *pdev)
        }
        *vfd = g2d_videodev;
        vfd->lock = &dev->mutex;
+       vfd->v4l2_dev = &dev->v4l2_dev;
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
        if (ret) {
                v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
index 5296385..4f6dd42 100644 (file)
@@ -344,7 +344,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
                pix_mp->num_planes = 2;
                /* Set pixelformat to the format in which MFC
                   outputs the decoded frame */
-               pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT;
+               pix_mp->pixelformat = ctx->dst_fmt->fourcc;
                pix_mp->plane_fmt[0].bytesperline = ctx->buf_width;
                pix_mp->plane_fmt[0].sizeimage = ctx->luma_size;
                pix_mp->plane_fmt[1].bytesperline = ctx->buf_width;
@@ -382,10 +382,16 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        mfc_err("Unsupported format for source.\n");
                        return -EINVAL;
                }
-               if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
-                       mfc_err("Not supported format.\n");
+               if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) {
+                       mfc_err("Unknown codec\n");
                        return -EINVAL;
                }
+               if (!IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               }
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
                fmt = find_format(f, MFC_FMT_RAW);
                if (!fmt) {
@@ -411,7 +417,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
        int ret = 0;
-       struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_mp;
 
        mfc_debug_enter();
@@ -425,54 +430,32 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                goto out;
        }
        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               fmt = find_format(f, MFC_FMT_RAW);
-               if (!fmt) {
-                       mfc_err("Unsupported format for source.\n");
-                       return -EINVAL;
-               }
-               if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               } else if (IS_MFCV6(dev) &&
-                               (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               }
-               ctx->dst_fmt = fmt;
-               mfc_debug_leave();
-               return ret;
-       } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               mfc_err("Wrong type error for S_FMT : %d", f->type);
-               return -EINVAL;
-       }
-       fmt = find_format(f, MFC_FMT_DEC);
-       if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) {
-               mfc_err("Unknown codec\n");
-               ret = -EINVAL;
+               /* dst_fmt is validated by call to vidioc_try_fmt */
+               ctx->dst_fmt = find_format(f, MFC_FMT_RAW);
+               ret = 0;
                goto out;
-       }
-       if (fmt->type != MFC_FMT_DEC) {
-               mfc_err("Wrong format selected, you should choose "
-                                       "format for decoding\n");
+       } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+               /* src_fmt is validated by call to vidioc_try_fmt */
+               ctx->src_fmt = find_format(f, MFC_FMT_DEC);
+               ctx->codec_mode = ctx->src_fmt->codec_mode;
+               mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
+               pix_mp->height = 0;
+               pix_mp->width = 0;
+               if (pix_mp->plane_fmt[0].sizeimage)
+                       ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
+               else
+                       pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
+                                                               DEF_CPB_SIZE;
+               pix_mp->plane_fmt[0].bytesperline = 0;
+               ctx->state = MFCINST_INIT;
+               ret = 0;
+               goto out;
+       } else {
+               mfc_err("Wrong type error for S_FMT : %d", f->type);
                ret = -EINVAL;
                goto out;
        }
-       if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
-               mfc_err("Not supported format.\n");
-               return -EINVAL;
-       }
-       ctx->src_fmt = fmt;
-       ctx->codec_mode = fmt->codec_mode;
-       mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
-       pix_mp->height = 0;
-       pix_mp->width = 0;
-       if (pix_mp->plane_fmt[0].sizeimage)
-               ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
-       else
-               pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
-                                                               DEF_CPB_SIZE;
-       pix_mp->plane_fmt[0].bytesperline = 0;
-       ctx->state = MFCINST_INIT;
+
 out:
        mfc_debug_leave();
        return ret;
index 2549967..59e56f4 100644 (file)
@@ -906,6 +906,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
 
 static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
+       struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
 
@@ -930,6 +931,18 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
                        return -EINVAL;
                }
 
+               if (!IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               } else if (IS_MFCV6(dev)) {
+                       if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
+                               mfc_err("Not supported format.\n");
+                               return -EINVAL;
+                       }
+               }
+
                if (fmt->num_planes != pix_fmt_mp->num_planes) {
                        mfc_err("failed to try output format\n");
                        return -EINVAL;
@@ -947,7 +960,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
 {
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
-       struct s5p_mfc_fmt *fmt;
        struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
        int ret = 0;
 
@@ -960,13 +972,9 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                goto out;
        }
        if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-               fmt = find_format(f, MFC_FMT_ENC);
-               if (!fmt) {
-                       mfc_err("failed to set capture format\n");
-                       return -EINVAL;
-               }
+               /* dst_fmt is validated by call to vidioc_try_fmt */
+               ctx->dst_fmt = find_format(f, MFC_FMT_ENC);
                ctx->state = MFCINST_INIT;
-               ctx->dst_fmt = fmt;
                ctx->codec_mode = ctx->dst_fmt->codec_mode;
                ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
                pix_fmt_mp->plane_fmt[0].bytesperline = 0;
@@ -987,28 +995,8 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
                }
                mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
        } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-               fmt = find_format(f, MFC_FMT_RAW);
-               if (!fmt) {
-                       mfc_err("failed to set output format\n");
-                       return -EINVAL;
-               }
-
-               if (!IS_MFCV6(dev) &&
-                               (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               } else if (IS_MFCV6(dev) &&
-                               (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
-                       mfc_err("Not supported format.\n");
-                       return -EINVAL;
-               }
-
-               if (fmt->num_planes != pix_fmt_mp->num_planes) {
-                       mfc_err("failed to set output format\n");
-                       ret = -EINVAL;
-                       goto out;
-               }
-               ctx->src_fmt = fmt;
+               /* src_fmt is validated by call to vidioc_try_fmt */
+               ctx->src_fmt = find_format(f, MFC_FMT_RAW);
                ctx->img_width = pix_fmt_mp->width;
                ctx->img_height = pix_fmt_mp->height;
                mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
index 4851cc2..c4ff973 100644 (file)
@@ -726,7 +726,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
 
        *eedata = data;
        *eedata_len = len;
-       dev_config = (void *)eedata;
+       dev_config = (void *)*eedata;
 
        switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) {
        case 0:
index cb69405..6e50707 100644 (file)
@@ -303,6 +303,11 @@ static int hdpvr_probe(struct usb_interface *interface,
 
        dev->workqueue = 0;
 
+       /* init video transfer queues first of all */
+       /* to prevent oops in hdpvr_delete() on error paths */
+       INIT_LIST_HEAD(&dev->free_buff_list);
+       INIT_LIST_HEAD(&dev->rec_buff_list);
+
        /* register v4l2_device early so it can be used for printks */
        if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
                dev_err(&interface->dev, "v4l2_device_register failed\n");
@@ -325,10 +330,6 @@ static int hdpvr_probe(struct usb_interface *interface,
        if (!dev->workqueue)
                goto error;
 
-       /* init video transfer queues */
-       INIT_LIST_HEAD(&dev->free_buff_list);
-       INIT_LIST_HEAD(&dev->rec_buff_list);
-
        dev->options = hdpvr_default_options;
 
        if (default_video_input < HDPVR_VIDEO_INPUTS)
@@ -405,7 +406,7 @@ static int hdpvr_probe(struct usb_interface *interface,
                                    video_nr[atomic_inc_return(&dev_nr)]);
        if (retval < 0) {
                v4l2_err(&dev->v4l2_dev, "registering videodev failed\n");
-               goto error;
+               goto reg_fail;
        }
 
        /* let the user know what node this device is now attached to */
index 8864436..7c5b860 100644 (file)
@@ -1,6 +1,6 @@
 config VIDEO_USBTV
         tristate "USBTV007 video capture support"
-        depends on VIDEO_DEV
+        depends on VIDEO_V4L2
         select VIDEOBUF2_VMALLOC
 
         ---help---
index bf43f87..9165017 100644 (file)
@@ -57,7 +57,7 @@
 #define USBTV_CHUNK_SIZE       256
 #define USBTV_CHUNK            240
 #define USBTV_CHUNKS           (USBTV_WIDTH * USBTV_HEIGHT \
-                                       / 2 / USBTV_CHUNK)
+                                       / 4 / USBTV_CHUNK)
 
 /* Chunk header. */
 #define USBTV_MAGIC_OK(chunk)  ((be32_to_cpu(chunk[0]) & 0xff000000) \
@@ -89,6 +89,7 @@ struct usbtv {
        /* Number of currently processed frame, useful find
         * out when a new one begins. */
        u32 frame_id;
+       int chunks_done;
 
        int iso_size;
        unsigned int sequence;
@@ -202,6 +203,26 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
        return 0;
 }
 
+/* Copy data from chunk into a frame buffer, deinterlacing the data
+ * into every second line. Unfortunately, they don't align nicely into
+ * 720 pixel lines, as the chunk is 240 words long, which is 480 pixels.
+ * Therefore, we break down the chunk into two halves before copyting,
+ * so that we can interleave a line if needed. */
+static void usbtv_chunk_to_vbuf(u32 *frame, u32 *src, int chunk_no, int odd)
+{
+       int half;
+
+       for (half = 0; half < 2; half++) {
+               int part_no = chunk_no * 2 + half;
+               int line = part_no / 3;
+               int part_index = (line * 2 + !odd) * 3 + (part_no % 3);
+
+               u32 *dst = &frame[part_index * USBTV_CHUNK/2];
+               memcpy(dst, src, USBTV_CHUNK/2 * sizeof(*src));
+               src += USBTV_CHUNK/2;
+       }
+}
+
 /* Called for each 256-byte image chunk.
  * First word identifies the chunk, followed by 240 words of image
  * data and padding. */
@@ -218,17 +239,17 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
        frame_id = USBTV_FRAME_ID(chunk);
        odd = USBTV_ODD(chunk);
        chunk_no = USBTV_CHUNK_NO(chunk);
-
-       /* Deinterlace. TODO: Use interlaced frame format. */
-       chunk_no = (chunk_no - chunk_no % 3) * 2 + chunk_no % 3;
-       chunk_no += !odd * 3;
-
        if (chunk_no >= USBTV_CHUNKS)
                return;
 
        /* Beginning of a frame. */
-       if (chunk_no == 0)
+       if (chunk_no == 0) {
                usbtv->frame_id = frame_id;
+               usbtv->chunks_done = 0;
+       }
+
+       if (usbtv->frame_id != frame_id)
+               return;
 
        spin_lock_irqsave(&usbtv->buflock, flags);
        if (list_empty(&usbtv->bufs)) {
@@ -241,19 +262,23 @@ static void usbtv_image_chunk(struct usbtv *usbtv, u32 *chunk)
        buf = list_first_entry(&usbtv->bufs, struct usbtv_buf, list);
        frame = vb2_plane_vaddr(&buf->vb, 0);
 
-       /* Copy the chunk. */
-       memcpy(&frame[chunk_no * USBTV_CHUNK], &chunk[1],
-                       USBTV_CHUNK * sizeof(chunk[1]));
+       /* Copy the chunk data. */
+       usbtv_chunk_to_vbuf(frame, &chunk[1], chunk_no, odd);
+       usbtv->chunks_done++;
 
        /* Last chunk in a frame, signalling an end */
-       if (usbtv->frame_id && chunk_no == USBTV_CHUNKS-1) {
+       if (odd && chunk_no == USBTV_CHUNKS-1) {
                int size = vb2_plane_size(&buf->vb, 0);
+               enum vb2_buffer_state state = usbtv->chunks_done ==
+                                               USBTV_CHUNKS ?
+                                               VB2_BUF_STATE_DONE :
+                                               VB2_BUF_STATE_ERROR;
 
                buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
                buf->vb.v4l2_buf.sequence = usbtv->sequence++;
                v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
                vb2_set_plane_payload(&buf->vb, 0, size);
-               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+               vb2_buffer_done(&buf->vb, state);
                list_del(&buf->list);
        }
 
@@ -518,7 +543,7 @@ static int usbtv_queue_setup(struct vb2_queue *vq,
        if (*nbuffers < 2)
                *nbuffers = 2;
        *nplanes = 1;
-       sizes[0] = USBTV_CHUNK * USBTV_CHUNKS * sizeof(u32);
+       sizes[0] = USBTV_WIDTH * USBTV_HEIGHT / 2 * sizeof(u32);
 
        return 0;
 }
index a746ba2..a956053 100644 (file)
@@ -1007,7 +1007,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
 
        soft = &pkt.soft.rfc1201;
 
-       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, sizeof(ARC_HDR_SIZE));
+       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
        if (pkt.hard.offset[0]) {
                ofs = pkt.hard.offset[0];
                length = 256 - ofs;
index 07f257d..e48cb33 100644 (file)
@@ -3714,11 +3714,17 @@ static int bond_neigh_init(struct neighbour *n)
  * The bonding ndo_neigh_setup is called at init time beofre any
  * slave exists. So we must declare proxy setup function which will
  * be used at run time to resolve the actual slave neigh param setup.
+ *
+ * It's also called by master devices (such as vlans) to setup their
+ * underlying devices. In that case - do nothing, we're already set up from
+ * our init.
  */
 static int bond_neigh_setup(struct net_device *dev,
                            struct neigh_parms *parms)
 {
-       parms->neigh_setup   = bond_neigh_init;
+       /* modify only our neigh_parms */
+       if (parms->dev == dev)
+               parms->neigh_setup = bond_neigh_init;
 
        return 0;
 }
index 6aa7b32..ac6177d 100644 (file)
@@ -412,10 +412,20 @@ static void esd_usb2_read_bulk_callback(struct urb *urb)
 
                switch (msg->msg.hdr.cmd) {
                case CMD_CAN_RX:
+                       if (msg->msg.rx.net >= dev->net_count) {
+                               dev_err(dev->udev->dev.parent, "format error\n");
+                               break;
+                       }
+
                        esd_usb2_rx_can_msg(dev->nets[msg->msg.rx.net], msg);
                        break;
 
                case CMD_CAN_TX:
+                       if (msg->msg.txdone.net >= dev->net_count) {
+                               dev_err(dev->udev->dev.parent, "format error\n");
+                               break;
+                       }
+
                        esd_usb2_tx_done_msg(dev->nets[msg->msg.txdone.net],
                                             msg);
                        break;
index 25723d8..925ab8e 100644 (file)
@@ -649,7 +649,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
                if ((mc->ptr + rec_len) > mc->end)
                        goto decode_failed;
 
-               memcpy(cf->data, mc->ptr, rec_len);
+               memcpy(cf->data, mc->ptr, cf->can_dlc);
                mc->ptr += rec_len;
        }
 
index cbd388e..8becd3d 100644 (file)
@@ -779,6 +779,7 @@ static int usb_8dev_start(struct usb_8dev_priv *priv)
                        usb_unanchor_urb(urb);
                        usb_free_coherent(priv->udev, RX_BUFFER_SIZE, buf,
                                          urb->transfer_dma);
+                       usb_free_urb(urb);
                        break;
                }
 
index 53ad213..d8d95d4 100644 (file)
@@ -3,19 +3,20 @@
 #
 
 config NET_VENDOR_ALLWINNER
-       bool "Allwinner devices"
-       default y
-       depends on ARCH_SUNXI
-       ---help---
-         If you have a network (Ethernet) card belonging to this
-        class, say Y and read the Ethernet-HOWTO, available from
-        <http://www.tldp.org/docs.html#howto>.
+       bool "Allwinner devices"
+       default y
 
-        Note that the answer to this question doesn't directly
-        affect the kernel: saying N will just cause the configurator
-        to skip all the questions about Allwinner cards. If you say Y,
-        you will be asked for your specific card in the following
-        questions.
+       depends on ARCH_SUNXI
+       ---help---
+         If you have a network (Ethernet) card belonging to this
+         class, say Y and read the Ethernet-HOWTO, available from
+         <http://www.tldp.org/docs.html#howto>.
+
+         Note that the answer to this question doesn't directly
+         affect the kernel: saying N will just cause the configurator
+         to skip all the questions about Allwinner cards. If you say Y,
+         you will be asked for your specific card in the following
+         questions.
 
 if NET_VENDOR_ALLWINNER
 
@@ -26,6 +27,7 @@ config SUN4I_EMAC
        select CRC32
        select MII
        select PHYLIB
+       select MDIO_SUN4I
         ---help---
           Support for Allwinner A10 EMAC ethernet driver.
 
index f1b121e..55d79cb 100644 (file)
@@ -199,7 +199,7 @@ static int arc_emac_rx(struct net_device *ndev, int budget)
        struct arc_emac_priv *priv = netdev_priv(ndev);
        unsigned int work_done;
 
-       for (work_done = 0; work_done <= budget; work_done++) {
+       for (work_done = 0; work_done < budget; work_done++) {
                unsigned int *last_rx_bd = &priv->last_rx_bd;
                struct net_device_stats *stats = &priv->stats;
                struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd];
index b2bf324..0f05565 100644 (file)
@@ -520,6 +520,9 @@ struct atl1c_adapter {
        struct net_device   *netdev;
        struct pci_dev      *pdev;
        struct napi_struct  napi;
+       struct page         *rx_page;
+       unsigned int        rx_page_offset;
+       unsigned int        rx_frag_size;
        struct atl1c_hw        hw;
        struct atl1c_hw_stats  hw_stats;
        struct mii_if_info  mii;    /* MII interface info */
index 786a874..a36a760 100644 (file)
@@ -481,10 +481,15 @@ static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
 static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
                                struct net_device *dev)
 {
+       unsigned int head_size;
        int mtu = dev->mtu;
 
        adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
                roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
+
+       head_size = SKB_DATA_ALIGN(adapter->rx_buffer_len + NET_SKB_PAD) +
+                   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       adapter->rx_frag_size = roundup_pow_of_two(head_size);
 }
 
 static netdev_features_t atl1c_fix_features(struct net_device *netdev,
@@ -952,6 +957,10 @@ static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
                kfree(adapter->tpd_ring[0].buffer_info);
                adapter->tpd_ring[0].buffer_info = NULL;
        }
+       if (adapter->rx_page) {
+               put_page(adapter->rx_page);
+               adapter->rx_page = NULL;
+       }
 }
 
 /**
@@ -1639,6 +1648,35 @@ static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
        skb_checksum_none_assert(skb);
 }
 
+static struct sk_buff *atl1c_alloc_skb(struct atl1c_adapter *adapter)
+{
+       struct sk_buff *skb;
+       struct page *page;
+
+       if (adapter->rx_frag_size > PAGE_SIZE)
+               return netdev_alloc_skb(adapter->netdev,
+                                       adapter->rx_buffer_len);
+
+       page = adapter->rx_page;
+       if (!page) {
+               adapter->rx_page = page = alloc_page(GFP_ATOMIC);
+               if (unlikely(!page))
+                       return NULL;
+               adapter->rx_page_offset = 0;
+       }
+
+       skb = build_skb(page_address(page) + adapter->rx_page_offset,
+                       adapter->rx_frag_size);
+       if (likely(skb)) {
+               adapter->rx_page_offset += adapter->rx_frag_size;
+               if (adapter->rx_page_offset >= PAGE_SIZE)
+                       adapter->rx_page = NULL;
+               else
+                       get_page(page);
+       }
+       return skb;
+}
+
 static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
 {
        struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring;
@@ -1660,7 +1698,7 @@ static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter)
        while (next_info->flags & ATL1C_BUFFER_FREE) {
                rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
 
-               skb = netdev_alloc_skb(adapter->netdev, adapter->rx_buffer_len);
+               skb = atl1c_alloc_skb(adapter);
                if (unlikely(!skb)) {
                        if (netif_msg_rx_err(adapter))
                                dev_warn(&pdev->dev, "alloc rx buffer failed\n");
index dedbd76..ce9b387 100644 (file)
@@ -486,7 +486,7 @@ struct bnx2x_fastpath {
 
        struct napi_struct      napi;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define BNX2X_FP_STATE_IDLE                  0
 #define BNX2X_FP_STATE_NAPI            (1 << 0)    /* NAPI owns this FP */
@@ -498,7 +498,7 @@ struct bnx2x_fastpath {
 #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD)
        /* protect state */
        spinlock_t lock;
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
        union host_hc_status_block      status_blk;
        /* chip independent shortcuts into sb structure */
@@ -572,7 +572,7 @@ struct bnx2x_fastpath {
 #define bnx2x_fp_stats(bp, fp) (&((bp)->fp_stats[(fp)->index]))
 #define bnx2x_fp_qstats(bp, fp)        (&((bp)->fp_stats[(fp)->index].eth_q_stats))
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp)
 {
        spin_lock_init(&fp->lock);
@@ -680,7 +680,7 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /* Use 2500 as a mini-jumbo MTU for FCoE */
 #define BNX2X_FCOE_MINI_JUMBO_MTU      2500
@@ -1502,6 +1502,7 @@ struct bnx2x {
 #define BC_SUPPORTS_DCBX_MSG_NON_PMF   (1 << 21)
 #define IS_VF_FLAG                     (1 << 22)
 #define INTERRUPTS_ENABLED_FLAG                (1 << 23)
+#define BC_SUPPORTS_RMMOD_CMD          (1 << 24)
 
 #define BP_NOMCP(bp)                   ((bp)->flags & NO_MCP_FLAG)
 
@@ -1830,6 +1831,8 @@ struct bnx2x {
 
        int fp_array_size;
        u32 dump_preset_idx;
+       bool                                    stats_started;
+       struct semaphore                        stats_sema;
 };
 
 /* Tx queues may be less or equal to Rx queues */
@@ -2451,4 +2454,6 @@ enum bnx2x_pci_bus_speed {
        BNX2X_PCI_LINK_SPEED_5000 = 5000,
        BNX2X_PCI_LINK_SPEED_8000 = 8000
 };
+
+void bnx2x_set_local_cmng(struct bnx2x *bp);
 #endif /* bnx2x.h */
index ee350bd..f2d1ff1 100644 (file)
@@ -3117,7 +3117,7 @@ int bnx2x_poll(struct napi_struct *napi, int budget)
        return work_done;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 int bnx2x_low_latency_recv(struct napi_struct *napi)
 {
index 0c94df4..f9122f2 100644 (file)
@@ -753,6 +753,10 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
                bnx2x_pfc_set_pfc(bp);
 
                bnx2x_dcbx_update_ets_params(bp);
+
+               /* ets may affect cmng configuration: reinit it in hw */
+               bnx2x_set_local_cmng(bp);
+
                bnx2x_dcbx_resume_hw_tx(bp);
 
                return;
index 5018e52..32767f6 100644 (file)
@@ -1300,6 +1300,9 @@ struct drv_func_mb {
 
        #define DRV_MSG_CODE_EEE_RESULTS_ACK            0xda000000
 
+       #define DRV_MSG_CODE_RMMOD                      0xdb000000
+       #define REQ_BC_VER_4_RMMOD_CMD                  0x0007080f
+
        #define DRV_MSG_CODE_SET_MF_BW                  0xe0000000
        #define REQ_BC_VER_4_SET_MF_BW                  0x00060202
        #define DRV_MSG_CODE_SET_MF_BW_ACK              0xe1000000
@@ -1372,6 +1375,8 @@ struct drv_func_mb {
 
        #define FW_MSG_CODE_EEE_RESULS_ACK              0xda100000
 
+       #define FW_MSG_CODE_RMMOD_ACK                   0xdb100000
+
        #define FW_MSG_CODE_SET_MF_BW_SENT              0xe0000000
        #define FW_MSG_CODE_SET_MF_BW_DONE              0xe1000000
 
index e5da078..955d6cf 100644 (file)
@@ -2476,7 +2476,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type)
 
        input.port_rate = bp->link_vars.line_speed;
 
-       if (cmng_type == CMNG_FNS_MINMAX) {
+       if (cmng_type == CMNG_FNS_MINMAX && input.port_rate) {
                int vn;
 
                /* read mf conf from shmem */
@@ -2533,6 +2533,21 @@ static void storm_memset_cmng(struct bnx2x *bp,
        }
 }
 
+/* init cmng mode in HW according to local configuration */
+void bnx2x_set_local_cmng(struct bnx2x *bp)
+{
+       int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
+
+       if (cmng_fns != CMNG_FNS_NONE) {
+               bnx2x_cmng_fns_init(bp, false, cmng_fns);
+               storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
+       } else {
+               /* rate shaping and fairness are disabled */
+               DP(NETIF_MSG_IFUP,
+                  "single function mode without fairness\n");
+       }
+}
+
 /* This function is called upon link interrupt */
 static void bnx2x_link_attn(struct bnx2x *bp)
 {
@@ -2568,17 +2583,8 @@ static void bnx2x_link_attn(struct bnx2x *bp)
                        bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP);
        }
 
-       if (bp->link_vars.link_up && bp->link_vars.line_speed) {
-               int cmng_fns = bnx2x_get_cmng_fns_mode(bp);
-
-               if (cmng_fns != CMNG_FNS_NONE) {
-                       bnx2x_cmng_fns_init(bp, false, cmng_fns);
-                       storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp));
-               } else
-                       /* rate shaping and fairness are disabled */
-                       DP(NETIF_MSG_IFUP,
-                          "single function mode without fairness\n");
-       }
+       if (bp->link_vars.link_up && bp->link_vars.line_speed)
+               bnx2x_set_local_cmng(bp);
 
        __bnx2x_link_report(bp);
 
@@ -10362,6 +10368,10 @@ static void bnx2x_get_common_hwinfo(struct bnx2x *bp)
 
        bp->flags |= (val >= REQ_BC_VER_4_DCBX_ADMIN_MSG_NON_PMF) ?
                        BC_SUPPORTS_DCBX_MSG_NON_PMF : 0;
+
+       bp->flags |= (val >= REQ_BC_VER_4_RMMOD_CMD) ?
+                       BC_SUPPORTS_RMMOD_CMD : 0;
+
        boot_mode = SHMEM_RD(bp,
                        dev_info.port_feature_config[BP_PORT(bp)].mba_config) &
                        PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK;
@@ -11524,6 +11534,7 @@ static int bnx2x_init_bp(struct bnx2x *bp)
        mutex_init(&bp->port.phy_mutex);
        mutex_init(&bp->fw_mb_mutex);
        spin_lock_init(&bp->stats_lock);
+       sema_init(&bp->stats_sema, 1);
 
        INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
        INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task);
@@ -12026,7 +12037,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
        .ndo_fcoe_get_wwn       = bnx2x_fcoe_get_wwn,
 #endif
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = bnx2x_low_latency_recv,
 #endif
 };
@@ -12817,13 +12828,17 @@ static void __bnx2x_remove(struct pci_dev *pdev,
        bnx2x_dcbnl_update_applist(bp, true);
 #endif
 
+       if (IS_PF(bp) &&
+           !BP_NOMCP(bp) &&
+           (bp->flags & BC_SUPPORTS_RMMOD_CMD))
+               bnx2x_fw_command(bp, DRV_MSG_CODE_RMMOD, 0);
+
        /* Close the interface - either directly or implicitly */
        if (remove_netdev) {
                unregister_netdev(dev);
        } else {
                rtnl_lock();
-               if (netif_running(dev))
-                       bnx2x_close(dev);
+               dev_close(dev);
                rtnl_unlock();
        }
 
index 95861ef..44104fb 100644 (file)
@@ -3463,7 +3463,7 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp)
 alloc_mem_err:
        BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
                       sizeof(struct bnx2x_vf_mbx_msg));
-       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+       BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->pf2vf_bulletin_mapping,
                       sizeof(union pf_vf_bulletin));
        return -ENOMEM;
 }
index 98366ab..d63d132 100644 (file)
@@ -221,7 +221,8 @@ static int bnx2x_stats_comp(struct bnx2x *bp)
  * Statistics service functions
  */
 
-static void bnx2x_stats_pmf_update(struct bnx2x *bp)
+/* should be called under stats_sema */
+static void __bnx2x_stats_pmf_update(struct bnx2x *bp)
 {
        struct dmae_command *dmae;
        u32 opcode;
@@ -518,7 +519,8 @@ static void bnx2x_func_stats_init(struct bnx2x *bp)
        *stats_comp = 0;
 }
 
-static void bnx2x_stats_start(struct bnx2x *bp)
+/* should be called under stats_sema */
+static void __bnx2x_stats_start(struct bnx2x *bp)
 {
        /* vfs travel through here as part of the statistics FSM, but no action
         * is required
@@ -534,13 +536,34 @@ static void bnx2x_stats_start(struct bnx2x *bp)
 
        bnx2x_hw_stats_post(bp);
        bnx2x_storm_stats_post(bp);
+
+       bp->stats_started = true;
+}
+
+static void bnx2x_stats_start(struct bnx2x *bp)
+{
+       if (down_timeout(&bp->stats_sema, HZ/10))
+               BNX2X_ERR("Unable to acquire stats lock\n");
+       __bnx2x_stats_start(bp);
+       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_pmf_start(struct bnx2x *bp)
 {
+       if (down_timeout(&bp->stats_sema, HZ/10))
+               BNX2X_ERR("Unable to acquire stats lock\n");
        bnx2x_stats_comp(bp);
-       bnx2x_stats_pmf_update(bp);
-       bnx2x_stats_start(bp);
+       __bnx2x_stats_pmf_update(bp);
+       __bnx2x_stats_start(bp);
+       up(&bp->stats_sema);
+}
+
+static void bnx2x_stats_pmf_update(struct bnx2x *bp)
+{
+       if (down_timeout(&bp->stats_sema, HZ/10))
+               BNX2X_ERR("Unable to acquire stats lock\n");
+       __bnx2x_stats_pmf_update(bp);
+       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_restart(struct bnx2x *bp)
@@ -550,8 +573,11 @@ static void bnx2x_stats_restart(struct bnx2x *bp)
         */
        if (IS_VF(bp))
                return;
+       if (down_timeout(&bp->stats_sema, HZ/10))
+               BNX2X_ERR("Unable to acquire stats lock\n");
        bnx2x_stats_comp(bp);
-       bnx2x_stats_start(bp);
+       __bnx2x_stats_start(bp);
+       up(&bp->stats_sema);
 }
 
 static void bnx2x_bmac_stats_update(struct bnx2x *bp)
@@ -888,9 +914,7 @@ static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp)
        /* Make sure we use the value of the counter
         * used for sending the last stats ramrod.
         */
-       spin_lock_bh(&bp->stats_lock);
        cur_stats_counter = bp->stats_counter - 1;
-       spin_unlock_bh(&bp->stats_lock);
 
        /* are storm stats valid? */
        if (le16_to_cpu(counters->xstats_counter) != cur_stats_counter) {
@@ -1227,12 +1251,18 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 {
        u32 *stats_comp = bnx2x_sp(bp, stats_comp);
 
-       if (bnx2x_edebug_stats_stopped(bp))
+       /* we run update from timer context, so give up
+        * if somebody is in the middle of transition
+        */
+       if (down_trylock(&bp->stats_sema))
                return;
 
+       if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started)
+               goto out;
+
        if (IS_PF(bp)) {
                if (*stats_comp != DMAE_COMP_VAL)
-                       return;
+                       goto out;
 
                if (bp->port.pmf)
                        bnx2x_hw_stats_update(bp);
@@ -1242,7 +1272,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
                                BNX2X_ERR("storm stats were not updated for 3 times\n");
                                bnx2x_panic();
                        }
-                       return;
+                       goto out;
                }
        } else {
                /* vf doesn't collect HW statistics, and doesn't get completions
@@ -1256,7 +1286,7 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        /* vf is done */
        if (IS_VF(bp))
-               return;
+               goto out;
 
        if (netif_msg_timer(bp)) {
                struct bnx2x_eth_stats *estats = &bp->eth_stats;
@@ -1267,6 +1297,9 @@ static void bnx2x_stats_update(struct bnx2x *bp)
 
        bnx2x_hw_stats_post(bp);
        bnx2x_storm_stats_post(bp);
+
+out:
+       up(&bp->stats_sema);
 }
 
 static void bnx2x_port_stats_stop(struct bnx2x *bp)
@@ -1332,6 +1365,11 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
 {
        int update = 0;
 
+       if (down_timeout(&bp->stats_sema, HZ/10))
+               BNX2X_ERR("Unable to acquire stats lock\n");
+
+       bp->stats_started = false;
+
        bnx2x_stats_comp(bp);
 
        if (bp->port.pmf)
@@ -1348,6 +1386,8 @@ static void bnx2x_stats_stop(struct bnx2x *bp)
                bnx2x_hw_stats_post(bp);
                bnx2x_stats_comp(bp);
        }
+
+       up(&bp->stats_sema);
 }
 
 static void bnx2x_stats_do_nothing(struct bnx2x *bp)
@@ -1376,15 +1416,17 @@ static const struct {
 void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
 {
        enum bnx2x_stats_state state;
+       void (*action)(struct bnx2x *bp);
        if (unlikely(bp->panic))
                return;
 
        spin_lock_bh(&bp->stats_lock);
        state = bp->stats_state;
        bp->stats_state = bnx2x_stats_stm[state][event].next_state;
+       action = bnx2x_stats_stm[state][event].action;
        spin_unlock_bh(&bp->stats_lock);
 
-       bnx2x_stats_stm[state][event].action(bp);
+       action(bp);
 
        if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
                DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
index d964f30..0da2214 100644 (file)
@@ -17625,7 +17625,8 @@ err_out_free_res:
        pci_release_regions(pdev);
 
 err_out_disable_pdev:
-       pci_disable_device(pdev);
+       if (pci_is_enabled(pdev))
+               pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        return err;
 }
@@ -17773,7 +17774,8 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
        rtnl_lock();
 
-       if (!netif_running(netdev))
+       /* We probably don't have netdev yet */
+       if (!netdev || !netif_running(netdev))
                goto done;
 
        tg3_phy_stop(tp);
@@ -17794,8 +17796,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
 
 done:
        if (state == pci_channel_io_perm_failure) {
-               tg3_napi_enable(tp);
-               dev_close(netdev);
+               if (netdev) {
+                       tg3_napi_enable(tp);
+                       dev_close(netdev);
+               }
                err = PCI_ERS_RESULT_DISCONNECT;
        } else {
                pci_disable_device(pdev);
@@ -17825,7 +17829,8 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
        rtnl_lock();
 
        if (pci_enable_device(pdev)) {
-               netdev_err(netdev, "Cannot re-enable PCI device after reset.\n");
+               dev_err(&pdev->dev,
+                       "Cannot re-enable PCI device after reset.\n");
                goto done;
        }
 
@@ -17833,7 +17838,7 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
        pci_restore_state(pdev);
        pci_save_state(pdev);
 
-       if (!netif_running(netdev)) {
+       if (!netdev || !netif_running(netdev)) {
                rc = PCI_ERS_RESULT_RECOVERED;
                goto done;
        }
@@ -17845,7 +17850,7 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
        rc = PCI_ERS_RESULT_RECOVERED;
 
 done:
-       if (rc != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) {
+       if (rc != PCI_ERS_RESULT_RECOVERED && netdev && netif_running(netdev)) {
                tg3_napi_enable(tp);
                dev_close(netdev);
        }
index 687ec4a..9c89dc8 100644 (file)
@@ -455,11 +455,6 @@ static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q,
                q->pg_chunk.offset = 0;
                mapping = pci_map_page(adapter->pdev, q->pg_chunk.page,
                                       0, q->alloc_size, PCI_DMA_FROMDEVICE);
-               if (unlikely(pci_dma_mapping_error(adapter->pdev, mapping))) {
-                       __free_pages(q->pg_chunk.page, order);
-                       q->pg_chunk.page = NULL;
-                       return -EIO;
-               }
                q->pg_chunk.mapping = mapping;
        }
        sd->pg_chunk = q->pg_chunk;
@@ -954,75 +949,40 @@ static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
        return flits_to_desc(flits);
 }
 
-
-/*     map_skb - map a packet main body and its page fragments
- *     @pdev: the PCI device
- *     @skb: the packet
- *     @addr: placeholder to save the mapped addresses
- *
- *     map the main body of an sk_buff and its page fragments, if any.
- */
-static int map_skb(struct pci_dev *pdev, const struct sk_buff *skb,
-                  dma_addr_t *addr)
-{
-       const skb_frag_t *fp, *end;
-       const struct skb_shared_info *si;
-
-       *addr = pci_map_single(pdev, skb->data, skb_headlen(skb),
-                              PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(pdev, *addr))
-               goto out_err;
-
-       si = skb_shinfo(skb);
-       end = &si->frags[si->nr_frags];
-
-       for (fp = si->frags; fp < end; fp++) {
-               *++addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp),
-                                          DMA_TO_DEVICE);
-               if (pci_dma_mapping_error(pdev, *addr))
-                       goto unwind;
-       }
-       return 0;
-
-unwind:
-       while (fp-- > si->frags)
-               dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp),
-                              DMA_TO_DEVICE);
-
-       pci_unmap_single(pdev, addr[-1], skb_headlen(skb), PCI_DMA_TODEVICE);
-out_err:
-       return -ENOMEM;
-}
-
 /**
- *     write_sgl - populate a scatter/gather list for a packet
+ *     make_sgl - populate a scatter/gather list for a packet
  *     @skb: the packet
  *     @sgp: the SGL to populate
  *     @start: start address of skb main body data to include in the SGL
  *     @len: length of skb main body data to include in the SGL
- *     @addr: the list of the mapped addresses
+ *     @pdev: the PCI device
  *
- *     Copies the scatter/gather list for the buffers that make up a packet
+ *     Generates a scatter/gather list for the buffers that make up a packet
  *     and returns the SGL size in 8-byte words.  The caller must size the SGL
  *     appropriately.
  */
-static inline unsigned int write_sgl(const struct sk_buff *skb,
+static inline unsigned int make_sgl(const struct sk_buff *skb,
                                    struct sg_ent *sgp, unsigned char *start,
-                                   unsigned int len, const dma_addr_t *addr)
+                                   unsigned int len, struct pci_dev *pdev)
 {
-       unsigned int i, j = 0, k = 0, nfrags;
+       dma_addr_t mapping;
+       unsigned int i, j = 0, nfrags;
 
        if (len) {
+               mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
                sgp->len[0] = cpu_to_be32(len);
-               sgp->addr[j++] = cpu_to_be64(addr[k++]);
+               sgp->addr[0] = cpu_to_be64(mapping);
+               j = 1;
        }
 
        nfrags = skb_shinfo(skb)->nr_frags;
        for (i = 0; i < nfrags; i++) {
                const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
+               mapping = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+                                          DMA_TO_DEVICE);
                sgp->len[j] = cpu_to_be32(skb_frag_size(frag));
-               sgp->addr[j] = cpu_to_be64(addr[k++]);
+               sgp->addr[j] = cpu_to_be64(mapping);
                j ^= 1;
                if (j == 0)
                        ++sgp;
@@ -1178,7 +1138,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
                            const struct port_info *pi,
                            unsigned int pidx, unsigned int gen,
                            struct sge_txq *q, unsigned int ndesc,
-                           unsigned int compl, const dma_addr_t *addr)
+                           unsigned int compl)
 {
        unsigned int flits, sgl_flits, cntrl, tso_info;
        struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
@@ -1236,7 +1196,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
        }
 
        sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
-       sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr);
+       sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
 
        write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
                         htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
@@ -1267,7 +1227,6 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        struct netdev_queue *txq;
        struct sge_qset *qs;
        struct sge_txq *q;
-       dma_addr_t addr[MAX_SKB_FRAGS + 1];
 
        /*
         * The chip min packet length is 9 octets but play safe and reject
@@ -1296,11 +1255,6 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
                return NETDEV_TX_BUSY;
        }
 
-       if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) {
-               dev_kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
        q->in_use += ndesc;
        if (unlikely(credits - ndesc < q->stop_thres)) {
                t3_stop_tx_queue(txq, qs, q);
@@ -1358,7 +1312,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        if (likely(!skb_shared(skb)))
                skb_orphan(skb);
 
-       write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr);
+       write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
        check_ring_tx_db(adap, q);
        return NETDEV_TX_OK;
 }
@@ -1623,8 +1577,7 @@ static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev,
  */
 static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
                          struct sge_txq *q, unsigned int pidx,
-                         unsigned int gen, unsigned int ndesc,
-                         const dma_addr_t *addr)
+                         unsigned int gen, unsigned int ndesc)
 {
        unsigned int sgl_flits, flits;
        struct work_request_hdr *from;
@@ -1645,9 +1598,9 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
 
        flits = skb_transport_offset(skb) / 8;
        sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
-       sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb),
-                            skb_tail_pointer(skb) -
-                            skb_transport_header(skb), addr);
+       sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb),
+                            skb->tail - skb->transport_header,
+                            adap->pdev);
        if (need_skb_unmap()) {
                setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits);
                skb->destructor = deferred_unmap_destructor;
@@ -1705,11 +1658,6 @@ again:   reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
                goto again;
        }
 
-       if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) {
-               spin_unlock(&q->lock);
-               return NET_XMIT_SUCCESS;
-       }
-
        gen = q->gen;
        q->in_use += ndesc;
        pidx = q->pidx;
@@ -1720,7 +1668,7 @@ again:    reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
        }
        spin_unlock(&q->lock);
 
-       write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head);
+       write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
        check_ring_tx_db(adap, q);
        return NET_XMIT_SUCCESS;
 }
@@ -1738,7 +1686,6 @@ static void restart_offloadq(unsigned long data)
        struct sge_txq *q = &qs->txq[TXQ_OFLD];
        const struct port_info *pi = netdev_priv(qs->netdev);
        struct adapter *adap = pi->adapter;
-       unsigned int written = 0;
 
        spin_lock(&q->lock);
 again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
@@ -1758,14 +1705,10 @@ again:  reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
                        break;
                }
 
-               if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head))
-                       break;
-
                gen = q->gen;
                q->in_use += ndesc;
                pidx = q->pidx;
                q->pidx += ndesc;
-               written += ndesc;
                if (q->pidx >= q->size) {
                        q->pidx -= q->size;
                        q->gen ^= 1;
@@ -1773,8 +1716,7 @@ again:    reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
                __skb_unlink(skb, &q->sendq);
                spin_unlock(&q->lock);
 
-               write_ofld_wr(adap, skb, q, pidx, gen, ndesc,
-                            (dma_addr_t *)skb->head);
+               write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
                spin_lock(&q->lock);
        }
        spin_unlock(&q->lock);
@@ -1784,9 +1726,8 @@ again:    reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
        set_bit(TXQ_LAST_PKT_DB, &q->flags);
 #endif
        wmb();
-       if (likely(written))
-               t3_write_reg(adap, A_SG_KDOORBELL,
-                            F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+       t3_write_reg(adap, A_SG_KDOORBELL,
+                    F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
 }
 
 /**
index 6e6e0a1..8ec5d74 100644 (file)
@@ -3048,6 +3048,9 @@ int be_cmd_get_func_config(struct be_adapter *adapter)
 
                adapter->max_event_queues = le16_to_cpu(desc->eq_count);
                adapter->if_cap_flags = le32_to_cpu(desc->cap_flags);
+
+               /* Clear flags that driver is not interested in */
+               adapter->if_cap_flags &=  BE_IF_CAP_FLAGS_WANT;
        }
 err:
        mutex_unlock(&adapter->mbox_lock);
index 5228d88..1b3b9e8 100644 (file)
@@ -563,6 +563,12 @@ enum be_if_flags {
        BE_IF_FLAGS_MULTICAST = 0x1000
 };
 
+#define BE_IF_CAP_FLAGS_WANT (BE_IF_FLAGS_RSS | BE_IF_FLAGS_PROMISCUOUS |\
+                        BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_VLAN_PROMISCUOUS |\
+                        BE_IF_FLAGS_VLAN | BE_IF_FLAGS_MCAST_PROMISCUOUS |\
+                        BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\
+                        BE_IF_FLAGS_UNTAGGED)
+
 /* An RX interface is an object with one or more MAC addresses and
  * filtering capabilities. */
 struct be_cmd_req_if_create {
index 2b0a0ea..ae23600 100644 (file)
@@ -259,6 +259,7 @@ struct bufdesc_ex {
 struct fec_enet_delayed_work {
        struct delayed_work delay_work;
        bool timeout;
+       bool trig_tx;
 };
 
 /* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
index d3ad5ea..77ea0db 100644 (file)
@@ -93,6 +93,20 @@ static void set_multicast_list(struct net_device *ndev);
 #define FEC_QUIRK_HAS_CSUM             (1 << 5)
 /* Controller has hardware vlan support */
 #define FEC_QUIRK_HAS_VLAN             (1 << 6)
+/* ENET IP errata ERR006358
+ *
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * If the ready bit in the transmit buffer descriptor (TxBD[R]) is previously
+ * detected as not set during a prior frame transmission, then the
+ * ENET_TDAR[TDAR] bit is cleared at a later time, even if additional TxBDs
+ * were added to the ring and the ENET_TDAR[TDAR] bit is set. This results in
+ * frames not being transmitted until there is a 0-to-1 transition on
+ * ENET_TDAR[TDAR].
+ */
+#define FEC_QUIRK_ERR006358            (1 << 7)
 
 static struct platform_device_id fec_devtype[] = {
        {
@@ -112,7 +126,7 @@ static struct platform_device_id fec_devtype[] = {
                .name = "imx6q-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
                                FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-                               FEC_QUIRK_HAS_VLAN,
+                               FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358,
        }, {
                .name = "mvf600-fec",
                .driver_data = FEC_QUIRK_ENET_MAC,
@@ -275,16 +289,11 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        struct fec_enet_private *fep = netdev_priv(ndev);
        const struct platform_device_id *id_entry =
                                platform_get_device_id(fep->pdev);
-       struct bufdesc *bdp;
+       struct bufdesc *bdp, *bdp_pre;
        void *bufaddr;
        unsigned short  status;
        unsigned int index;
 
-       if (!fep->link) {
-               /* Link is down or auto-negotiation is in progress. */
-               return NETDEV_TX_BUSY;
-       }
-
        /* Fill in a Tx ring entry */
        bdp = fep->cur_tx;
 
@@ -370,6 +379,15 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                ebdp->cbd_esc |= BD_ENET_TX_PINS;
                }
        }
+
+       bdp_pre = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+       if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
+           !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
+               fep->delay_work.trig_tx = true;
+               schedule_delayed_work(&(fep->delay_work.delay_work),
+                                       msecs_to_jiffies(1));
+       }
+
        /* If this was the last BD in the ring, start at the beginning again. */
        if (status & BD_ENET_TX_WRAP)
                bdp = fep->tx_bd_base;
@@ -689,6 +707,11 @@ static void fec_enet_work(struct work_struct *work)
                fec_restart(fep->netdev, fep->full_duplex);
                netif_wake_queue(fep->netdev);
        }
+
+       if (fep->delay_work.trig_tx) {
+               fep->delay_work.trig_tx = false;
+               writel(0, fep->hwp + FEC_X_DES_ACTIVE);
+       }
 }
 
 static void
@@ -2279,4 +2302,5 @@ static struct platform_driver fec_driver = {
 
 module_platform_driver(fec_driver);
 
+MODULE_ALIAS("platform:"DRIVER_NAME);
 MODULE_LICENSE("GPL");
index 6a0c1b6..c1d72c0 100644 (file)
@@ -3739,9 +3739,8 @@ static void igb_set_rx_mode(struct net_device *netdev)
        rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_VFE);
 
        if (netdev->flags & IFF_PROMISC) {
-               u32 mrqc = rd32(E1000_MRQC);
                /* retain VLAN HW filtering if in VT mode */
-               if (mrqc & E1000_MRQC_ENABLE_VMDQ)
+               if (adapter->vfs_allocated_count)
                        rctl |= E1000_RCTL_VFE;
                rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
                vmolr |= (E1000_VMOLR_ROPE | E1000_VMOLR_MPME);
index 7be725c..a6494e5 100644 (file)
@@ -54,7 +54,7 @@
 
 #include <net/busy_poll.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 #define LL_EXTENDED_STATS
 #endif
 /* common prefix used by pr_<> macros */
@@ -366,7 +366,7 @@ struct ixgbe_q_vector {
        struct rcu_head rcu;    /* to avoid race with update stats on free */
        char name[IFNAMSIZ + 9];
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define IXGBE_QV_STATE_IDLE        0
 #define IXGBE_QV_STATE_NAPI       1    /* NAPI owns this QV */
@@ -377,12 +377,12 @@ struct ixgbe_q_vector {
 #define IXGBE_QV_YIELD (IXGBE_QV_STATE_NAPI_YIELD | IXGBE_QV_STATE_POLL_YIELD)
 #define IXGBE_QV_USER_PEND (IXGBE_QV_STATE_POLL | IXGBE_QV_STATE_POLL_YIELD)
        spinlock_t lock;
-#endif  /* CONFIG_NET_LL_RX_POLL */
+#endif  /* CONFIG_NET_RX_BUSY_POLL */
 
        /* for dynamic allocation of rings associated with this q_vector */
        struct ixgbe_ring ring[0] ____cacheline_internodealigned_in_smp;
 };
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
 {
 
@@ -462,7 +462,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
        WARN_ON(!(q_vector->state & IXGBE_QV_LOCKED));
        return q_vector->state & IXGBE_QV_USER_PEND;
 }
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
 static inline void ixgbe_qv_init_lock(struct ixgbe_q_vector *q_vector)
 {
 }
@@ -491,7 +491,7 @@ static inline bool ixgbe_qv_ll_polling(struct ixgbe_q_vector *q_vector)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #ifdef CONFIG_IXGBE_HWMON
 
index ac78077..7a77f37 100644 (file)
@@ -108,9 +108,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw,
 
        /* Enable arbiter */
        reg &= ~IXGBE_DPMCS_ARBDIS;
-       /* Enable DFP and Recycle mode */
-       reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM);
        reg |= IXGBE_DPMCS_TSOEF;
+
        /* Configure Max TSO packet size 34KB including payload and headers */
        reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT);
 
index bad8f14..be4b1fb 100644 (file)
@@ -1998,7 +1998,7 @@ static int ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
        return total_rx_packets;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 static int ixgbe_low_latency_recv(struct napi_struct *napi)
 {
@@ -2030,7 +2030,7 @@ static int ixgbe_low_latency_recv(struct napi_struct *napi)
 
        return found;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 /**
  * ixgbe_configure_msix - Configure MSI-X hardware
@@ -7227,7 +7227,7 @@ static const struct net_device_ops ixgbe_netdev_ops = {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = ixgbe_netpoll,
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = ixgbe_low_latency_recv,
 #endif
 #ifdef IXGBE_FCOE
index 712779f..b017818 100644 (file)
@@ -88,6 +88,8 @@
 #define      MVNETA_TX_IN_PRGRS                  BIT(1)
 #define      MVNETA_TX_FIFO_EMPTY                BIT(8)
 #define MVNETA_RX_MIN_FRAME_SIZE                 0x247c
+#define MVNETA_SGMII_SERDES_CFG                         0x24A0
+#define      MVNETA_SGMII_SERDES_PROTO          0x0cc7
 #define MVNETA_TYPE_PRIO                         0x24bc
 #define      MVNETA_FORCE_UNI                    BIT(21)
 #define MVNETA_TXQ_CMD_1                         0x24e4
@@ -655,6 +657,8 @@ static void mvneta_port_sgmii_config(struct mvneta_port *pp)
        val = mvreg_read(pp, MVNETA_GMAC_CTRL_2);
        val |= MVNETA_GMAC2_PSC_ENABLE;
        mvreg_write(pp, MVNETA_GMAC_CTRL_2, val);
+
+       mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO);
 }
 
 /* Start the Ethernet port RX and TX activity */
@@ -2728,28 +2732,24 @@ static int mvneta_probe(struct platform_device *pdev)
 
        pp = netdev_priv(dev);
 
-       pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
-       init_timer(&pp->tx_done_timer);
-       clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
-
        pp->weight = MVNETA_RX_POLL_WEIGHT;
        pp->phy_node = phy_node;
        pp->phy_interface = phy_mode;
 
-       pp->base = of_iomap(dn, 0);
-       if (pp->base == NULL) {
-               err = -ENOMEM;
-               goto err_free_irq;
-       }
-
        pp->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pp->clk)) {
                err = PTR_ERR(pp->clk);
-               goto err_unmap;
+               goto err_free_irq;
        }
 
        clk_prepare_enable(pp->clk);
 
+       pp->base = of_iomap(dn, 0);
+       if (pp->base == NULL) {
+               err = -ENOMEM;
+               goto err_clk;
+       }
+
        dt_mac_addr = of_get_mac_address(dn);
        if (dt_mac_addr && is_valid_ether_addr(dt_mac_addr)) {
                mac_from = "device tree";
@@ -2766,6 +2766,9 @@ static int mvneta_probe(struct platform_device *pdev)
        }
 
        pp->tx_done_timer.data = (unsigned long)dev;
+       pp->tx_done_timer.function = mvneta_tx_done_timer_callback;
+       init_timer(&pp->tx_done_timer);
+       clear_bit(MVNETA_F_TX_DONE_TIMER_BIT, &pp->flags);
 
        pp->tx_ring_size = MVNETA_MAX_TXD;
        pp->rx_ring_size = MVNETA_MAX_RXD;
@@ -2776,7 +2779,7 @@ static int mvneta_probe(struct platform_device *pdev)
        err = mvneta_init(pp, phy_addr);
        if (err < 0) {
                dev_err(&pdev->dev, "can't init eth hal\n");
-               goto err_clk;
+               goto err_unmap;
        }
        mvneta_port_power_up(pp, phy_mode);
 
@@ -2806,10 +2809,10 @@ static int mvneta_probe(struct platform_device *pdev)
 
 err_deinit:
        mvneta_deinit(pp);
-err_clk:
-       clk_disable_unprepare(pp->clk);
 err_unmap:
        iounmap(pp->base);
+err_clk:
+       clk_disable_unprepare(pp->clk);
 err_free_irq:
        irq_dispose_mapping(dev->irq);
 err_free_netdev:
index c896079..ef94a59 100644 (file)
@@ -931,17 +931,20 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base)
 }
 
 /* Allocate and setup a new buffer for receiving */
-static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
-                         struct sk_buff *skb, unsigned int bufsize)
+static int skge_rx_setup(struct skge_port *skge, struct skge_element *e,
+                        struct sk_buff *skb, unsigned int bufsize)
 {
        struct skge_rx_desc *rd = e->desc;
-       u64 map;
+       dma_addr_t map;
 
        map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
                             PCI_DMA_FROMDEVICE);
 
-       rd->dma_lo = map;
-       rd->dma_hi = map >> 32;
+       if (pci_dma_mapping_error(skge->hw->pdev, map))
+               return -1;
+
+       rd->dma_lo = lower_32_bits(map);
+       rd->dma_hi = upper_32_bits(map);
        e->skb = skb;
        rd->csum1_start = ETH_HLEN;
        rd->csum2_start = ETH_HLEN;
@@ -953,6 +956,7 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
        rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
        dma_unmap_addr_set(e, mapaddr, map);
        dma_unmap_len_set(e, maplen, bufsize);
+       return 0;
 }
 
 /* Resume receiving using existing skb,
@@ -1014,7 +1018,10 @@ static int skge_rx_fill(struct net_device *dev)
                        return -ENOMEM;
 
                skb_reserve(skb, NET_IP_ALIGN);
-               skge_rx_setup(skge, e, skb, skge->rx_buf_size);
+               if (skge_rx_setup(skge, e, skb, skge->rx_buf_size) < 0) {
+                       dev_kfree_skb(skb);
+                       return -EIO;
+               }
        } while ((e = e->next) != ring->start);
 
        ring->to_clean = ring->start;
@@ -2544,7 +2551,7 @@ static int skge_up(struct net_device *dev)
 
        BUG_ON(skge->dma & 7);
 
-       if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
+       if (upper_32_bits(skge->dma) != upper_32_bits(skge->dma + skge->mem_size)) {
                dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
                err = -EINVAL;
                goto free_pci_mem;
@@ -2729,7 +2736,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
        struct skge_tx_desc *td;
        int i;
        u32 control, len;
-       u64 map;
+       dma_addr_t map;
 
        if (skb_padto(skb, ETH_ZLEN))
                return NETDEV_TX_OK;
@@ -2743,11 +2750,14 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
        e->skb = skb;
        len = skb_headlen(skb);
        map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(hw->pdev, map))
+               goto mapping_error;
+
        dma_unmap_addr_set(e, mapaddr, map);
        dma_unmap_len_set(e, maplen, len);
 
-       td->dma_lo = map;
-       td->dma_hi = map >> 32;
+       td->dma_lo = lower_32_bits(map);
+       td->dma_hi = upper_32_bits(map);
 
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                const int offset = skb_checksum_start_offset(skb);
@@ -2778,14 +2788,16 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
 
                        map = skb_frag_dma_map(&hw->pdev->dev, frag, 0,
                                               skb_frag_size(frag), DMA_TO_DEVICE);
+                       if (dma_mapping_error(&hw->pdev->dev, map))
+                               goto mapping_unwind;
 
                        e = e->next;
                        e->skb = skb;
                        tf = e->desc;
                        BUG_ON(tf->control & BMU_OWN);
 
-                       tf->dma_lo = map;
-                       tf->dma_hi = (u64) map >> 32;
+                       tf->dma_lo = lower_32_bits(map);
+                       tf->dma_hi = upper_32_bits(map);
                        dma_unmap_addr_set(e, mapaddr, map);
                        dma_unmap_len_set(e, maplen, skb_frag_size(frag));
 
@@ -2815,6 +2827,26 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
        }
 
        return NETDEV_TX_OK;
+
+mapping_unwind:
+       e = skge->tx_ring.to_use;
+       pci_unmap_single(hw->pdev,
+                        dma_unmap_addr(e, mapaddr),
+                        dma_unmap_len(e, maplen),
+                        PCI_DMA_TODEVICE);
+       while (i-- > 0) {
+               e = e->next;
+               pci_unmap_page(hw->pdev,
+                              dma_unmap_addr(e, mapaddr),
+                              dma_unmap_len(e, maplen),
+                              PCI_DMA_TODEVICE);
+       }
+
+mapping_error:
+       if (net_ratelimit())
+               dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name);
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
 }
 
 
@@ -3045,11 +3077,13 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
 
                pci_dma_sync_single_for_cpu(skge->hw->pdev,
                                            dma_unmap_addr(e, mapaddr),
-                                           len, PCI_DMA_FROMDEVICE);
+                                           dma_unmap_len(e, maplen),
+                                           PCI_DMA_FROMDEVICE);
                skb_copy_from_linear_data(e->skb, skb->data, len);
                pci_dma_sync_single_for_device(skge->hw->pdev,
                                               dma_unmap_addr(e, mapaddr),
-                                              len, PCI_DMA_FROMDEVICE);
+                                              dma_unmap_len(e, maplen),
+                                              PCI_DMA_FROMDEVICE);
                skge_rx_reuse(e, skge->rx_buf_size);
        } else {
                struct sk_buff *nskb;
@@ -3058,13 +3092,17 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                if (!nskb)
                        goto resubmit;
 
+               if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) {
+                       dev_kfree_skb(nskb);
+                       goto resubmit;
+               }
+
                pci_unmap_single(skge->hw->pdev,
                                 dma_unmap_addr(e, mapaddr),
                                 dma_unmap_len(e, maplen),
                                 PCI_DMA_FROMDEVICE);
                skb = e->skb;
                prefetch(skb->data);
-               skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
        }
 
        skb_put(skb, len);
index 727874f..a28cd80 100644 (file)
@@ -223,7 +223,7 @@ static int mlx4_en_get_sset_count(struct net_device *dev, int sset)
        case ETH_SS_STATS:
                return (priv->stats_bitmap ? bit_count : NUM_ALL_STATS) +
                        (priv->tx_ring_num * 2) +
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                        (priv->rx_ring_num * 5);
 #else
                        (priv->rx_ring_num * 2);
@@ -276,7 +276,7 @@ static void mlx4_en_get_ethtool_stats(struct net_device *dev,
        for (i = 0; i < priv->rx_ring_num; i++) {
                data[index++] = priv->rx_ring[i].packets;
                data[index++] = priv->rx_ring[i].bytes;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                data[index++] = priv->rx_ring[i].yields;
                data[index++] = priv->rx_ring[i].misses;
                data[index++] = priv->rx_ring[i].cleaned;
@@ -344,7 +344,7 @@ static void mlx4_en_get_strings(struct net_device *dev,
                                "rx%d_packets", i);
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
                                "rx%d_bytes", i);
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
                                "rx%d_napi_yield", i);
                        sprintf(data + (index++) * ETH_GSTRING_LEN,
index 5eac871..fa37b7a 100644 (file)
@@ -68,7 +68,7 @@ int mlx4_en_setup_tc(struct net_device *dev, u8 up)
        return 0;
 }
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 /* must be called with local_bh_disable()d */
 static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 {
@@ -94,7 +94,7 @@ static int mlx4_en_low_latency_recv(struct napi_struct *napi)
 
        return done;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #ifdef CONFIG_RFS_ACCEL
 
@@ -2140,7 +2140,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        .ndo_busy_poll          = mlx4_en_low_latency_recv,
 #endif
 };
index 8873d68..6fc6dab 100644 (file)
@@ -845,16 +845,7 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave,
                           MLX4_CMD_NATIVE);
 
        if (!err && dev->caps.function != slave) {
-               /* if config MAC in DB use it */
-               if (priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac)
-                       def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
-               else {
-                       /* set slave default_mac address */
-                       MLX4_GET(def_mac, outbox->buf, QUERY_PORT_MAC_OFFSET);
-                       def_mac += slave << 8;
-                       priv->mfunc.master.vf_admin[slave].vport[vhcr->in_modifier].mac = def_mac;
-               }
-
+               def_mac = priv->mfunc.master.vf_oper[slave].vport[vhcr->in_modifier].state.mac;
                MLX4_PUT(outbox->buf, def_mac, QUERY_PORT_MAC_OFFSET);
 
                /* get port type - currently only eth is enabled */
index e85af92..36be320 100644 (file)
@@ -371,7 +371,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 
        dev->caps.sqp_demux = (mlx4_is_master(dev)) ? MLX4_MAX_NUM_SLAVES : 0;
 
-       if (!enable_64b_cqe_eqe) {
+       if (!enable_64b_cqe_eqe && !mlx4_is_slave(dev)) {
                if (dev_cap->flags &
                    (MLX4_DEV_CAP_FLAG_64B_CQE | MLX4_DEV_CAP_FLAG_64B_EQE)) {
                        mlx4_warn(dev, "64B EQEs/CQEs supported by the device but not enabled\n");
index 35fb60e..5e0aa56 100644 (file)
@@ -292,7 +292,7 @@ struct mlx4_en_rx_ring {
        void *rx_info;
        unsigned long bytes;
        unsigned long packets;
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned long yields;
        unsigned long misses;
        unsigned long cleaned;
@@ -318,7 +318,7 @@ struct mlx4_en_cq {
        struct mlx4_cqe *buf;
 #define MLX4_EN_OPCODE_ERROR   0x1e
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int state;
 #define MLX4_EN_CQ_STATE_IDLE        0
 #define MLX4_EN_CQ_STATE_NAPI     1    /* NAPI owns this CQ */
@@ -329,7 +329,7 @@ struct mlx4_en_cq {
 #define CQ_YIELD (MLX4_EN_CQ_STATE_NAPI_YIELD | MLX4_EN_CQ_STATE_POLL_YIELD)
 #define CQ_USER_PEND (MLX4_EN_CQ_STATE_POLL | MLX4_EN_CQ_STATE_POLL_YIELD)
        spinlock_t poll_lock; /* protects from LLS/napi conflicts */
-#endif  /* CONFIG_NET_LL_RX_POLL */
+#endif  /* CONFIG_NET_RX_BUSY_POLL */
 };
 
 struct mlx4_en_port_profile {
@@ -580,7 +580,7 @@ struct mlx4_mac_entry {
        struct rcu_head rcu;
 };
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 static inline void mlx4_en_cq_init_lock(struct mlx4_en_cq *cq)
 {
        spin_lock_init(&cq->poll_lock);
@@ -687,7 +687,7 @@ static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq)
 {
        return false;
 }
-#endif /* CONFIG_NET_LL_RX_POLL */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 
 #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
 
index 205753a..5472cbd 100644 (file)
@@ -46,7 +46,7 @@
 #include "mlx5_core.h"
 
 enum {
-       CMD_IF_REV = 3,
+       CMD_IF_REV = 5,
 };
 
 enum {
@@ -282,6 +282,12 @@ const char *mlx5_command_str(int command)
        case MLX5_CMD_OP_TEARDOWN_HCA:
                return "TEARDOWN_HCA";
 
+       case MLX5_CMD_OP_ENABLE_HCA:
+               return "MLX5_CMD_OP_ENABLE_HCA";
+
+       case MLX5_CMD_OP_DISABLE_HCA:
+               return "MLX5_CMD_OP_DISABLE_HCA";
+
        case MLX5_CMD_OP_QUERY_PAGES:
                return "QUERY_PAGES";
 
@@ -1113,7 +1119,13 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
 
        for (i = 0; i < (1 << cmd->log_sz); i++) {
                if (test_bit(i, &vector)) {
+                       struct semaphore *sem;
+
                        ent = cmd->ent_arr[i];
+                       if (ent->page_queue)
+                               sem = &cmd->pages_sem;
+                       else
+                               sem = &cmd->sem;
                        ktime_get_ts(&ent->ts2);
                        memcpy(ent->out->first.data, ent->lay->out, sizeof(ent->lay->out));
                        dump_command(dev, ent, 0);
@@ -1136,10 +1148,7 @@ void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, unsigned long vector)
                        } else {
                                complete(&ent->done);
                        }
-                       if (ent->page_queue)
-                               up(&cmd->pages_sem);
-                       else
-                               up(&cmd->sem);
+                       up(sem);
                }
        }
 }
index c02cbcf..443cc4d 100644 (file)
@@ -268,7 +268,7 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq)
                case MLX5_EVENT_TYPE_PAGE_REQUEST:
                        {
                                u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id);
-                               s16 npages = be16_to_cpu(eqe->data.req_pages.num_pages);
+                               s32 npages = be32_to_cpu(eqe->data.req_pages.num_pages);
 
                                mlx5_core_dbg(dev, "page request for func 0x%x, napges %d\n", func_id, npages);
                                mlx5_core_req_pages_handler(dev, func_id, npages);
index 72a5222..f012658 100644 (file)
@@ -113,7 +113,7 @@ int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev,
        caps->log_max_srq = out->hca_cap.log_max_srqs & 0x1f;
        caps->local_ca_ack_delay = out->hca_cap.local_ca_ack_delay & 0x1f;
        caps->log_max_mcg = out->hca_cap.log_max_mcg;
-       caps->max_qp_mcg = be16_to_cpu(out->hca_cap.max_qp_mcg);
+       caps->max_qp_mcg = be32_to_cpu(out->hca_cap.max_qp_mcg) & 0xffffff;
        caps->max_ra_res_qp = 1 << (out->hca_cap.log_max_ra_res_qp & 0x3f);
        caps->max_ra_req_qp = 1 << (out->hca_cap.log_max_ra_req_qp & 0x3f);
        caps->max_srq_wqes = 1 << out->hca_cap.log_max_srq_sz;
index 748f10a..3e6670c 100644 (file)
@@ -55,33 +55,9 @@ enum {
 };
 
 static DEFINE_SPINLOCK(health_lock);
-
 static LIST_HEAD(health_list);
 static struct work_struct health_work;
 
-static health_handler_t reg_handler;
-int mlx5_register_health_report_handler(health_handler_t handler)
-{
-       spin_lock_irq(&health_lock);
-       if (reg_handler) {
-               spin_unlock_irq(&health_lock);
-               return -EEXIST;
-       }
-       reg_handler = handler;
-       spin_unlock_irq(&health_lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(mlx5_register_health_report_handler);
-
-void mlx5_unregister_health_report_handler(void)
-{
-       spin_lock_irq(&health_lock);
-       reg_handler = NULL;
-       spin_unlock_irq(&health_lock);
-}
-EXPORT_SYMBOL(mlx5_unregister_health_report_handler);
-
 static void health_care(struct work_struct *work)
 {
        struct mlx5_core_health *health, *n;
@@ -98,11 +74,8 @@ static void health_care(struct work_struct *work)
                priv = container_of(health, struct mlx5_priv, health);
                dev = container_of(priv, struct mlx5_core_dev, priv);
                mlx5_core_warn(dev, "handling bad device here\n");
+               /* nothing yet */
                spin_lock_irq(&health_lock);
-               if (reg_handler)
-                       reg_handler(dev->pdev, health->health,
-                                   sizeof(health->health));
-
                list_del_init(&health->list);
                spin_unlock_irq(&health_lock);
        }
index 12242de..b47739b 100644 (file)
@@ -249,6 +249,44 @@ static int set_hca_ctrl(struct mlx5_core_dev *dev)
        return err;
 }
 
+static int mlx5_core_enable_hca(struct mlx5_core_dev *dev)
+{
+       int err;
+       struct mlx5_enable_hca_mbox_in in;
+       struct mlx5_enable_hca_mbox_out out;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_ENABLE_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return 0;
+}
+
+static int mlx5_core_disable_hca(struct mlx5_core_dev *dev)
+{
+       int err;
+       struct mlx5_disable_hca_mbox_in in;
+       struct mlx5_disable_hca_mbox_out out;
+
+       memset(&in, 0, sizeof(in));
+       memset(&out, 0, sizeof(out));
+       in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_DISABLE_HCA);
+       err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
+       if (err)
+               return err;
+
+       if (out.hdr.status)
+               return mlx5_cmd_status_to_err(&out.hdr);
+
+       return 0;
+}
+
 int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
 {
        struct mlx5_priv *priv = &dev->priv;
@@ -304,28 +342,41 @@ int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev)
        }
 
        mlx5_pagealloc_init(dev);
+
+       err = mlx5_core_enable_hca(dev);
+       if (err) {
+               dev_err(&pdev->dev, "enable hca failed\n");
+               goto err_pagealloc_cleanup;
+       }
+
+       err = mlx5_satisfy_startup_pages(dev, 1);
+       if (err) {
+               dev_err(&pdev->dev, "failed to allocate boot pages\n");
+               goto err_disable_hca;
+       }
+
        err = set_hca_ctrl(dev);
        if (err) {
                dev_err(&pdev->dev, "set_hca_ctrl failed\n");
-               goto err_pagealloc_cleanup;
+               goto reclaim_boot_pages;
        }
 
        err = handle_hca_cap(dev);
        if (err) {
                dev_err(&pdev->dev, "handle_hca_cap failed\n");
-               goto err_pagealloc_cleanup;
+               goto reclaim_boot_pages;
        }
 
-       err = mlx5_satisfy_startup_pages(dev);
+       err = mlx5_satisfy_startup_pages(dev, 0);
        if (err) {
-               dev_err(&pdev->dev, "failed to allocate startup pages\n");
-               goto err_pagealloc_cleanup;
+               dev_err(&pdev->dev, "failed to allocate init pages\n");
+               goto reclaim_boot_pages;
        }
 
        err = mlx5_pagealloc_start(dev);
        if (err) {
                dev_err(&pdev->dev, "mlx5_pagealloc_start failed\n");
-               goto err_reclaim_pages;
+               goto reclaim_boot_pages;
        }
 
        err = mlx5_cmd_init_hca(dev);
@@ -396,9 +447,12 @@ err_stop_poll:
 err_pagealloc_stop:
        mlx5_pagealloc_stop(dev);
 
-err_reclaim_pages:
+reclaim_boot_pages:
        mlx5_reclaim_startup_pages(dev);
 
+err_disable_hca:
+       mlx5_core_disable_hca(dev);
+
 err_pagealloc_cleanup:
        mlx5_pagealloc_cleanup(dev);
        mlx5_cmd_cleanup(dev);
@@ -434,6 +488,7 @@ void mlx5_dev_cleanup(struct mlx5_core_dev *dev)
        mlx5_cmd_teardown_hca(dev);
        mlx5_pagealloc_stop(dev);
        mlx5_reclaim_startup_pages(dev);
+       mlx5_core_disable_hca(dev);
        mlx5_pagealloc_cleanup(dev);
        mlx5_cmd_cleanup(dev);
        iounmap(dev->iseg);
index f0bf463..3a2408d 100644 (file)
@@ -43,10 +43,16 @@ enum {
        MLX5_PAGES_TAKE         = 2
 };
 
+enum {
+       MLX5_BOOT_PAGES         = 1,
+       MLX5_INIT_PAGES         = 2,
+       MLX5_POST_INIT_PAGES    = 3
+};
+
 struct mlx5_pages_req {
        struct mlx5_core_dev *dev;
        u32     func_id;
-       s16     npages;
+       s32     npages;
        struct work_struct work;
 };
 
@@ -64,27 +70,23 @@ struct mlx5_query_pages_inbox {
 
 struct mlx5_query_pages_outbox {
        struct mlx5_outbox_hdr  hdr;
-       u8                      reserved[2];
+       __be16                  rsvd;
        __be16                  func_id;
-       __be16                  init_pages;
-       __be16                  num_pages;
+       __be32                  num_pages;
 };
 
 struct mlx5_manage_pages_inbox {
        struct mlx5_inbox_hdr   hdr;
-       __be16                  rsvd0;
+       __be16                  rsvd;
        __be16                  func_id;
-       __be16                  rsvd1;
-       __be16                  num_entries;
-       u8                      rsvd2[16];
+       __be32                  num_entries;
        __be64                  pas[0];
 };
 
 struct mlx5_manage_pages_outbox {
        struct mlx5_outbox_hdr  hdr;
-       u8                      rsvd0[2];
-       __be16                  num_entries;
-       u8                      rsvd1[20];
+       __be32                  num_entries;
+       u8                      rsvd[4];
        __be64                  pas[0];
 };
 
@@ -146,7 +148,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr)
 }
 
 static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
-                               s16 *pages, s16 *init_pages)
+                               s32 *npages, int boot)
 {
        struct mlx5_query_pages_inbox   in;
        struct mlx5_query_pages_outbox  out;
@@ -155,6 +157,8 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
        memset(&in, 0, sizeof(in));
        memset(&out, 0, sizeof(out));
        in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES);
+       in.hdr.opmod = boot ? cpu_to_be16(MLX5_BOOT_PAGES) : cpu_to_be16(MLX5_INIT_PAGES);
+
        err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out));
        if (err)
                return err;
@@ -162,10 +166,7 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id,
        if (out.hdr.status)
                return mlx5_cmd_status_to_err(&out.hdr);
 
-       if (pages)
-               *pages = be16_to_cpu(out.num_pages);
-       if (init_pages)
-               *init_pages = be16_to_cpu(out.init_pages);
+       *npages = be32_to_cpu(out.num_pages);
        *func_id = be16_to_cpu(out.func_id);
 
        return err;
@@ -219,7 +220,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages,
        in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
        in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE);
        in->func_id = cpu_to_be16(func_id);
-       in->num_entries = cpu_to_be16(npages);
+       in->num_entries = cpu_to_be32(npages);
        err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out));
        mlx5_core_dbg(dev, "err %d\n", err);
        if (err) {
@@ -287,7 +288,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
        in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES);
        in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE);
        in.func_id = cpu_to_be16(func_id);
-       in.num_entries = cpu_to_be16(npages);
+       in.num_entries = cpu_to_be32(npages);
        mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen);
        err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen);
        if (err) {
@@ -301,7 +302,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages,
                goto out_free;
        }
 
-       num_claimed = be16_to_cpu(out->num_entries);
+       num_claimed = be32_to_cpu(out->num_entries);
        if (nclaimed)
                *nclaimed = num_claimed;
 
@@ -340,7 +341,7 @@ static void pages_work_handler(struct work_struct *work)
 }
 
 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
-                                s16 npages)
+                                s32 npages)
 {
        struct mlx5_pages_req *req;
 
@@ -357,19 +358,20 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
        queue_work(dev->priv.pg_wq, &req->work);
 }
 
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev)
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot)
 {
-       s16 uninitialized_var(init_pages);
        u16 uninitialized_var(func_id);
+       s32 uninitialized_var(npages);
        int err;
 
-       err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages);
+       err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot);
        if (err)
                return err;
 
-       mlx5_core_dbg(dev, "requested %d init pages for func_id 0x%x\n", init_pages, func_id);
+       mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n",
+                     npages, boot ? "boot" : "init", func_id);
 
-       return give_pages(dev, func_id, init_pages, 0);
+       return give_pages(dev, func_id, npages, 0);
 }
 
 static int optimal_reclaimed_pages(void)
index 71d4a39..68f5d9c 100644 (file)
@@ -164,6 +164,7 @@ int mlx5_alloc_uuars(struct mlx5_core_dev *dev, struct mlx5_uuar_info *uuari)
                uuari->uars[i].map = ioremap(addr, PAGE_SIZE);
                if (!uuari->uars[i].map) {
                        mlx5_cmd_free_uar(dev, uuari->uars[i].index);
+                       err = -ENOMEM;
                        goto out_count;
                }
                mlx5_core_dbg(dev, "allocated uar index 0x%x, mmaped at %p\n",
index cb22341..a588ffd 100644 (file)
@@ -4,7 +4,7 @@
 
 config PCH_GBE
        tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE"
-       depends on PCI
+       depends on PCI && (X86 || COMPILE_TEST)
        select MII
        select PTP_1588_CLOCK_PCH
        ---help---
index b00cf56..221645e 100644 (file)
@@ -1400,8 +1400,8 @@ void qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *, u64, u64);
 #define ADDR_IN_RANGE(addr, low, high) \
        (((addr) < (high)) && ((addr) >= (low)))
 
-#define QLCRD32(adapter, off) \
-       (adapter->ahw->hw_ops->read_reg)(adapter, off)
+#define QLCRD32(adapter, off, err) \
+       (adapter->ahw->hw_ops->read_reg)(adapter, off, err)
 
 #define QLCWR32(adapter, off, val) \
        adapter->ahw->hw_ops->write_reg(adapter, off, val)
@@ -1604,7 +1604,7 @@ struct qlcnic_nic_template {
 struct qlcnic_hardware_ops {
        void (*read_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
        void (*write_crb) (struct qlcnic_adapter *, char *, loff_t, size_t);
-       int (*read_reg) (struct qlcnic_adapter *, ulong);
+       int (*read_reg) (struct qlcnic_adapter *, ulong, int *);
        int (*write_reg) (struct qlcnic_adapter *, ulong, u32);
        void (*get_ocm_win) (struct qlcnic_hardware_context *);
        int (*get_mac_address) (struct qlcnic_adapter *, u8 *);
@@ -1662,12 +1662,6 @@ static inline void qlcnic_write_crb(struct qlcnic_adapter *adapter, char *buf,
        adapter->ahw->hw_ops->write_crb(adapter, buf, offset, size);
 }
 
-static inline int qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter,
-                                      ulong off)
-{
-       return adapter->ahw->hw_ops->read_reg(adapter, off);
-}
-
 static inline int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter,
                                        ulong off, u32 data)
 {
@@ -1869,7 +1863,8 @@ static inline void qlcnic_free_mac_list(struct qlcnic_adapter *adapter)
 
 static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter)
 {
-       adapter->ahw->hw_ops->set_mac_filter_count(adapter);
+       if (adapter->ahw->hw_ops->set_mac_filter_count)
+               adapter->ahw->hw_ops->set_mac_filter_count(adapter);
 }
 
 static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter,
index 0913c62..9d4bb7f 100644 (file)
@@ -228,17 +228,17 @@ static int __qlcnic_set_win_base(struct qlcnic_adapter *adapter, u32 addr)
        return 0;
 }
 
-int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr)
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *adapter, ulong addr,
+                               int *err)
 {
-       int ret;
        struct qlcnic_hardware_context *ahw = adapter->ahw;
 
-       ret = __qlcnic_set_win_base(adapter, (u32) addr);
-       if (!ret) {
+       *err = __qlcnic_set_win_base(adapter, (u32) addr);
+       if (!*err) {
                return QLCRDX(ahw, QLCNIC_WILDCARD);
        } else {
                dev_err(&adapter->pdev->dev,
-                       "%s failed, addr = 0x%x\n", __func__, (int)addr);
+                       "%s failed, addr = 0x%lx\n", __func__, addr);
                return -EIO;
        }
 }
@@ -561,7 +561,7 @@ void qlcnic_83xx_cam_unlock(struct qlcnic_adapter *adapter)
 void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                          loff_t offset, size_t size)
 {
-       int ret;
+       int ret = 0;
        u32 data;
 
        if (qlcnic_api_lock(adapter)) {
@@ -571,7 +571,7 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                return;
        }
 
-       ret = qlcnic_83xx_rd_reg_indirect(adapter, (u32) offset);
+       data = QLCRD32(adapter, (u32) offset, &ret);
        qlcnic_api_unlock(adapter);
 
        if (ret == -EIO) {
@@ -580,7 +580,6 @@ void qlcnic_83xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                        __func__, (u32)offset);
                return;
        }
-       data = ret;
        memcpy(buf, &data, size);
 }
 
@@ -2075,18 +2074,25 @@ void qlcnic_83xx_config_intr_coal(struct qlcnic_adapter *adapter)
 static void qlcnic_83xx_handle_link_aen(struct qlcnic_adapter *adapter,
                                        u32 data[])
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u8 link_status, duplex;
        /* link speed */
        link_status = LSB(data[3]) & 1;
-       adapter->ahw->link_speed = MSW(data[2]);
-       adapter->ahw->link_autoneg = MSB(MSW(data[3]));
-       adapter->ahw->module_type = MSB(LSW(data[3]));
-       duplex = LSB(MSW(data[3]));
-       if (duplex)
-               adapter->ahw->link_duplex = DUPLEX_FULL;
-       else
-               adapter->ahw->link_duplex = DUPLEX_HALF;
-       adapter->ahw->has_link_events = 1;
+       if (link_status) {
+               ahw->link_speed = MSW(data[2]);
+               duplex = LSB(MSW(data[3]));
+               if (duplex)
+                       ahw->link_duplex = DUPLEX_FULL;
+               else
+                       ahw->link_duplex = DUPLEX_HALF;
+       } else {
+               ahw->link_speed = SPEED_UNKNOWN;
+               ahw->link_duplex = DUPLEX_UNKNOWN;
+       }
+
+       ahw->link_autoneg = MSB(MSW(data[3]));
+       ahw->module_type = MSB(LSW(data[3]));
+       ahw->has_link_events = 1;
        qlcnic_advert_link_change(adapter, link_status);
 }
 
@@ -2384,9 +2390,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
                                      u32 flash_addr, u8 *p_data,
                                      int count)
 {
-       int i, ret;
-       u32 word, range, flash_offset, addr = flash_addr;
+       u32 word, range, flash_offset, addr = flash_addr, ret;
        ulong indirect_add, direct_window;
+       int i, err = 0;
 
        flash_offset = addr & (QLCNIC_FLASH_SECTOR_SIZE - 1);
        if (addr & 0x3) {
@@ -2404,10 +2410,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
                /* Multi sector read */
                for (i = 0; i < count; i++) {
                        indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
-                       ret = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                         indirect_add);
-                       if (ret == -EIO)
-                               return -EIO;
+                       ret = QLCRD32(adapter, indirect_add, &err);
+                       if (err == -EIO)
+                               return err;
 
                        word = ret;
                        *(u32 *)p_data  = word;
@@ -2428,10 +2433,9 @@ int qlcnic_83xx_lockless_flash_read32(struct qlcnic_adapter *adapter,
                /* Single sector read */
                for (i = 0; i < count; i++) {
                        indirect_add = QLC_83XX_FLASH_DIRECT_DATA(addr);
-                       ret = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                         indirect_add);
-                       if (ret == -EIO)
-                               return -EIO;
+                       ret = QLCRD32(adapter, indirect_add, &err);
+                       if (err == -EIO)
+                               return err;
 
                        word = ret;
                        *(u32 *)p_data  = word;
@@ -2447,10 +2451,13 @@ static int qlcnic_83xx_poll_flash_status_reg(struct qlcnic_adapter *adapter)
 {
        u32 status;
        int retries = QLC_83XX_FLASH_READ_RETRY_COUNT;
+       int err = 0;
 
        do {
-               status = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                    QLC_83XX_FLASH_STATUS);
+               status = QLCRD32(adapter, QLC_83XX_FLASH_STATUS, &err);
+               if (err == -EIO)
+                       return err;
+
                if ((status & QLC_83XX_FLASH_STATUS_READY) ==
                    QLC_83XX_FLASH_STATUS_READY)
                        break;
@@ -2502,7 +2509,8 @@ int qlcnic_83xx_disable_flash_write(struct qlcnic_adapter *adapter)
 
 int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
 {
-       int ret, mfg_id;
+       int ret, err = 0;
+       u32 mfg_id;
 
        if (qlcnic_83xx_lock_flash(adapter))
                return -EIO;
@@ -2517,9 +2525,11 @@ int qlcnic_83xx_read_flash_mfg_id(struct qlcnic_adapter *adapter)
                return -EIO;
        }
 
-       mfg_id = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
-       if (mfg_id == -EIO)
-               return -EIO;
+       mfg_id = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);
+       if (err == -EIO) {
+               qlcnic_83xx_unlock_flash(adapter);
+               return err;
+       }
 
        adapter->flash_mfg_id = (mfg_id & 0xFF);
        qlcnic_83xx_unlock_flash(adapter);
@@ -2636,7 +2646,7 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
                                 u32 *p_data, int count)
 {
        u32 temp;
-       int ret = -EIO;
+       int ret = -EIO, err = 0;
 
        if ((count < QLC_83XX_FLASH_WRITE_MIN) ||
            (count > QLC_83XX_FLASH_WRITE_MAX)) {
@@ -2645,8 +2655,10 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
                return -EIO;
        }
 
-       temp = qlcnic_83xx_rd_reg_indirect(adapter,
-                                          QLC_83XX_FLASH_SPI_CONTROL);
+       temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);
+       if (err == -EIO)
+               return err;
+
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_SPI_CONTROL,
                                     (temp | QLC_83XX_FLASH_SPI_CTRL));
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
@@ -2695,13 +2707,18 @@ int qlcnic_83xx_flash_bulk_write(struct qlcnic_adapter *adapter, u32 addr,
                return -EIO;
        }
 
-       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_SPI_STATUS);
+       ret = QLCRD32(adapter, QLC_83XX_FLASH_SPI_STATUS, &err);
+       if (err == -EIO)
+               return err;
+
        if ((ret & QLC_83XX_FLASH_SPI_CTRL) == QLC_83XX_FLASH_SPI_CTRL) {
                dev_err(&adapter->pdev->dev, "%s: failed at %d\n",
                        __func__, __LINE__);
                /* Operation failed, clear error bit */
-               temp = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                  QLC_83XX_FLASH_SPI_CONTROL);
+               temp = QLCRD32(adapter, QLC_83XX_FLASH_SPI_CONTROL, &err);
+               if (err == -EIO)
+                       return err;
+
                qlcnic_83xx_wrt_reg_indirect(adapter,
                                             QLC_83XX_FLASH_SPI_CONTROL,
                                             (temp | QLC_83XX_FLASH_SPI_CTRL));
@@ -2823,6 +2840,7 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
 {
        int i, j, ret = 0;
        u32 temp;
+       int err = 0;
 
        /* Check alignment */
        if (addr & 0xF)
@@ -2855,8 +2873,12 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
                                             QLCNIC_TA_WRITE_START);
 
                for (j = 0; j < MAX_CTL_CHECK; j++) {
-                       temp = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                          QLCNIC_MS_CTRL);
+                       temp = QLCRD32(adapter, QLCNIC_MS_CTRL, &err);
+                       if (err == -EIO) {
+                               mutex_unlock(&adapter->ahw->mem_lock);
+                               return err;
+                       }
+
                        if ((temp & TA_CTL_BUSY) == 0)
                                break;
                }
@@ -2878,9 +2900,9 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
 int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
                             u8 *p_data, int count)
 {
-       int i, ret;
-       u32 word, addr = flash_addr;
+       u32 word, addr = flash_addr, ret;
        ulong  indirect_addr;
+       int i, err = 0;
 
        if (qlcnic_83xx_lock_flash(adapter) != 0)
                return -EIO;
@@ -2900,10 +2922,10 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
                }
 
                indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
-               ret = qlcnic_83xx_rd_reg_indirect(adapter,
-                                                 indirect_addr);
-               if (ret == -EIO)
-                       return -EIO;
+               ret = QLCRD32(adapter, indirect_addr, &err);
+               if (err == -EIO)
+                       return err;
+
                word = ret;
                *(u32 *)p_data  = word;
                p_data = p_data + 4;
@@ -3014,8 +3036,8 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
        }
 
        if (ahw->port_type == QLCNIC_XGBE) {
-               ecmd->supported = SUPPORTED_1000baseT_Full;
-               ecmd->advertising = ADVERTISED_1000baseT_Full;
+               ecmd->supported = SUPPORTED_10000baseT_Full;
+               ecmd->advertising = ADVERTISED_10000baseT_Full;
        } else {
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
@@ -3244,6 +3266,11 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev)
        u8 val;
        int ret, max_sds_rings = adapter->max_sds_rings;
 
+       if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+               netdev_info(netdev, "Device is resetting\n");
+               return -EBUSY;
+       }
+
        if (qlcnic_get_diag_lock(adapter)) {
                netdev_info(netdev, "Device in diagnostics mode\n");
                return -EBUSY;
@@ -3369,7 +3396,8 @@ int qlcnic_83xx_set_pauseparam(struct qlcnic_adapter *adapter,
 
 static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
 {
-       int ret;
+       int ret, err = 0;
+       u32 temp;
 
        qlcnic_83xx_wrt_reg_indirect(adapter, QLC_83XX_FLASH_ADDR,
                                     QLC_83XX_FLASH_OEM_READ_SIG);
@@ -3379,8 +3407,11 @@ static int qlcnic_83xx_read_flash_status_reg(struct qlcnic_adapter *adapter)
        if (ret)
                return -EIO;
 
-       ret = qlcnic_83xx_rd_reg_indirect(adapter, QLC_83XX_FLASH_RDDATA);
-       return ret & 0xFF;
+       temp = QLCRD32(adapter, QLC_83XX_FLASH_RDDATA, &err);
+       if (err == -EIO)
+               return err;
+
+       return temp & 0xFF;
 }
 
 int qlcnic_83xx_flash_test(struct qlcnic_adapter *adapter)
index 2548d14..272f56a 100644 (file)
@@ -508,7 +508,7 @@ void qlcnic_83xx_add_sysfs(struct qlcnic_adapter *);
 void qlcnic_83xx_remove_sysfs(struct qlcnic_adapter *);
 void qlcnic_83xx_write_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
 void qlcnic_83xx_read_crb(struct qlcnic_adapter *, char *, loff_t, size_t);
-int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong);
+int qlcnic_83xx_rd_reg_indirect(struct qlcnic_adapter *, ulong, int *);
 int qlcnic_83xx_wrt_reg_indirect(struct qlcnic_adapter *, ulong, u32);
 void qlcnic_83xx_process_rcv_diag(struct qlcnic_adapter *, int, u64 []);
 int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *, u32);
index f41dfab..345d987 100644 (file)
@@ -629,7 +629,8 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter)
                return -EIO;
        }
 
-       qlcnic_set_drv_version(adapter);
+       if (adapter->portnum == 0)
+               qlcnic_set_drv_version(adapter);
        qlcnic_83xx_idc_attach_driver(adapter);
 
        return 0;
@@ -1303,8 +1304,11 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
 {
        int i, j;
        u32 val = 0, val1 = 0, reg = 0;
+       int err = 0;
 
-       val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG);
+       val = QLCRD32(adapter, QLC_83XX_SRE_SHIM_REG, &err);
+       if (err == -EIO)
+               return;
        dev_info(&adapter->pdev->dev, "SRE-Shim Ctrl:0x%x\n", val);
 
        for (j = 0; j < 2; j++) {
@@ -1318,7 +1322,9 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
                        reg = QLC_83XX_PORT1_THRESHOLD;
                }
                for (i = 0; i < 8; i++) {
-                       val = QLCRD32(adapter, reg + (i * 0x4));
+                       val = QLCRD32(adapter, reg + (i * 0x4), &err);
+                       if (err == -EIO)
+                               return;
                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
                }
                dev_info(&adapter->pdev->dev, "\n");
@@ -1335,8 +1341,10 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
                        reg = QLC_83XX_PORT1_TC_MC_REG;
                }
                for (i = 0; i < 4; i++) {
-                       val = QLCRD32(adapter, reg + (i * 0x4));
-                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
+                       val = QLCRD32(adapter, reg + (i * 0x4), &err);
+                       if (err == -EIO)
+                               return;
+                       dev_info(&adapter->pdev->dev, "0x%x  ", val);
                }
                dev_info(&adapter->pdev->dev, "\n");
        }
@@ -1352,17 +1360,25 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
                        reg = QLC_83XX_PORT1_TC_STATS;
                }
                for (i = 7; i >= 0; i--) {
-                       val = QLCRD32(adapter, reg);
+                       val = QLCRD32(adapter, reg, &err);
+                       if (err == -EIO)
+                               return;
                        val &= ~(0x7 << 29);    /* Reset bits 29 to 31 */
                        QLCWR32(adapter, reg, (val | (i << 29)));
-                       val = QLCRD32(adapter, reg);
+                       val = QLCRD32(adapter, reg, &err);
+                       if (err == -EIO)
+                               return;
                        dev_info(&adapter->pdev->dev, "0x%x  ", val);
                }
                dev_info(&adapter->pdev->dev, "\n");
        }
 
-       val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD);
-       val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD);
+       val = QLCRD32(adapter, QLC_83XX_PORT2_IFB_THRESHOLD, &err);
+       if (err == -EIO)
+               return;
+       val1 = QLCRD32(adapter, QLC_83XX_PORT3_IFB_THRESHOLD, &err);
+       if (err == -EIO)
+               return;
        dev_info(&adapter->pdev->dev,
                 "IFB-Pause Thresholds: Port 2:0x%x, Port 3:0x%x\n",
                 val, val1);
@@ -1425,7 +1441,7 @@ static void qlcnic_83xx_take_eport_out_of_reset(struct qlcnic_adapter *adapter)
 static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
 {
        u32 heartbeat, peg_status;
-       int retries, ret = -EIO;
+       int retries, ret = -EIO, err = 0;
 
        retries = QLCNIC_HEARTBEAT_CHECK_RETRY_COUNT;
        p_dev->heartbeat = QLC_SHARED_REG_RD32(p_dev,
@@ -1453,11 +1469,11 @@ static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev)
                         "PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,\n"
                         "PEG_NET_4_PC: 0x%x\n", peg_status,
                         QLC_SHARED_REG_RD32(p_dev, QLCNIC_PEG_HALT_STATUS2),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3),
-                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4));
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_0, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_1, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_2, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_3, &err),
+                        QLCRD32(p_dev, QLC_83XX_CRB_PEG_NET_4, &err));
 
                if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
                        dev_err(&p_dev->pdev->dev,
@@ -1501,18 +1517,22 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
 static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
                                int duration, u32 mask, u32 status)
 {
+       int timeout_error, err = 0;
        u32 value;
-       int timeout_error;
        u8 retries;
 
-       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+       value = QLCRD32(p_dev, addr, &err);
+       if (err == -EIO)
+               return err;
        retries = duration / 10;
 
        do {
                if ((value & mask) != status) {
                        timeout_error = 1;
                        msleep(duration / 10);
-                       value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+                       value = QLCRD32(p_dev, addr, &err);
+                       if (err == -EIO)
+                               return err;
                } else {
                        timeout_error = 0;
                        break;
@@ -1606,9 +1626,12 @@ int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
 static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
                                           u32 raddr, u32 waddr)
 {
-       int value;
+       int err = 0;
+       u32 value;
 
-       value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+       value = QLCRD32(p_dev, raddr, &err);
+       if (err == -EIO)
+               return;
        qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
 }
 
@@ -1617,12 +1640,16 @@ static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
                                    u32 raddr, u32 waddr,
                                    struct qlc_83xx_rmw *p_rmw_hdr)
 {
-       int value;
+       int err = 0;
+       u32 value;
 
-       if (p_rmw_hdr->index_a)
+       if (p_rmw_hdr->index_a) {
                value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
-       else
-               value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
+       } else {
+               value = QLCRD32(p_dev, raddr, &err);
+               if (err == -EIO)
+                       return;
+       }
 
        value &= p_rmw_hdr->mask;
        value <<= p_rmw_hdr->shl;
@@ -1675,7 +1702,7 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
        long delay;
        struct qlc_83xx_entry *entry;
        struct qlc_83xx_poll *poll;
-       int i;
+       int i, err = 0;
        unsigned long arg1, arg2;
 
        poll = (struct qlc_83xx_poll *)((char *)p_hdr +
@@ -1699,10 +1726,12 @@ static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
                                                         arg1, delay,
                                                         poll->mask,
                                                         poll->status)){
-                                       qlcnic_83xx_rd_reg_indirect(p_dev,
-                                                                   arg1);
-                                       qlcnic_83xx_rd_reg_indirect(p_dev,
-                                                                   arg2);
+                                       QLCRD32(p_dev, arg1, &err);
+                                       if (err == -EIO)
+                                               return;
+                                       QLCRD32(p_dev, arg2, &err);
+                                       if (err == -EIO)
+                                               return;
                                }
                        }
                }
@@ -1768,7 +1797,7 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
                                       struct qlc_83xx_entry_hdr *p_hdr)
 {
        long delay;
-       int index, i, j;
+       int index, i, j, err;
        struct qlc_83xx_quad_entry *entry;
        struct qlc_83xx_poll *poll;
        unsigned long addr;
@@ -1788,7 +1817,10 @@ static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
                                                  poll->mask, poll->status)){
                                index = p_dev->ahw->reset.array_index;
                                addr = entry->dr_addr;
-                               j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
+                               j = QLCRD32(p_dev, addr, &err);
+                               if (err == -EIO)
+                                       return;
+
                                p_dev->ahw->reset.array[index++] = j;
 
                                if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
@@ -2123,6 +2155,8 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        set_bit(QLC_83XX_MBX_READY, &adapter->ahw->idc.status);
        qlcnic_83xx_clear_function_resources(adapter);
 
+       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
+
        /* register for NIC IDC AEN Events */
        qlcnic_83xx_register_nic_idc_func(adapter, 1);
 
@@ -2140,8 +2174,6 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac)
        if (adapter->nic_ops->init_driver(adapter))
                return -EIO;
 
-       INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work);
-
        /* Periodically monitor device status */
        qlcnic_83xx_idc_poll_dev_state(&adapter->fw_work.work);
 
index 0581a48..d09389b 100644 (file)
@@ -104,7 +104,7 @@ static u32
 qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
 {
        u32 rsp;
-       int timeout = 0;
+       int timeout = 0, err = 0;
 
        do {
                /* give atleast 1ms for firmware to respond */
@@ -113,7 +113,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
                if (++timeout > QLCNIC_OS_CRB_RETRY_COUNT)
                        return QLCNIC_CDRP_RSP_TIMEOUT;
 
-               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET);
+               rsp = QLCRD32(adapter, QLCNIC_CDRP_CRB_OFFSET, &err);
        } while (!QLCNIC_CDRP_IS_RSP(rsp));
 
        return rsp;
@@ -122,7 +122,7 @@ qlcnic_poll_rsp(struct qlcnic_adapter *adapter)
 int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                          struct qlcnic_cmd_args *cmd)
 {
-       int i;
+       int i, err = 0;
        u32 rsp;
        u32 signature;
        struct pci_dev *pdev = adapter->pdev;
@@ -148,7 +148,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                dev_err(&pdev->dev, "card response timeout.\n");
                cmd->rsp.arg[0] = QLCNIC_RCODE_TIMEOUT;
        } else if (rsp == QLCNIC_CDRP_RSP_FAIL) {
-               cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1));
+               cmd->rsp.arg[0] = QLCRD32(adapter, QLCNIC_CDRP_ARG(1), &err);
                switch (cmd->rsp.arg[0]) {
                case QLCNIC_RCODE_INVALID_ARGS:
                        fmt = "CDRP invalid args: [%d]\n";
@@ -175,7 +175,7 @@ int qlcnic_82xx_issue_cmd(struct qlcnic_adapter *adapter,
                cmd->rsp.arg[0] = QLCNIC_RCODE_SUCCESS;
 
        for (i = 1; i < cmd->rsp.num; i++)
-               cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i));
+               cmd->rsp.arg[i] = QLCRD32(adapter, QLCNIC_CDRP_ARG(i), &err);
 
        /* Release semaphore */
        qlcnic_api_unlock(adapter);
@@ -210,10 +210,10 @@ int qlcnic_fw_cmd_set_drv_version(struct qlcnic_adapter *adapter, u32 fw_cmd)
        if (err) {
                dev_info(&adapter->pdev->dev,
                         "Failed to set driver version in firmware\n");
-               return -EIO;
+               err = -EIO;
        }
-
-       return 0;
+       qlcnic_free_mbx_args(&cmd);
+       return err;
 }
 
 int
index 700a463..7aac23a 100644 (file)
@@ -150,6 +150,7 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = {
        "Link_Test_on_offline",
        "Interrupt_Test_offline",
        "Internal_Loopback_offline",
+       "External_Loopback_offline",
        "EEPROM_Test_offline"
 };
 
@@ -266,7 +267,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
 {
        struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 speed, reg;
-       int check_sfp_module = 0;
+       int check_sfp_module = 0, err = 0;
        u16 pcifn = ahw->pci_func;
 
        /* read which mode */
@@ -289,7 +290,7 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
 
        } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
                u32 val = 0;
-               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
+               val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR, &err);
 
                if (val == QLCNIC_PORT_MODE_802_3_AP) {
                        ecmd->supported = SUPPORTED_1000baseT_Full;
@@ -300,9 +301,13 @@ int qlcnic_82xx_get_settings(struct qlcnic_adapter *adapter,
                }
 
                if (netif_running(adapter->netdev) && ahw->has_link_events) {
-                       reg = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
-                       speed = P3P_LINK_SPEED_VAL(pcifn, reg);
-                       ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+                       if (ahw->linkup) {
+                               reg = QLCRD32(adapter,
+                                             P3P_LINK_SPEED_REG(pcifn), &err);
+                               speed = P3P_LINK_SPEED_VAL(pcifn, reg);
+                               ahw->link_speed = speed * P3P_LINK_SPEED_MHZ;
+                       }
+
                        ethtool_cmd_speed_set(ecmd, ahw->link_speed);
                        ecmd->autoneg = ahw->link_autoneg;
                        ecmd->duplex = ahw->link_duplex;
@@ -463,13 +468,14 @@ static int qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 static int qlcnic_82xx_get_registers(struct qlcnic_adapter *adapter,
                                     u32 *regs_buff)
 {
-       int i, j = 0;
+       int i, j = 0, err = 0;
 
        for (i = QLCNIC_DEV_INFO_SIZE + 1; diag_registers[j] != -1; j++, i++)
                regs_buff[i] = QLC_SHARED_REG_RD32(adapter, diag_registers[j]);
        j = 0;
        while (ext_diag_registers[j] != -1)
-               regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++]);
+               regs_buff[i++] = QLCRD32(adapter, ext_diag_registers[j++],
+                                        &err);
        return i;
 }
 
@@ -519,13 +525,16 @@ qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
 static u32 qlcnic_test_link(struct net_device *dev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
+       int err = 0;
        u32 val;
 
        if (qlcnic_83xx_check(adapter)) {
                val = qlcnic_83xx_test_link(adapter);
                return (val & 1) ? 0 : 1;
        }
-       val = QLCRD32(adapter, CRB_XG_STATE_P3P);
+       val = QLCRD32(adapter, CRB_XG_STATE_P3P, &err);
+       if (err == -EIO)
+               return err;
        val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
        return (val == XG_LINK_UP_P3P) ? 0 : 1;
 }
@@ -658,6 +667,7 @@ qlcnic_get_pauseparam(struct net_device *netdev,
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int port = adapter->ahw->physical_port;
+       int err = 0;
        __u32 val;
 
        if (qlcnic_83xx_check(adapter)) {
@@ -668,9 +678,13 @@ qlcnic_get_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return;
                /* get flow control settings */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
+               if (err == -EIO)
+                       return;
                pause->rx_pause = qlcnic_gb_get_rx_flowctl(val);
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return;
                switch (port) {
                case 0:
                        pause->tx_pause = !(qlcnic_gb_get_gb0_mask(val));
@@ -690,7 +704,9 @@ qlcnic_get_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
                        return;
                pause->rx_pause = 1;
-               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return;
                if (port == 0)
                        pause->tx_pause = !(qlcnic_xg_get_xg0_mask(val));
                else
@@ -707,6 +723,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        int port = adapter->ahw->physical_port;
+       int err = 0;
        __u32 val;
 
        if (qlcnic_83xx_check(adapter))
@@ -717,7 +734,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
                        return -EIO;
                /* set flow control */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port));
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), &err);
+               if (err == -EIO)
+                       return err;
 
                if (pause->rx_pause)
                        qlcnic_gb_rx_flowctl(val);
@@ -728,7 +747,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                                val);
                QLCWR32(adapter, QLCNIC_NIU_GB_MAC_CONFIG_0(port), val);
                /* set autoneg */
-               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return err;
                switch (port) {
                case 0:
                        if (pause->tx_pause)
@@ -764,7 +785,9 @@ qlcnic_set_pauseparam(struct net_device *netdev,
                if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
                        return -EIO;
 
-               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL);
+               val = QLCRD32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, &err);
+               if (err == -EIO)
+                       return err;
                if (port == 0) {
                        if (pause->tx_pause)
                                qlcnic_xg_unset_xg0_mask(val);
@@ -788,11 +811,14 @@ static int qlcnic_reg_test(struct net_device *dev)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 data_read;
+       int err = 0;
 
        if (qlcnic_83xx_check(adapter))
                return qlcnic_83xx_reg_test(adapter);
 
-       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0));
+       data_read = QLCRD32(adapter, QLCNIC_PCIX_PH_REG(0), &err);
+       if (err == -EIO)
+               return err;
        if ((data_read & 0xffff) != adapter->pdev->vendor)
                return 1;
 
@@ -1026,8 +1052,15 @@ qlcnic_diag_test(struct net_device *dev, struct ethtool_test *eth_test,
                if (data[3])
                        eth_test->flags |= ETH_TEST_FL_FAILED;
 
-               data[4] = qlcnic_eeprom_test(dev);
-               if (data[4])
+               if (eth_test->flags & ETH_TEST_FL_EXTERNAL_LB) {
+                       data[4] = qlcnic_loopback_test(dev, QLCNIC_ELB_MODE);
+                       if (data[4])
+                               eth_test->flags |= ETH_TEST_FL_FAILED;
+                       eth_test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE;
+               }
+
+               data[5] = qlcnic_eeprom_test(dev);
+               if (data[5])
                        eth_test->flags |= ETH_TEST_FL_FAILED;
        }
 }
@@ -1257,17 +1290,20 @@ qlcnic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
+       int err = 0;
 
        if (qlcnic_83xx_check(adapter))
                return;
        wol->supported = 0;
        wol->wolopts = 0;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
+       if (err == -EIO)
+               return;
        if (wol_cfg & (1UL << adapter->portnum))
                wol->supported |= WAKE_MAGIC;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
        if (wol_cfg & (1UL << adapter->portnum))
                wol->wolopts |= WAKE_MAGIC;
 }
@@ -1277,17 +1313,22 @@ qlcnic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct qlcnic_adapter *adapter = netdev_priv(dev);
        u32 wol_cfg;
+       int err = 0;
 
        if (qlcnic_83xx_check(adapter))
                return -EOPNOTSUPP;
        if (wol->wolopts & ~WAKE_MAGIC)
                return -EINVAL;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
+       if (err == -EIO)
+               return err;
        if (!(wol_cfg & (1 << adapter->portnum)))
                return -EOPNOTSUPP;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
+       if (err == -EIO)
+               return err;
        if (wol->wolopts & WAKE_MAGIC)
                wol_cfg |= 1UL << adapter->portnum;
        else
@@ -1540,7 +1581,7 @@ qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
                return 0;
        case QLCNIC_SET_QUIESCENT:
        case QLCNIC_RESET_QUIESCENT:
-               state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+               state = QLC_SHARED_REG_RD32(adapter, QLCNIC_CRB_DEV_STATE);
                if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
                        netdev_info(netdev, "Device in FAILED state\n");
                return 0;
index 5b5d2ed..4d5f59b 100644 (file)
@@ -317,16 +317,20 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
 int
 qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 {
-       int done = 0, timeout = 0;
+       int timeout = 0;
+       int err = 0;
+       u32 done = 0;
 
        while (!done) {
-               done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)));
+               done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
+                              &err);
                if (done == 1)
                        break;
                if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
                        dev_err(&adapter->pdev->dev,
                                "Failed to acquire sem=%d lock; holdby=%d\n",
-                               sem, id_reg ? QLCRD32(adapter, id_reg) : -1);
+                               sem,
+                               id_reg ? QLCRD32(adapter, id_reg, &err) : -1);
                        return -EIO;
                }
                msleep(1);
@@ -341,19 +345,22 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 void
 qlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
 {
-       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)));
+       int err = 0;
+
+       QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err);
 }
 
 int qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
 {
+       int err = 0;
        u32 data;
 
        if (qlcnic_82xx_check(adapter))
                qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
        else {
-               data = qlcnic_83xx_rd_reg_indirect(adapter, addr);
-               if (data == -EIO)
-                       return -EIO;
+               data = QLCRD32(adapter, addr, &err);
+               if (err == -EIO)
+                       return err;
        }
        return data;
 }
@@ -516,20 +523,18 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
        if (netdev->flags & IFF_PROMISC) {
                if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
                        mode = VPORT_MISS_MODE_ACCEPT_ALL;
-       } else if (netdev->flags & IFF_ALLMULTI) {
-               if (netdev_mc_count(netdev) > ahw->max_mc_count) {
-                       mode = VPORT_MISS_MODE_ACCEPT_MULTI;
-               } else if (!netdev_mc_empty(netdev) &&
-                          !qlcnic_sriov_vf_check(adapter)) {
-                               netdev_for_each_mc_addr(ha, netdev)
-                                       qlcnic_nic_add_mac(adapter, ha->addr,
-                                                          vlan);
-               }
-               if (mode != VPORT_MISS_MODE_ACCEPT_MULTI &&
-                   qlcnic_sriov_vf_check(adapter))
-                       qlcnic_vf_add_mc_list(netdev, vlan);
+       } else if ((netdev->flags & IFF_ALLMULTI) ||
+                  (netdev_mc_count(netdev) > ahw->max_mc_count)) {
+               mode = VPORT_MISS_MODE_ACCEPT_MULTI;
+       } else if (!netdev_mc_empty(netdev) &&
+                  !qlcnic_sriov_vf_check(adapter)) {
+               netdev_for_each_mc_addr(ha, netdev)
+                       qlcnic_nic_add_mac(adapter, ha->addr, vlan);
        }
 
+       if (qlcnic_sriov_vf_check(adapter))
+               qlcnic_vf_add_mc_list(netdev, vlan);
+
        /* configure unicast MAC address, if there is not sufficient space
         * to store all the unicast addresses then enable promiscuous mode
         */
@@ -1161,7 +1166,8 @@ int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
        return -EIO;
 }
 
-int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off,
+                             int *err)
 {
        unsigned long flags;
        int rv;
@@ -1417,7 +1423,7 @@ int qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
 
 int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
 {
-       int offset, board_type, magic;
+       int offset, board_type, magic, err = 0;
        struct pci_dev *pdev = adapter->pdev;
 
        offset = QLCNIC_FW_MAGIC_OFFSET;
@@ -1437,7 +1443,9 @@ int qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
        adapter->ahw->board_type = board_type;
 
        if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
-               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
+               u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err);
+               if (err == -EIO)
+                       return err;
                if ((gpio & 0x8000) == 0)
                        board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
        }
@@ -1477,10 +1485,13 @@ int
 qlcnic_wol_supported(struct qlcnic_adapter *adapter)
 {
        u32 wol_cfg;
+       int err = 0;
 
-       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV);
+       wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
        if (wol_cfg & (1UL << adapter->portnum)) {
-               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG);
+               wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
+               if (err == -EIO)
+                       return err;
                if (wol_cfg & (1 << adapter->portnum))
                        return 1;
        }
@@ -1541,6 +1552,7 @@ void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
 void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                          loff_t offset, size_t size)
 {
+       int err = 0;
        u32 data;
        u64 qmdata;
 
@@ -1548,7 +1560,7 @@ void qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
                qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
                memcpy(buf, &qmdata, size);
        } else {
-               data = QLCRD32(adapter, offset);
+               data = QLCRD32(adapter, offset, &err);
                memcpy(buf, &data, size);
        }
 }
index 2c22504..4a71b28 100644 (file)
@@ -154,7 +154,7 @@ struct qlcnic_hardware_context;
 struct qlcnic_adapter;
 
 int qlcnic_82xx_start_firmware(struct qlcnic_adapter *);
-int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong);
+int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *);
 int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32);
 int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int);
 int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32);
index d28336f..974d626 100644 (file)
@@ -142,7 +142,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter)
                                         buffrag->length, PCI_DMA_TODEVICE);
                        buffrag->dma = 0ULL;
                }
-               for (j = 0; j < cmd_buf->frag_count; j++) {
+               for (j = 1; j < cmd_buf->frag_count; j++) {
                        buffrag++;
                        if (buffrag->dma) {
                                pci_unmap_page(adapter->pdev, buffrag->dma,
@@ -286,10 +286,11 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
 {
        long timeout = 0;
        long done = 0;
+       int err = 0;
 
        cond_resched();
        while (done == 0) {
-               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS);
+               done = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_STATUS, &err);
                done &= 2;
                if (++timeout >= QLCNIC_MAX_ROM_WAIT_USEC) {
                        dev_err(&adapter->pdev->dev,
@@ -304,6 +305,8 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
 static int do_rom_fast_read(struct qlcnic_adapter *adapter,
                            u32 addr, u32 *valp)
 {
+       int err = 0;
+
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ABYTE_CNT, 3);
@@ -317,7 +320,9 @@ static int do_rom_fast_read(struct qlcnic_adapter *adapter,
        udelay(10);
        QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 
-       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA);
+       *valp = QLCRD32(adapter, QLCNIC_ROMUSB_ROM_RDATA, &err);
+       if (err == -EIO)
+               return err;
        return 0;
 }
 
@@ -369,11 +374,11 @@ int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp)
 
 int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
 {
-       int addr, val;
+       int addr, err = 0;
        int i, n, init_delay;
        struct crb_addr_pair *buf;
        unsigned offset;
-       u32 off;
+       u32 off, val;
        struct pci_dev *pdev = adapter->pdev;
 
        QLC_SHARED_REG_WR32(adapter, QLCNIC_CMDPEG_STATE, 0);
@@ -402,7 +407,9 @@ int qlcnic_pinit_from_rom(struct qlcnic_adapter *adapter)
        QLCWR32(adapter, QLCNIC_CRB_NIU + 0xb0000, 0x00);
 
        /* halt sre */
-       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000);
+       val = QLCRD32(adapter, QLCNIC_CRB_SRE + 0x1000, &err);
+       if (err == -EIO)
+               return err;
        QLCWR32(adapter, QLCNIC_CRB_SRE + 0x1000, val & (~(0x1)));
 
        /* halt epg */
@@ -719,10 +726,12 @@ qlcnic_check_flash_fw_ver(struct qlcnic_adapter *adapter)
 static int
 qlcnic_has_mn(struct qlcnic_adapter *adapter)
 {
-       u32 capability;
-       capability = 0;
+       u32 capability = 0;
+       int err = 0;
 
-       capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY);
+       capability = QLCRD32(adapter, QLCNIC_PEG_TUNE_CAPABILITY, &err);
+       if (err == -EIO)
+               return err;
        if (capability & QLCNIC_PEG_TUNE_MN_PRESENT)
                return 1;
 
index d3f8797..6946d35 100644 (file)
@@ -161,36 +161,68 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
        return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
 }
 
+static void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter,
+                                     struct qlcnic_filter *fil,
+                                     void *addr, u16 vlan_id)
+{
+       int ret;
+       u8 op;
+
+       op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+       ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
+       if (ret)
+               return;
+
+       op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
+       ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
+       if (!ret) {
+               hlist_del(&fil->fnode);
+               adapter->rx_fhash.fnum--;
+       }
+}
+
+static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,
+                                                   void *addr, u16 vlan_id)
+{
+       struct qlcnic_filter *tmp_fil = NULL;
+       struct hlist_node *n;
+
+       hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
+               if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) &&
+                   tmp_fil->vlan_id == vlan_id)
+                       return tmp_fil;
+       }
+
+       return NULL;
+}
+
 void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
                          int loopback_pkt, u16 vlan_id)
 {
        struct ethhdr *phdr = (struct ethhdr *)(skb->data);
        struct qlcnic_filter *fil, *tmp_fil;
-       struct hlist_node *n;
        struct hlist_head *head;
        unsigned long time;
        u64 src_addr = 0;
-       u8 hindex, found = 0, op;
+       u8 hindex, op;
        int ret;
 
        memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+       hindex = qlcnic_mac_hash(src_addr) &
+                (adapter->fhash.fbucket_size - 1);
 
        if (loopback_pkt) {
                if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
                        return;
 
-               hindex = qlcnic_mac_hash(src_addr) &
-                        (adapter->fhash.fbucket_size - 1);
                head = &(adapter->rx_fhash.fhead[hindex]);
 
-               hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
-                       if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-                           tmp_fil->vlan_id == vlan_id) {
-                               time = tmp_fil->ftime;
-                               if (jiffies > (QLCNIC_READD_AGE * HZ + time))
-                                       tmp_fil->ftime = jiffies;
-                               return;
-                       }
+               tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+               if (tmp_fil) {
+                       time = tmp_fil->ftime;
+                       if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time))
+                               tmp_fil->ftime = jiffies;
+                       return;
                }
 
                fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
@@ -205,36 +237,37 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
                adapter->rx_fhash.fnum++;
                spin_unlock(&adapter->rx_mac_learn_lock);
        } else {
-               hindex = qlcnic_mac_hash(src_addr) &
-                        (adapter->fhash.fbucket_size - 1);
-               head = &(adapter->rx_fhash.fhead[hindex]);
-               spin_lock(&adapter->rx_mac_learn_lock);
-               hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
-                       if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
-                           tmp_fil->vlan_id == vlan_id) {
-                               found = 1;
-                               break;
-                       }
-               }
+               head = &adapter->fhash.fhead[hindex];
 
-               if (!found) {
-                       spin_unlock(&adapter->rx_mac_learn_lock);
-                       return;
-               }
+               spin_lock(&adapter->mac_learn_lock);
 
-               op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
-               ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr,
-                                               vlan_id, op);
-               if (!ret) {
+               tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+               if (tmp_fil) {
                        op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
                        ret = qlcnic_sre_macaddr_change(adapter,
                                                        (u8 *)&src_addr,
                                                        vlan_id, op);
                        if (!ret) {
-                               hlist_del(&(tmp_fil->fnode));
-                               adapter->rx_fhash.fnum--;
+                               hlist_del(&tmp_fil->fnode);
+                               adapter->fhash.fnum--;
                        }
+
+                       spin_unlock(&adapter->mac_learn_lock);
+
+                       return;
                }
+
+               spin_unlock(&adapter->mac_learn_lock);
+
+               head = &adapter->rx_fhash.fhead[hindex];
+
+               spin_lock(&adapter->rx_mac_learn_lock);
+
+               tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
+               if (tmp_fil)
+                       qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr,
+                                                 vlan_id);
+
                spin_unlock(&adapter->rx_mac_learn_lock);
        }
 }
@@ -262,7 +295,7 @@ void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr,
 
        mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
        mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
-       memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+       memcpy(mac_req->mac_addr, uaddr, ETH_ALEN);
 
        vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
        vlan_req->vlan_id = cpu_to_le16(vlan_id);
index 4528f8e..bc05d01 100644 (file)
@@ -977,8 +977,8 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
 static int
 qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
 {
-       int err;
        struct qlcnic_info nic_info;
+       int err = 0;
 
        memset(&nic_info, 0, sizeof(struct qlcnic_info));
        err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func);
@@ -993,7 +993,9 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
 
        if (adapter->ahw->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
                u32 temp;
-               temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+               temp = QLCRD32(adapter, CRB_FW_CAPABILITIES_2, &err);
+               if (err == -EIO)
+                       return err;
                adapter->ahw->extra_capability[0] = temp;
        }
        adapter->ahw->max_mac_filters = nic_info.max_mac_filters;
@@ -1383,6 +1385,8 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
        if (adapter->ahw->diag_test == QLCNIC_INTERRUPT_TEST) {
                if (qlcnic_82xx_check(adapter))
                        handler = qlcnic_tmp_intr;
+               else
+                       handler = qlcnic_83xx_tmp_intr;
                if (!QLCNIC_IS_MSI_FAMILY(adapter))
                        flags |= IRQF_SHARED;
 
@@ -1531,12 +1535,12 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        if (netdev->features & NETIF_F_LRO)
                qlcnic_config_hw_lro(adapter, QLCNIC_LRO_ENABLED);
 
+       set_bit(__QLCNIC_DEV_UP, &adapter->state);
        qlcnic_napi_enable(adapter);
 
        qlcnic_linkevent_request(adapter, 1);
 
        adapter->ahw->reset_context = 0;
-       set_bit(__QLCNIC_DEV_UP, &adapter->state);
        return 0;
 }
 
@@ -2139,7 +2143,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (qlcnic_83xx_check(adapter) && !qlcnic_use_msi_x &&
            !!qlcnic_use_msi)
                dev_warn(&pdev->dev,
-                        "83xx adapter do not support MSI interrupts\n");
+                        "Device does not support MSI interrupts\n");
 
        err = qlcnic_setup_intr(adapter, 0);
        if (err) {
@@ -2161,7 +2165,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                goto err_out_disable_mbx_intr;
 
-       qlcnic_set_drv_version(adapter);
+       if (adapter->portnum == 0)
+               qlcnic_set_drv_version(adapter);
 
        pci_set_drvdata(pdev, adapter);
 
@@ -3081,7 +3086,8 @@ done:
        adapter->fw_fail_cnt = 0;
        adapter->flags &= ~QLCNIC_FW_HANG;
        clear_bit(__QLCNIC_RESETTING, &adapter->state);
-       qlcnic_set_drv_version(adapter);
+       if (adapter->portnum == 0)
+               qlcnic_set_drv_version(adapter);
 
        if (!qlcnic_clr_drv_state(adapter))
                qlcnic_schedule_work(adapter, qlcnic_fw_poll_work,
@@ -3093,6 +3099,7 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
 {
        u32 state = 0, heartbeat;
        u32 peg_status;
+       int err = 0;
 
        if (qlcnic_check_temp(adapter))
                goto detach;
@@ -3139,11 +3146,11 @@ qlcnic_check_health(struct qlcnic_adapter *adapter)
                        "PEG_NET_4_PC: 0x%x\n",
                        peg_status,
                        QLC_SHARED_REG_RD32(adapter, QLCNIC_PEG_HALT_STATUS2),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c),
-                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c));
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_0 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_1 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_2 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_3 + 0x3c, &err),
+                       QLCRD32(adapter, QLCNIC_CRB_PEG_NET_4 + 0x3c, &err));
        if (QLCNIC_FWERROR_CODE(peg_status) == 0x67)
                dev_err(&adapter->pdev->dev,
                        "Firmware aborted with error code 0x00006700. "
index ab8a674..79e54ef 100644 (file)
@@ -1084,7 +1084,7 @@ flash_temp:
        tmpl_hdr = ahw->fw_dump.tmpl_hdr;
        tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
 
-       if ((tmpl_hdr->version & 0xffffff) >= 0x20001)
+       if ((tmpl_hdr->version & 0xfffff) >= 0x20001)
                ahw->fw_dump.use_pex_dma = true;
        else
                ahw->fw_dump.use_pex_dma = false;
index 62380ce..5d40045 100644 (file)
@@ -562,7 +562,7 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
        INIT_LIST_HEAD(&adapter->vf_mc_list);
        if (!qlcnic_use_msi_x && !!qlcnic_use_msi)
                dev_warn(&adapter->pdev->dev,
-                        "83xx adapter do not support MSI interrupts\n");
+                        "Device does not support MSI interrupts\n");
 
        err = qlcnic_setup_intr(adapter, 1);
        if (err) {
@@ -762,6 +762,7 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type)
                        memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num);
                        mbx->req.arg[0] = (type | (mbx->req.num << 16) |
                                           (3 << 29));
+                       mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16;
                        return 0;
                }
        }
@@ -813,6 +814,7 @@ static int qlcnic_sriov_prepare_bc_hdr(struct qlcnic_bc_trans *trans,
                cmd->req.num = trans->req_pay_size / 4;
                cmd->rsp.num = trans->rsp_pay_size / 4;
                hdr = trans->rsp_hdr;
+               cmd->op_type = trans->req_hdr->op_type;
        }
 
        trans->trans_id = seq;
index ee0c1d3..eb49cd6 100644 (file)
@@ -635,12 +635,12 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
                                           struct qlcnic_cmd_args *cmd)
 {
        struct qlcnic_vf_info *vf = trans->vf;
-       struct qlcnic_adapter *adapter = vf->adapter;
-       int err;
+       struct qlcnic_vport *vp = vf->vp;
+       struct qlcnic_adapter *adapter;
        u16 func = vf->pci_func;
+       int err;
 
-       cmd->rsp.arg[0] = trans->req_hdr->cmd_op;
-       cmd->rsp.arg[0] |= (1 << 16);
+       adapter = vf->adapter;
 
        if (trans->req_hdr->cmd_op == QLCNIC_BC_CMD_CHANNEL_INIT) {
                err = qlcnic_sriov_pf_config_vport(adapter, 1, func);
@@ -650,6 +650,8 @@ static int qlcnic_sriov_pf_channel_cfg_cmd(struct qlcnic_bc_trans *trans,
                                qlcnic_sriov_pf_config_vport(adapter, 0, func);
                }
        } else {
+               if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+                       vp->vlan = 0;
                err = qlcnic_sriov_pf_config_vport(adapter, 0, func);
        }
 
@@ -1183,7 +1185,7 @@ static int qlcnic_sriov_pf_get_acl_cmd(struct qlcnic_bc_trans *trans,
        u8 cmd_op, mode = vp->vlan_mode;
 
        cmd_op = trans->req_hdr->cmd_op;
-       cmd->rsp.arg[0] = (cmd_op & 0xffff) | 14 << 16 | 1 << 25;
+       cmd->rsp.arg[0] |= 1 << 25;
 
        switch (mode) {
        case QLC_GUEST_VLAN_MODE:
@@ -1561,6 +1563,7 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
                                struct qlcnic_vf_info *vf)
 {
        struct net_device *dev = vf->adapter->netdev;
+       struct qlcnic_vport *vp = vf->vp;
 
        if (!test_and_clear_bit(QLC_BC_VF_STATE, &vf->state)) {
                clear_bit(QLC_BC_VF_FLR, &vf->state);
@@ -1573,6 +1576,9 @@ void qlcnic_sriov_pf_handle_flr(struct qlcnic_sriov *sriov,
                return;
        }
 
+       if (vp->vlan_mode == QLC_GUEST_VLAN_MODE)
+               vp->vlan = 0;
+
        qlcnic_sriov_schedule_flr(sriov, vf, qlcnic_sriov_pf_process_flr);
        netdev_info(dev, "FLR received for PCI func %d\n", vf->pci_func);
 }
@@ -1621,13 +1627,15 @@ int qlcnic_sriov_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
 {
        struct qlcnic_adapter *adapter = netdev_priv(netdev);
        struct qlcnic_sriov *sriov = adapter->ahw->sriov;
-       int i, num_vfs = sriov->num_vfs;
+       int i, num_vfs;
        struct qlcnic_vf_info *vf_info;
        u8 *curr_mac;
 
        if (!qlcnic_sriov_pf_check(adapter))
                return -EOPNOTSUPP;
 
+       num_vfs = sriov->num_vfs;
+
        if (!is_valid_ether_addr(mac) || vf >= num_vfs)
                return -EINVAL;
 
@@ -1741,6 +1749,7 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
 
        switch (vlan) {
        case 4095:
+               vp->vlan = 0;
                vp->vlan_mode = QLC_GUEST_VLAN_MODE;
                break;
        case 0:
@@ -1759,6 +1768,29 @@ int qlcnic_sriov_set_vf_vlan(struct net_device *netdev, int vf,
        return 0;
 }
 
+static inline __u32 qlcnic_sriov_get_vf_vlan(struct qlcnic_adapter *adapter,
+                                            struct qlcnic_vport *vp, int vf)
+{
+       __u32 vlan = 0;
+
+       switch (vp->vlan_mode) {
+       case QLC_PVID_MODE:
+               vlan = vp->vlan;
+               break;
+       case QLC_GUEST_VLAN_MODE:
+               vlan = MAX_VLAN_ID;
+               break;
+       case QLC_NO_VLAN_MODE:
+               vlan = 0;
+               break;
+       default:
+               netdev_info(adapter->netdev, "Invalid VLAN mode = %d for VF %d\n",
+                           vp->vlan_mode, vf);
+       }
+
+       return vlan;
+}
+
 int qlcnic_sriov_get_vf_config(struct net_device *netdev,
                               int vf, struct ifla_vf_info *ivi)
 {
@@ -1774,7 +1806,7 @@ int qlcnic_sriov_get_vf_config(struct net_device *netdev,
 
        vp = sriov->vf_info[vf].vp;
        memcpy(&ivi->mac, vp->mac, ETH_ALEN);
-       ivi->vlan = vp->vlan;
+       ivi->vlan = qlcnic_sriov_get_vf_vlan(adapter, vp, vf);
        ivi->qos = vp->qos;
        ivi->spoofchk = vp->spoofchk;
        if (vp->max_tx_bw == MAX_BW)
index 10ed82b..660c3f5 100644 (file)
@@ -170,9 +170,9 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter,
 
        if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
                err = qlcnic_get_beacon_state(adapter, &h_beacon_state);
-               if (!err) {
-                       dev_info(&adapter->pdev->dev,
-                                "Failed to get current beacon state\n");
+               if (err) {
+                       netdev_err(adapter->netdev,
+                                  "Failed to get current beacon state\n");
                } else {
                        if (h_beacon_state == QLCNIC_BEACON_DISABLE)
                                ahw->beacon_state = 0;
index e6acb9f..d2e5919 100644 (file)
@@ -478,7 +478,7 @@ rx_status_loop:
 
        while (1) {
                u32 status, len;
-               dma_addr_t mapping;
+               dma_addr_t mapping, new_mapping;
                struct sk_buff *skb, *new_skb;
                struct cp_desc *desc;
                const unsigned buflen = cp->rx_buf_sz;
@@ -520,6 +520,14 @@ rx_status_loop:
                        goto rx_next;
                }
 
+               new_mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
+                                        PCI_DMA_FROMDEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, new_mapping)) {
+                       dev->stats.rx_dropped++;
+                       kfree_skb(new_skb);
+                       goto rx_next;
+               }
+
                dma_unmap_single(&cp->pdev->dev, mapping,
                                 buflen, PCI_DMA_FROMDEVICE);
 
@@ -531,12 +539,11 @@ rx_status_loop:
 
                skb_put(skb, len);
 
-               mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
-                                        PCI_DMA_FROMDEVICE);
                cp->rx_skb[rx_tail] = new_skb;
 
                cp_rx_skb(cp, skb, desc);
                rx++;
+               mapping = new_mapping;
 
 rx_next:
                cp->rx_ring[rx_tail].opts2 = 0;
@@ -716,6 +723,22 @@ static inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
                TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
 }
 
+static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb,
+                                  int first, int entry_last)
+{
+       int frag, index;
+       struct cp_desc *txd;
+       skb_frag_t *this_frag;
+       for (frag = 0; frag+first < entry_last; frag++) {
+               index = first+frag;
+               cp->tx_skb[index] = NULL;
+               txd = &cp->tx_ring[index];
+               this_frag = &skb_shinfo(skb)->frags[frag];
+               dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
+                                skb_frag_size(this_frag), PCI_DMA_TODEVICE);
+       }
+}
+
 static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                                        struct net_device *dev)
 {
@@ -749,6 +772,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
 
                len = skb->len;
                mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, mapping))
+                       goto out_dma_error;
+
                txd->opts2 = opts2;
                txd->addr = cpu_to_le64(mapping);
                wmb();
@@ -786,6 +812,9 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                first_len = skb_headlen(skb);
                first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
                                               first_len, PCI_DMA_TODEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, first_mapping))
+                       goto out_dma_error;
+
                cp->tx_skb[entry] = skb;
                entry = NEXT_TX(entry);
 
@@ -799,6 +828,11 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
                        mapping = dma_map_single(&cp->pdev->dev,
                                                 skb_frag_address(this_frag),
                                                 len, PCI_DMA_TODEVICE);
+                       if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+                               unwind_tx_frag_mapping(cp, skb, first_entry, entry);
+                               goto out_dma_error;
+                       }
+
                        eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 
                        ctrl = eor | len | DescOwn;
@@ -859,11 +893,16 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
        if (TX_BUFFS_AVAIL(cp) <= (MAX_SKB_FRAGS + 1))
                netif_stop_queue(dev);
 
+out_unlock:
        spin_unlock_irqrestore(&cp->lock, intr_flags);
 
        cpw8(TxPoll, NormalTxPoll);
 
        return NETDEV_TX_OK;
+out_dma_error:
+       kfree_skb(skb);
+       cp->dev->stats.tx_dropped++;
+       goto out_unlock;
 }
 
 /* Set or clear the multicast filter for this adaptor.
@@ -1054,6 +1093,10 @@ static int cp_refill_rx(struct cp_private *cp)
 
                mapping = dma_map_single(&cp->pdev->dev, skb->data,
                                         cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               if (dma_mapping_error(&cp->pdev->dev, mapping)) {
+                       kfree_skb(skb);
+                       goto err_out;
+               }
                cp->rx_skb[i] = skb;
 
                cp->rx_ring[i].opts2 = 0;
index 4106a74..b5eb419 100644 (file)
@@ -3689,7 +3689,7 @@ static void rtl_phy_work(struct rtl8169_private *tp)
        if (tp->link_ok(ioaddr))
                return;
 
-       netif_warn(tp, link, tp->dev, "PHY reset until link up\n");
+       netif_dbg(tp, link, tp->dev, "PHY reset until link up\n");
 
        tp->phy_reset_enable(tp);
 
@@ -6468,6 +6468,8 @@ static int rtl8169_close(struct net_device *dev)
        rtl8169_down(dev);
        rtl_unlock_work(tp);
 
+       cancel_work_sync(&tp->wk.work);
+
        free_irq(pdev->irq, dev);
 
        dma_free_coherent(&pdev->dev, R8169_RX_RING_BYTES, tp->RxDescArray,
@@ -6793,8 +6795,6 @@ static void rtl_remove_one(struct pci_dev *pdev)
                rtl8168_driver_stop(tp);
        }
 
-       cancel_work_sync(&tp->wk.work);
-
        netif_napi_del(&tp->napi);
 
        unregister_netdev(dev);
index b74a60a..2a469b2 100644 (file)
@@ -1209,7 +1209,9 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
        EFX_BUG_ON_PARANOID(skb_headlen(skb) < nhoff + 4 * ip->ihl + 4);
        ports = (const __be16 *)(skb->data + nhoff + 4 * ip->ihl);
 
-       efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT, 0, rxq_index);
+       efx_filter_init_rx(&spec, EFX_FILTER_PRI_HINT,
+                          efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
+                          rxq_index);
        rc = efx_filter_set_ipv4_full(&spec, ip->protocol,
                                      ip->daddr, ports[1], ip->saddr, ports[0]);
        if (rc)
index eb4aea3..f5d7ad7 100644 (file)
@@ -1318,7 +1318,7 @@ static void sis900_timer(unsigned long data)
                if (duplex){
                        sis900_set_mode(sis_priv, speed, duplex);
                        sis630_set_eq(net_dev, sis_priv->chipset_rev);
-                       netif_start_queue(net_dev);
+                       netif_carrier_on(net_dev);
                }
 
                sis_priv->timer.expires = jiffies + HZ;
@@ -1336,10 +1336,8 @@ static void sis900_timer(unsigned long data)
                status = sis900_default_phy(net_dev);
                mii_phy = sis_priv->mii;
 
-               if (status & MII_STAT_LINK){
+               if (status & MII_STAT_LINK)
                        sis900_check_mode(net_dev, mii_phy);
-                       netif_carrier_on(net_dev);
-               }
        } else {
        /* Link ON -> OFF */
                 if (!(status & MII_STAT_LINK)){
@@ -1612,12 +1610,6 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
        unsigned int  index_cur_tx, index_dirty_tx;
        unsigned int  count_dirty_tx;
 
-       /* Don't transmit data before the complete of auto-negotiation */
-       if(!sis_priv->autong_complete){
-               netif_stop_queue(net_dev);
-               return NETDEV_TX_BUSY;
-       }
-
        spin_lock_irqsave(&sis_priv->lock, flags);
 
        /* Calculate the next Tx descriptor entry. */
index c9d942a..1ef9d8a 100644 (file)
@@ -33,10 +33,15 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
        struct stmmac_priv *priv = (struct stmmac_priv *)p;
        unsigned int txsize = priv->dma_tx_size;
        unsigned int entry = priv->cur_tx % txsize;
-       struct dma_desc *desc = priv->dma_tx + entry;
+       struct dma_desc *desc;
        unsigned int nopaged_len = skb_headlen(skb);
        unsigned int bmax, len;
 
+       if (priv->extend_desc)
+               desc = (struct dma_desc *)(priv->dma_etx + entry);
+       else
+               desc = priv->dma_tx + entry;
+
        if (priv->plat->enh_desc)
                bmax = BUF_SIZE_8KiB;
        else
@@ -54,7 +59,11 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
                                                STMMAC_RING_MODE);
                wmb();
                entry = (++priv->cur_tx) % txsize;
-               desc = priv->dma_tx + entry;
+
+               if (priv->extend_desc)
+                       desc = (struct dma_desc *)(priv->dma_etx + entry);
+               else
+                       desc = priv->dma_tx + entry;
 
                desc->des2 = dma_map_single(priv->device, skb->data + bmax,
                                            len, DMA_TO_DEVICE);
index f2ccb36..0a9bb9d 100644 (file)
@@ -939,15 +939,20 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
 
        skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
                                 GFP_KERNEL);
-       if (unlikely(skb == NULL)) {
+       if (!skb) {
                pr_err("%s: Rx init fails; skb is NULL\n", __func__);
-               return 1;
+               return -ENOMEM;
        }
        skb_reserve(skb, NET_IP_ALIGN);
        priv->rx_skbuff[i] = skb;
        priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
                                                priv->dma_buf_sz,
                                                DMA_FROM_DEVICE);
+       if (dma_mapping_error(priv->device, priv->rx_skbuff_dma[i])) {
+               pr_err("%s: DMA mapping error\n", __func__);
+               dev_kfree_skb_any(skb);
+               return -EINVAL;
+       }
 
        p->des2 = priv->rx_skbuff_dma[i];
 
@@ -958,6 +963,16 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
        return 0;
 }
 
+static void stmmac_free_rx_buffers(struct stmmac_priv *priv, int i)
+{
+       if (priv->rx_skbuff[i]) {
+               dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
+                                priv->dma_buf_sz, DMA_FROM_DEVICE);
+               dev_kfree_skb_any(priv->rx_skbuff[i]);
+       }
+       priv->rx_skbuff[i] = NULL;
+}
+
 /**
  * init_dma_desc_rings - init the RX/TX descriptor rings
  * @dev: net device structure
@@ -965,13 +980,14 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,
  * and allocates the socket buffers. It suppors the chained and ring
  * modes.
  */
-static void init_dma_desc_rings(struct net_device *dev)
+static int init_dma_desc_rings(struct net_device *dev)
 {
        int i;
        struct stmmac_priv *priv = netdev_priv(dev);
        unsigned int txsize = priv->dma_tx_size;
        unsigned int rxsize = priv->dma_rx_size;
        unsigned int bfsize = 0;
+       int ret = -ENOMEM;
 
        /* Set the max buffer size according to the DESC mode
         * and the MTU. Note that RING mode allows 16KiB bsize.
@@ -992,34 +1008,60 @@ static void init_dma_desc_rings(struct net_device *dev)
                                                          dma_extended_desc),
                                                   &priv->dma_rx_phy,
                                                   GFP_KERNEL);
+               if (!priv->dma_erx)
+                       goto err_dma;
+
                priv->dma_etx = dma_alloc_coherent(priv->device, txsize *
                                                   sizeof(struct
                                                          dma_extended_desc),
                                                   &priv->dma_tx_phy,
                                                   GFP_KERNEL);
-               if ((!priv->dma_erx) || (!priv->dma_etx))
-                       return;
+               if (!priv->dma_etx) {
+                       dma_free_coherent(priv->device, priv->dma_rx_size *
+                                       sizeof(struct dma_extended_desc),
+                                       priv->dma_erx, priv->dma_rx_phy);
+                       goto err_dma;
+               }
        } else {
                priv->dma_rx = dma_alloc_coherent(priv->device, rxsize *
                                                  sizeof(struct dma_desc),
                                                  &priv->dma_rx_phy,
                                                  GFP_KERNEL);
+               if (!priv->dma_rx)
+                       goto err_dma;
+
                priv->dma_tx = dma_alloc_coherent(priv->device, txsize *
                                                  sizeof(struct dma_desc),
                                                  &priv->dma_tx_phy,
                                                  GFP_KERNEL);
-               if ((!priv->dma_rx) || (!priv->dma_tx))
-                       return;
+               if (!priv->dma_tx) {
+                       dma_free_coherent(priv->device, priv->dma_rx_size *
+                                       sizeof(struct dma_desc),
+                                       priv->dma_rx, priv->dma_rx_phy);
+                       goto err_dma;
+               }
        }
 
        priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t),
                                            GFP_KERNEL);
+       if (!priv->rx_skbuff_dma)
+               goto err_rx_skbuff_dma;
+
        priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *),
                                        GFP_KERNEL);
+       if (!priv->rx_skbuff)
+               goto err_rx_skbuff;
+
        priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t),
                                            GFP_KERNEL);
+       if (!priv->tx_skbuff_dma)
+               goto err_tx_skbuff_dma;
+
        priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *),
                                        GFP_KERNEL);
+       if (!priv->tx_skbuff)
+               goto err_tx_skbuff;
+
        if (netif_msg_probe(priv)) {
                pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__,
                         (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy);
@@ -1034,8 +1076,9 @@ static void init_dma_desc_rings(struct net_device *dev)
                else
                        p = priv->dma_rx + i;
 
-               if (stmmac_init_rx_buffers(priv, p, i))
-                       break;
+               ret = stmmac_init_rx_buffers(priv, p, i);
+               if (ret)
+                       goto err_init_rx_buffers;
 
                if (netif_msg_probe(priv))
                        pr_debug("[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
@@ -1081,20 +1124,44 @@ static void init_dma_desc_rings(struct net_device *dev)
 
        if (netif_msg_hw(priv))
                stmmac_display_rings(priv);
+
+       return 0;
+err_init_rx_buffers:
+       while (--i >= 0)
+               stmmac_free_rx_buffers(priv, i);
+       kfree(priv->tx_skbuff);
+err_tx_skbuff:
+       kfree(priv->tx_skbuff_dma);
+err_tx_skbuff_dma:
+       kfree(priv->rx_skbuff);
+err_rx_skbuff:
+       kfree(priv->rx_skbuff_dma);
+err_rx_skbuff_dma:
+       if (priv->extend_desc) {
+               dma_free_coherent(priv->device, priv->dma_tx_size *
+                                 sizeof(struct dma_extended_desc),
+                                 priv->dma_etx, priv->dma_tx_phy);
+               dma_free_coherent(priv->device, priv->dma_rx_size *
+                                 sizeof(struct dma_extended_desc),
+                                 priv->dma_erx, priv->dma_rx_phy);
+       } else {
+               dma_free_coherent(priv->device,
+                               priv->dma_tx_size * sizeof(struct dma_desc),
+                               priv->dma_tx, priv->dma_tx_phy);
+               dma_free_coherent(priv->device,
+                               priv->dma_rx_size * sizeof(struct dma_desc),
+                               priv->dma_rx, priv->dma_rx_phy);
+       }
+err_dma:
+       return ret;
 }
 
 static void dma_free_rx_skbufs(struct stmmac_priv *priv)
 {
        int i;
 
-       for (i = 0; i < priv->dma_rx_size; i++) {
-               if (priv->rx_skbuff[i]) {
-                       dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
-                                        priv->dma_buf_sz, DMA_FROM_DEVICE);
-                       dev_kfree_skb_any(priv->rx_skbuff[i]);
-               }
-               priv->rx_skbuff[i] = NULL;
-       }
+       for (i = 0; i < priv->dma_rx_size; i++)
+               stmmac_free_rx_buffers(priv, i);
 }
 
 static void dma_free_tx_skbufs(struct stmmac_priv *priv)
@@ -1560,12 +1627,17 @@ static int stmmac_open(struct net_device *dev)
        priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
        priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
        priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
-       init_dma_desc_rings(dev);
+
+       ret = init_dma_desc_rings(dev);
+       if (ret < 0) {
+               pr_err("%s: DMA descriptors initialization failed\n", __func__);
+               goto dma_desc_error;
+       }
 
        /* DMA initialization and SW reset */
        ret = stmmac_init_dma_engine(priv);
        if (ret < 0) {
-               pr_err("%s: DMA initialization failed\n", __func__);
+               pr_err("%s: DMA engine initialization failed\n", __func__);
                goto init_error;
        }
 
@@ -1672,6 +1744,7 @@ wolirq_error:
 
 init_error:
        free_dma_desc_resources(priv);
+dma_desc_error:
        if (priv->phydev)
                phy_disconnect(priv->phydev);
 phy_error:
index 05a1674..22a7a43 100644 (file)
@@ -1867,7 +1867,7 @@ static int cpsw_probe(struct platform_device *pdev)
 
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
                for (i = res->start; i <= res->end; i++) {
-                       if (request_irq(i, cpsw_interrupt, IRQF_DISABLED,
+                       if (request_irq(i, cpsw_interrupt, 0,
                                        dev_name(&pdev->dev), priv)) {
                                dev_err(priv->dev, "error attaching irq\n");
                                goto clean_ale_ret;
index 07b176b..1a222bc 100644 (file)
@@ -1568,8 +1568,7 @@ static int emac_dev_open(struct net_device *ndev)
        while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
                for (i = res->start; i <= res->end; i++) {
                        if (devm_request_irq(&priv->pdev->dev, i, emac_irq,
-                                            IRQF_DISABLED,
-                                            ndev->name, ndev))
+                                            0, ndev->name, ndev))
                                goto rollback;
                }
                k++;
index 1d6dc41..d01cacf 100644 (file)
@@ -2100,7 +2100,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
 
                __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
        }
-       netif_rx(skb);
+       netif_receive_skb(skb);
 
        stats->rx_bytes += pkt_len;
        stats->rx_packets++;
@@ -2884,6 +2884,7 @@ out:
        return ret;
 
 err_iounmap:
+       netif_napi_del(&vptr->napi);
        iounmap(regs);
 err_free_dev:
        free_netdev(netdev);
@@ -2904,6 +2905,7 @@ static int velocity_remove(struct device *dev)
        struct velocity_info *vptr = netdev_priv(netdev);
 
        unregister_netdev(netdev);
+       netif_napi_del(&vptr->napi);
        iounmap(vptr->mac_regs);
        free_netdev(netdev);
        velocity_nics--;
index 18373b6..16b43bf 100644 (file)
@@ -337,8 +337,11 @@ static int macvlan_open(struct net_device *dev)
        int err;
 
        if (vlan->port->passthru) {
-               if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC))
-                       dev_set_promiscuity(lowerdev, 1);
+               if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) {
+                       err = dev_set_promiscuity(lowerdev, 1);
+                       if (err < 0)
+                               goto out;
+               }
                goto hash_add;
        }
 
@@ -736,6 +739,10 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
                        return -EADDRNOTAVAIL;
        }
 
+       if (data && data[IFLA_MACVLAN_FLAGS] &&
+           nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC)
+               return -EINVAL;
+
        if (data && data[IFLA_MACVLAN_MODE]) {
                switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) {
                case MACVLAN_MODE_PRIVATE:
@@ -863,6 +870,18 @@ static int macvlan_changelink(struct net_device *dev,
                struct nlattr *tb[], struct nlattr *data[])
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
+       enum macvlan_mode mode;
+       bool set_mode = false;
+
+       /* Validate mode, but don't set yet: setting flags may fail. */
+       if (data && data[IFLA_MACVLAN_MODE]) {
+               set_mode = true;
+               mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+               /* Passthrough mode can't be set or cleared dynamically */
+               if ((mode == MACVLAN_MODE_PASSTHRU) !=
+                   (vlan->mode == MACVLAN_MODE_PASSTHRU))
+                       return -EINVAL;
+       }
 
        if (data && data[IFLA_MACVLAN_FLAGS]) {
                __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]);
@@ -879,8 +898,8 @@ static int macvlan_changelink(struct net_device *dev,
                }
                vlan->flags = flags;
        }
-       if (data && data[IFLA_MACVLAN_MODE])
-               vlan->mode = nla_get_u32(data[IFLA_MACVLAN_MODE]);
+       if (set_mode)
+               vlan->mode = mode;
        return 0;
 }
 
index a98fb0e..b51db2a 100644 (file)
@@ -818,10 +818,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
                skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY;
                skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
        }
-       if (vlan)
+       if (vlan) {
+               local_bh_disable();
                macvlan_start_xmit(skb, vlan->dev);
-       else
+               local_bh_enable();
+       } else {
                kfree_skb(skb);
+       }
        rcu_read_unlock();
 
        return total_len;
@@ -912,8 +915,11 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
 done:
        rcu_read_lock();
        vlan = rcu_dereference(q->vlan);
-       if (vlan)
+       if (vlan) {
+               preempt_disable();
                macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0);
+               preempt_enable();
+       }
        rcu_read_unlock();
 
        return ret ? ret : copied;
index 61d3f4e..7f25e49 100644 (file)
@@ -40,7 +40,7 @@ struct sun4i_mdio_data {
 static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 {
        struct sun4i_mdio_data *data = bus->priv;
-       unsigned long start_jiffies;
+       unsigned long timeout_jiffies;
        int value;
 
        /* issue the phy address and reg */
@@ -49,10 +49,9 @@ static int sun4i_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
        writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
 
        /* Wait read complete */
-       start_jiffies = jiffies;
+       timeout_jiffies = jiffies + MDIO_TIMEOUT;
        while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
-               if (time_after(start_jiffies,
-                              start_jiffies + MDIO_TIMEOUT))
+               if (time_is_before_jiffies(timeout_jiffies))
                        return -ETIMEDOUT;
                msleep(1);
        }
@@ -69,7 +68,7 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
                            u16 value)
 {
        struct sun4i_mdio_data *data = bus->priv;
-       unsigned long start_jiffies;
+       unsigned long timeout_jiffies;
 
        /* issue the phy address and reg */
        writel((mii_id << 8) | regnum, data->membase + EMAC_MAC_MADR_REG);
@@ -77,10 +76,9 @@ static int sun4i_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        writel(0x1, data->membase + EMAC_MAC_MCMD_REG);
 
        /* Wait read complete */
-       start_jiffies = jiffies;
+       timeout_jiffies = jiffies + MDIO_TIMEOUT;
        while (readl(data->membase + EMAC_MAC_MIND_REG) & 0x1) {
-               if (time_after(start_jiffies,
-                              start_jiffies + MDIO_TIMEOUT))
+               if (time_is_before_jiffies(timeout_jiffies))
                        return -ETIMEDOUT;
                msleep(1);
        }
index db690a3..71af122 100644 (file)
@@ -1074,8 +1074,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        u32 rxhash;
 
        if (!(tun->flags & TUN_NO_PI)) {
-               if ((len -= sizeof(pi)) > total_len)
+               if (len < sizeof(pi))
                        return -EINVAL;
+               len -= sizeof(pi);
 
                if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi)))
                        return -EFAULT;
@@ -1083,8 +1084,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
        }
 
        if (tun->flags & TUN_VNET_HDR) {
-               if ((len -= tun->vnet_hdr_sz) > total_len)
+               if (len < tun->vnet_hdr_sz)
                        return -EINVAL;
+               len -= tun->vnet_hdr_sz;
 
                if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso)))
                        return -EFAULT;
index 1e3c302..2bc87e3 100644 (file)
@@ -1029,10 +1029,10 @@ static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.supports_gmii = 1;
 
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                             NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                             NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                                NETIF_F_RXCSUM;
 
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
@@ -1173,7 +1173,6 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
        if (((skb->len + 8) % frame_size) == 0)
                tx_hdr2 |= 0x80008000;  /* Enable padding */
 
-       skb_linearize(skb);
        headroom = skb_headroom(skb);
        tailroom = skb_tailroom(skb);
 
@@ -1317,10 +1316,10 @@ static int ax88179_reset(struct usbnet *dev)
                          1, 1, tmp);
 
        dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                             NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                             NETIF_F_RXCSUM;
 
        dev->net->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-                                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_TSO;
+                                NETIF_F_RXCSUM;
 
        /* Enable checksum offload */
        *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
index ee13f9e..11c51f2 100644 (file)
@@ -344,17 +344,41 @@ static const int multicast_filter_limit = 32;
 static
 int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
-       return usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
+       int ret;
+       void *tmp;
+
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       ret = usb_control_msg(tp->udev, usb_rcvctrlpipe(tp->udev, 0),
                               RTL8152_REQ_GET_REGS, RTL8152_REQT_READ,
-                              value, index, data, size, 500);
+                              value, index, tmp, size, 500);
+
+       memcpy(data, tmp, size);
+       kfree(tmp);
+
+       return ret;
 }
 
 static
 int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
 {
-       return usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
+       int ret;
+       void *tmp;
+
+       tmp = kmalloc(size, GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
+       memcpy(tmp, data, size);
+
+       ret = usb_control_msg(tp->udev, usb_sndctrlpipe(tp->udev, 0),
                               RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE,
-                              value, index, data, size, 500);
+                              value, index, tmp, size, 500);
+
+       kfree(tmp);
+       return ret;
 }
 
 static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size,
@@ -490,37 +514,31 @@ int usb_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data)
 
 static u32 ocp_read_dword(struct r8152 *tp, u16 type, u16 index)
 {
-       u32 data;
+       __le32 data;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(data), &data, type);
 
        return __le32_to_cpu(data);
 }
 
 static void ocp_write_dword(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
-       else
-               usb_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(data), &data);
+       __le32 tmp = __cpu_to_le32(data);
+
+       generic_ocp_write(tp, index, BYTE_EN_DWORD, sizeof(tmp), &tmp, type);
 }
 
 static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
 {
        u32 data;
+       __le32 tmp;
        u8 shift = index & 2;
 
        index &= ~3;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       data = __le32_to_cpu(data);
+       data = __le32_to_cpu(tmp);
        data >>= (shift * 8);
        data &= 0xffff;
 
@@ -529,7 +547,8 @@ static u16 ocp_read_word(struct r8152 *tp, u16 type, u16 index)
 
 static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       u32 tmp, mask = 0xffff;
+       u32 mask = 0xffff;
+       __le32 tmp;
        u16 byen = BYTE_EN_WORD;
        u8 shift = index & 2;
 
@@ -542,34 +561,25 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(tmp), &tmp);
-       else
-               usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       tmp = __le32_to_cpu(tmp) & ~mask;
-       tmp |= data;
-       tmp = __cpu_to_le32(tmp);
+       data |= __le32_to_cpu(tmp) & ~mask;
+       tmp = __cpu_to_le32(data);
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
-       else
-               usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+       generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
 }
 
 static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
 {
        u32 data;
+       __le32 tmp;
        u8 shift = index & 3;
 
        index &= ~3;
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(data), &data);
-       else
-               usb_ocp_read(tp, index, sizeof(data), &data);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       data = __le32_to_cpu(data);
+       data = __le32_to_cpu(tmp);
        data >>= (shift * 8);
        data &= 0xff;
 
@@ -578,7 +588,8 @@ static u8 ocp_read_byte(struct r8152 *tp, u16 type, u16 index)
 
 static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
 {
-       u32 tmp, mask = 0xff;
+       u32 mask = 0xff;
+       __le32 tmp;
        u16 byen = BYTE_EN_BYTE;
        u8 shift = index & 3;
 
@@ -591,19 +602,12 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_read(tp, index, sizeof(tmp), &tmp);
-       else
-               usb_ocp_read(tp, index, sizeof(tmp), &tmp);
+       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
 
-       tmp = __le32_to_cpu(tmp) & ~mask;
-       tmp |= data;
-       tmp = __cpu_to_le32(tmp);
+       data |= __le32_to_cpu(tmp) & ~mask;
+       tmp = __cpu_to_le32(data);
 
-       if (type == MCU_TYPE_PLA)
-               pla_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
-       else
-               usb_ocp_write(tp, index, byen, sizeof(tmp), &tmp);
+       generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
 }
 
 static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value)
@@ -685,21 +689,14 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
 static inline void set_ethernet_addr(struct r8152 *tp)
 {
        struct net_device *dev = tp->netdev;
-       u8 *node_id;
-
-       node_id = kmalloc(sizeof(u8) * 8, GFP_KERNEL);
-       if (!node_id) {
-               netif_err(tp, probe, dev, "out of memory");
-               return;
-       }
+       u8 node_id[8] = {0};
 
-       if (pla_ocp_read(tp, PLA_IDR, sizeof(u8) * 8, node_id) < 0)
+       if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0)
                netif_notice(tp, probe, dev, "inet addr fail\n");
        else {
                memcpy(dev->dev_addr, node_id, dev->addr_len);
                memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
        }
-       kfree(node_id);
 }
 
 static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
@@ -882,15 +879,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
 static void _rtl8152_set_rx_mode(struct net_device *netdev)
 {
        struct r8152 *tp = netdev_priv(netdev);
-       u32 tmp, *mc_filter;    /* Multicast hash filter */
+       u32 mc_filter[2];       /* Multicast hash filter */
+       __le32 tmp[2];
        u32 ocp_data;
 
-       mc_filter = kmalloc(sizeof(u32) * 2, GFP_KERNEL);
-       if (!mc_filter) {
-               netif_err(tp, link, netdev, "out of memory");
-               return;
-       }
-
        clear_bit(RTL8152_SET_RX_MODE, &tp->flags);
        netif_stop_queue(netdev);
        ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
@@ -918,14 +910,12 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
                }
        }
 
-       tmp = mc_filter[0];
-       mc_filter[0] = __cpu_to_le32(swab32(mc_filter[1]));
-       mc_filter[1] = __cpu_to_le32(swab32(tmp));
+       tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
+       tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
 
-       pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(u32) * 2, mc_filter);
+       pla_ocp_write(tp, PLA_MAR, BYTE_EN_DWORD, sizeof(tmp), tmp);
        ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
        netif_wake_queue(netdev);
-       kfree(mc_filter);
 }
 
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
index 8523922..2df2f4f 100644 (file)
 
 static int pla_read_word(struct usb_device *udev, u16 index)
 {
-       int data, ret;
+       int ret;
        u8 shift = index & 2;
-       __le32 ocp_data;
+       __le32 *tmp;
+
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
 
        index &= ~3;
 
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-                             500);
+                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
        if (ret < 0)
-               return ret;
+               goto out2;
 
-       data = __le32_to_cpu(ocp_data);
-       data >>= (shift * 8);
-       data &= 0xffff;
+       ret = __le32_to_cpu(*tmp);
+       ret >>= (shift * 8);
+       ret &= 0xffff;
 
-       return data;
+out2:
+       kfree(tmp);
+       return ret;
 }
 
 static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 {
-       __le32 ocp_data;
+       __le32 *tmp;
        u32 mask = 0xffff;
        u16 byen = BYTE_EN_WORD;
        u8 shift = index & 2;
        int ret;
 
+       tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               return -ENOMEM;
+
        data &= mask;
 
        if (shift) {
@@ -63,19 +72,20 @@ static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
 
        ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
                              RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
-                             index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
-                             500);
+                             index, MCU_TYPE_PLA, tmp, sizeof(*tmp), 500);
        if (ret < 0)
-               return ret;
+               goto out3;
 
-       data |= __le32_to_cpu(ocp_data) & ~mask;
-       ocp_data = __cpu_to_le32(data);
+       data |= __le32_to_cpu(*tmp) & ~mask;
+       *tmp = __cpu_to_le32(data);
 
        ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                              RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
-                             index, MCU_TYPE_PLA | byen, &ocp_data,
-                             sizeof(ocp_data), 500);
+                             index, MCU_TYPE_PLA | byen, tmp, sizeof(*tmp),
+                             500);
 
+out3:
+       kfree(tmp);
        return ret;
 }
 
@@ -116,11 +126,18 @@ out1:
 static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
 {
        struct usbnet *dev = netdev_priv(netdev);
+       int ret;
 
        if (phy_id != R815x_PHY_ID)
                return -EINVAL;
 
-       return ocp_reg_read(dev, BASE_MII + reg * 2);
+       if (usb_autopm_get_interface(dev->intf) < 0)
+               return -ENODEV;
+
+       ret = ocp_reg_read(dev, BASE_MII + reg * 2);
+
+       usb_autopm_put_interface(dev->intf);
+       return ret;
 }
 
 static
@@ -131,7 +148,12 @@ void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
        if (phy_id != R815x_PHY_ID)
                return;
 
+       if (usb_autopm_get_interface(dev->intf) < 0)
+               return;
+
        ocp_reg_write(dev, BASE_MII + reg * 2, val);
+
+       usb_autopm_put_interface(dev->intf);
 }
 
 static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -150,7 +172,7 @@ static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = R815x_PHY_ID;
        dev->mii.supports_gmii = 1;
 
-       return 0;
+       return status;
 }
 
 static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -169,7 +191,7 @@ static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id = R815x_PHY_ID;
        dev->mii.supports_gmii = 0;
 
-       return 0;
+       return status;
 }
 
 static const struct driver_info r8152_info = {
index 7540974..66ebbac 100644 (file)
@@ -45,7 +45,6 @@
 #define EEPROM_MAC_OFFSET              (0x01)
 #define DEFAULT_TX_CSUM_ENABLE         (true)
 #define DEFAULT_RX_CSUM_ENABLE         (true)
-#define DEFAULT_TSO_ENABLE             (true)
 #define SMSC75XX_INTERNAL_PHY_ID       (1)
 #define SMSC75XX_TX_OVERHEAD           (8)
 #define MAX_RX_FIFO_SIZE               (20 * 1024)
@@ -1410,17 +1409,14 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
 
        INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
 
-       if (DEFAULT_TX_CSUM_ENABLE) {
+       if (DEFAULT_TX_CSUM_ENABLE)
                dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
-               if (DEFAULT_TSO_ENABLE)
-                       dev->net->features |= NETIF_F_SG |
-                               NETIF_F_TSO | NETIF_F_TSO6;
-       }
+
        if (DEFAULT_RX_CSUM_ENABLE)
                dev->net->features |= NETIF_F_RXCSUM;
 
        dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
-               NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;
+                               NETIF_F_RXCSUM;
 
        ret = smsc75xx_wait_ready(dev, 0);
        if (ret < 0) {
@@ -2200,8 +2196,6 @@ static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev,
 {
        u32 tx_cmd_a, tx_cmd_b;
 
-       skb_linearize(skb);
-
        if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) {
                struct sk_buff *skb2 =
                        skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags);
index da86652..eee1f19 100644 (file)
@@ -269,6 +269,7 @@ static void veth_setup(struct net_device *dev)
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->features |= VETH_FEATURES;
+       dev->vlan_features = dev->features;
        dev->destructor = veth_dev_free;
 
        dev->hw_features = VETH_FEATURES;
index a5ba8dd..767f7af 100644 (file)
@@ -136,7 +136,8 @@ struct vxlan_dev {
        u32               flags;        /* VXLAN_F_* below */
 
        struct work_struct sock_work;
-       struct work_struct igmp_work;
+       struct work_struct igmp_join;
+       struct work_struct igmp_leave;
 
        unsigned long     age_interval;
        struct timer_list age_timer;
@@ -736,7 +737,6 @@ static bool vxlan_snoop(struct net_device *dev,
        return false;
 }
 
-
 /* See if multicast group is already in use by other ID */
 static bool vxlan_group_used(struct vxlan_net *vn, __be32 remote_ip)
 {
@@ -770,12 +770,13 @@ static void vxlan_sock_release(struct vxlan_net *vn, struct vxlan_sock *vs)
        queue_work(vxlan_wq, &vs->del_work);
 }
 
-/* Callback to update multicast group membership.
- * Scheduled when vxlan goes up/down.
+/* Callback to update multicast group membership when first VNI on
+ * multicast asddress is brought up
+ * Done as workqueue because ip_mc_join_group acquires RTNL.
  */
-static void vxlan_igmp_work(struct work_struct *work)
+static void vxlan_igmp_join(struct work_struct *work)
 {
-       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_work);
+       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
        struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
        struct vxlan_sock *vs = vxlan->vn_sock;
        struct sock *sk = vs->sock->sk;
@@ -785,10 +786,27 @@ static void vxlan_igmp_work(struct work_struct *work)
        };
 
        lock_sock(sk);
-       if (vxlan_group_used(vn, vxlan->default_dst.remote_ip))
-               ip_mc_join_group(sk, &mreq);
-       else
-               ip_mc_leave_group(sk, &mreq);
+       ip_mc_join_group(sk, &mreq);
+       release_sock(sk);
+
+       vxlan_sock_release(vn, vs);
+       dev_put(vxlan->dev);
+}
+
+/* Inverse of vxlan_igmp_join when last VNI is brought down */
+static void vxlan_igmp_leave(struct work_struct *work)
+{
+       struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
+       struct vxlan_net *vn = net_generic(dev_net(vxlan->dev), vxlan_net_id);
+       struct vxlan_sock *vs = vxlan->vn_sock;
+       struct sock *sk = vs->sock->sk;
+       struct ip_mreqn mreq = {
+               .imr_multiaddr.s_addr   = vxlan->default_dst.remote_ip,
+               .imr_ifindex            = vxlan->default_dst.remote_ifindex,
+       };
+
+       lock_sock(sk);
+       ip_mc_leave_group(sk, &mreq);
        release_sock(sk);
 
        vxlan_sock_release(vn, vs);
@@ -1359,6 +1377,7 @@ static void vxlan_uninit(struct net_device *dev)
 /* Start ageing timer and join group when device is brought up */
 static int vxlan_open(struct net_device *dev)
 {
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
@@ -1366,10 +1385,11 @@ static int vxlan_open(struct net_device *dev)
        if (!vs)
                return -ENOTCONN;
 
-       if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+       if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+           vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
                vxlan_sock_hold(vs);
                dev_hold(dev);
-               queue_work(vxlan_wq, &vxlan->igmp_work);
+               queue_work(vxlan_wq, &vxlan->igmp_join);
        }
 
        if (vxlan->age_interval)
@@ -1400,13 +1420,15 @@ static void vxlan_flush(struct vxlan_dev *vxlan)
 /* Cleanup timer and forwarding table on shutdown */
 static int vxlan_stop(struct net_device *dev)
 {
+       struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
        struct vxlan_sock *vs = vxlan->vn_sock;
 
-       if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip))) {
+       if (vs && IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) &&
+           ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) {
                vxlan_sock_hold(vs);
                dev_hold(dev);
-               queue_work(vxlan_wq, &vxlan->igmp_work);
+               queue_work(vxlan_wq, &vxlan->igmp_leave);
        }
 
        del_timer_sync(&vxlan->age_timer);
@@ -1471,7 +1493,8 @@ static void vxlan_setup(struct net_device *dev)
 
        INIT_LIST_HEAD(&vxlan->next);
        spin_lock_init(&vxlan->hash_lock);
-       INIT_WORK(&vxlan->igmp_work, vxlan_igmp_work);
+       INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join);
+       INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave);
        INIT_WORK(&vxlan->sock_work, vxlan_sock_work);
 
        init_timer_deferrable(&vxlan->age_timer);
@@ -1770,8 +1793,6 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head)
        struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id);
        struct vxlan_dev *vxlan = netdev_priv(dev);
 
-       flush_workqueue(vxlan_wq);
-
        spin_lock(&vn->sock_lock);
        hlist_del_rcu(&vxlan->hlist);
        spin_unlock(&vn->sock_lock);
@@ -1878,10 +1899,12 @@ static __net_exit void vxlan_exit_net(struct net *net)
 {
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        struct vxlan_dev *vxlan;
+       LIST_HEAD(list);
 
        rtnl_lock();
        list_for_each_entry(vxlan, &vn->vxlan_list, next)
-               dev_close(vxlan->dev);
+               unregister_netdevice_queue(vxlan->dev, &list);
+       unregister_netdevice_many(&list);
        rtnl_unlock();
 }
 
index cde58fe..82e8088 100644 (file)
@@ -1,6 +1,6 @@
 config ATH10K
         tristate "Atheros 802.11ac wireless cards support"
-        depends on MAC80211
+        depends on MAC80211 && HAS_DMA
        select ATH_COMMON
         ---help---
           This module adds support for wireless adapters based on
index 81b686c..40825d4 100644 (file)
@@ -325,7 +325,7 @@ ath5k_prepare_multicast(struct ieee80211_hw *hw,
        struct netdev_hw_addr *ha;
 
        mfilt[0] = 0;
-       mfilt[1] = 1;
+       mfilt[1] = 0;
 
        netdev_hw_addr_list_for_each(ha, mc_list) {
                /* calculate XOR of eight 6-bit values */
index d1acfe9..1576d58 100644 (file)
@@ -610,7 +610,15 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
        REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
        if (AR_SREV_9280_20_OR_LATER(ah)) {
-               val = REG_READ(ah, AR_PCU_MISC_MODE2);
+               /*
+                * For AR9280 and above, there is a new feature that allows
+                * Multicast search based on both MAC Address and Key ID.
+                * By default, this feature is enabled. But since the driver
+                * is not using this feature, we switch it off; otherwise
+                * multicast search based on MAC addr only will fail.
+                */
+               val = REG_READ(ah, AR_PCU_MISC_MODE2) &
+                       (~AR_ADHOC_MCAST_KEYID_ENABLE);
 
                if (!AR_SREV_9271(ah))
                        val &= ~AR_PCU_MISC_MODE2_HWWAR1;
index 9e582e1..5205a36 100644 (file)
@@ -1082,7 +1082,7 @@ static void ath9k_hif_usb_firmware_fail(struct hif_device_usb *hif_dev)
        struct device *dev = &hif_dev->udev->dev;
        struct device *parent = dev->parent;
 
-       complete(&hif_dev->fw_done);
+       complete_all(&hif_dev->fw_done);
 
        if (parent)
                device_lock(parent);
@@ -1131,7 +1131,7 @@ static void ath9k_hif_usb_firmware_cb(const struct firmware *fw, void *context)
 
        release_firmware(fw);
        hif_dev->flags |= HIF_USB_READY;
-       complete(&hif_dev->fw_done);
+       complete_all(&hif_dev->fw_done);
 
        return;
 
@@ -1295,7 +1295,9 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 
        usb_set_intfdata(interface, NULL);
 
-       if (!unplugged && (hif_dev->flags & HIF_USB_START))
+       /* If firmware was loaded we should drop it
+        * go back to first stage bootloader. */
+       if (!unplugged && (hif_dev->flags & HIF_USB_READY))
                ath9k_hif_usb_reboot(udev);
 
        kfree(hif_dev);
@@ -1316,7 +1318,10 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
        if (!(hif_dev->flags & HIF_USB_START))
                ath9k_htc_suspend(hif_dev->htc_handle);
 
-       ath9k_hif_usb_dealloc_urbs(hif_dev);
+       wait_for_completion(&hif_dev->fw_done);
+
+       if (hif_dev->flags & HIF_USB_READY)
+               ath9k_hif_usb_dealloc_urbs(hif_dev);
 
        return 0;
 }
index 71a183f..c3676bf 100644 (file)
@@ -861,6 +861,7 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
        if (error != 0)
                goto err_rx;
 
+       ath9k_hw_disable(priv->ah);
 #ifdef CONFIG_MAC80211_LEDS
        /* must be initialized before ieee80211_register_hw */
        priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
index c59ae43..9279927 100644 (file)
@@ -146,6 +146,28 @@ static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
                               ARRAY_SIZE(bf->rates));
 }
 
+static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+                            struct sk_buff *skb)
+{
+       int q;
+
+       q = skb_get_queue_mapping(skb);
+       if (txq == sc->tx.uapsdq)
+               txq = sc->tx.txq_map[q];
+
+       if (txq != sc->tx.txq_map[q])
+               return;
+
+       if (WARN_ON(--txq->pending_frames < 0))
+               txq->pending_frames = 0;
+
+       if (txq->stopped &&
+           txq->pending_frames < sc->tx.txq_max_pending[q]) {
+               ieee80211_wake_queue(sc->hw, q);
+               txq->stopped = false;
+       }
+}
+
 static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
 {
        struct ath_txq *txq = tid->ac->txq;
@@ -167,6 +189,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
                if (!bf) {
                        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
                        if (!bf) {
+                               ath_txq_skb_done(sc, txq, skb);
                                ieee80211_free_txskb(sc->hw, skb);
                                continue;
                        }
@@ -811,6 +834,7 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
 
                if (!bf) {
                        __skb_unlink(skb, &tid->buf_q);
+                       ath_txq_skb_done(sc, txq, skb);
                        ieee80211_free_txskb(sc->hw, skb);
                        continue;
                }
@@ -1824,6 +1848,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_txq *txq,
 
        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
+               ath_txq_skb_done(sc, txq, skb);
                ieee80211_free_txskb(sc->hw, skb);
                return;
        }
@@ -2090,6 +2115,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        bf = ath_tx_setup_buffer(sc, txq, tid, skb);
        if (!bf) {
+               ath_txq_skb_done(sc, txq, skb);
                if (txctl->paprd)
                        dev_kfree_skb_any(skb);
                else
@@ -2189,7 +2215,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
-       int q, padpos, padsize;
+       int padpos, padsize;
        unsigned long flags;
 
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
@@ -2225,21 +2251,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        __skb_queue_tail(&txq->complete_q, skb);
-
-       q = skb_get_queue_mapping(skb);
-       if (txq == sc->tx.uapsdq)
-               txq = sc->tx.txq_map[q];
-
-       if (txq == sc->tx.txq_map[q]) {
-               if (WARN_ON(--txq->pending_frames < 0))
-                       txq->pending_frames = 0;
-
-               if (txq->stopped &&
-                   txq->pending_frames < sc->tx.txq_max_pending[q]) {
-                       ieee80211_wake_queue(sc->hw, q);
-                       txq->stopped = false;
-               }
-       }
+       ath_txq_skb_done(sc, txq, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
index e8308ec..ab63676 100644 (file)
@@ -145,7 +145,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
                                   le16_to_cpu(hdr.type), hdr.flags);
                        if (len <= MAX_MBOXITEM_SIZE) {
                                int n = 0;
-                               unsigned char printbuf[16 * 3 + 2];
+                               char printbuf[16 * 3 + 2];
                                unsigned char databuf[MAX_MBOXITEM_SIZE];
                                void __iomem *src = wmi_buffer(wil, d.addr) +
                                        sizeof(struct wil6210_mbox_hdr);
@@ -416,7 +416,7 @@ static int wil_txdesc_debugfs_show(struct seq_file *s, void *data)
                seq_printf(s, "  SKB = %p\n", skb);
 
                if (skb) {
-                       unsigned char printbuf[16 * 3 + 2];
+                       char printbuf[16 * 3 + 2];
                        int i = 0;
                        int len = le16_to_cpu(d->dma.length);
                        void *p = skb->data;
index 8e89755..8009901 100644 (file)
@@ -242,7 +242,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
 {
        unsigned long flags;
 
-       if (!ifp)
+       if (!ifp || !ifp->ndev)
                return;
 
        brcmf_dbg(TRACE, "enter: idx=%d stop=0x%X reason=%d state=%d\n",
index f0d9f7f..29b1f24 100644 (file)
@@ -1744,13 +1744,14 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        ulong flags;
        int fifo = BRCMF_FWS_FIFO_BCMC;
        bool multicast = is_multicast_ether_addr(eh->h_dest);
+       bool pae = eh->h_proto == htons(ETH_P_PAE);
 
        /* determine the priority */
        if (!skb->priority)
                skb->priority = cfg80211_classify8021d(skb);
 
        drvr->tx_multicast += !!multicast;
-       if (ntohs(eh->h_proto) == ETH_P_PAE)
+       if (pae)
                atomic_inc(&ifp->pend_8021x_cnt);
 
        if (!brcmf_fws_fc_active(fws)) {
@@ -1781,6 +1782,11 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
                brcmf_fws_schedule_deq(fws);
        } else {
                brcmf_err("drop skb: no hanger slot\n");
+               if (pae) {
+                       atomic_dec(&ifp->pend_8021x_cnt);
+                       if (waitqueue_active(&ifp->pend_8021x_wait))
+                               wake_up(&ifp->pend_8021x_wait);
+               }
                brcmu_pkt_buf_free_skb(skb);
        }
        brcmf_fws_unlock(drvr, flags);
index 277b37a..7fa71f7 100644 (file)
@@ -1093,8 +1093,11 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
                brcmf_dbg(INFO, "Call WLC_DISASSOC to stop excess roaming\n ");
                err = brcmf_fil_cmd_data_set(vif->ifp,
                                             BRCMF_C_DISASSOC, NULL, 0);
-               if (err)
+               if (err) {
                        brcmf_err("WLC_DISASSOC failed (%d)\n", err);
+                       cfg80211_disconnected(vif->wdev.netdev, 0,
+                                             NULL, 0, GFP_KERNEL);
+               }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
index 7365674..010b252 100644 (file)
@@ -1406,11 +1406,8 @@ static void cw1200_do_unjoin(struct cw1200_common *priv)
        if (!priv->join_status)
                goto done;
 
-       if (priv->join_status > CW1200_JOIN_STATUS_IBSS) {
-               wiphy_err(priv->hw->wiphy, "Unexpected: join status: %d\n",
-                         priv->join_status);
-               BUG_ON(1);
-       }
+       if (priv->join_status == CW1200_JOIN_STATUS_AP)
+               goto done;
 
        cancel_work_sync(&priv->update_filtering_work);
        cancel_work_sync(&priv->set_beacon_wakeup_period_work);
index 5862c37..e824d4d 100644 (file)
@@ -1165,7 +1165,7 @@ void cw1200_rx_cb(struct cw1200_common *priv,
                if (cw1200_handle_action_rx(priv, skb))
                        return;
        } else if (ieee80211_is_beacon(frame->frame_control) &&
-                  !arg->status &&
+                  !arg->status && priv->vif &&
                   !memcmp(ieee80211_get_SA(frame), priv->vif->bss_conf.bssid,
                           ETH_ALEN)) {
                const u8 *tim_ie;
index b9b2bb5..f2ed62e 100644 (file)
@@ -4460,12 +4460,12 @@ il4965_irq_tasklet(struct il_priv *il)
                 * is killed. Hence update the killswitch state here. The
                 * rfkill handler will care about restarting if needed.
                 */
-               if (!test_bit(S_ALIVE, &il->status)) {
-                       if (hw_rf_kill)
-                               set_bit(S_RFKILL, &il->status);
-                       else
-                               clear_bit(S_RFKILL, &il->status);
+               if (hw_rf_kill) {
+                       set_bit(S_RFKILL, &il->status);
+               } else {
+                       clear_bit(S_RFKILL, &il->status);
                        wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill);
+                       il_force_reset(il, true);
                }
 
                handled |= CSR_INT_BIT_RF_KILL;
@@ -5334,6 +5334,9 @@ il4965_alive_start(struct il_priv *il)
 
        il->active_rate = RATES_MASK;
 
+       il_power_update_mode(il, true);
+       D_INFO("Updated power mode\n");
+
        if (il_is_associated(il)) {
                struct il_rxon_cmd *active_rxon =
                    (struct il_rxon_cmd *)&il->active;
@@ -5364,9 +5367,6 @@ il4965_alive_start(struct il_priv *il)
        D_INFO("ALIVE processing complete.\n");
        wake_up(&il->wait_command_queue);
 
-       il_power_update_mode(il, true);
-       D_INFO("Updated power mode\n");
-
        return;
 
 restart:
index 3195aad..b03e22e 100644 (file)
@@ -4660,6 +4660,7 @@ il_force_reset(struct il_priv *il, bool external)
 
        return 0;
 }
+EXPORT_SYMBOL(il_force_reset);
 
 int
 il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
index 3952ddf..1531a4f 100644 (file)
@@ -758,7 +758,7 @@ int iwl_alive_start(struct iwl_priv *priv)
                                         BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
                if (ret)
                        return ret;
-       } else {
+       } else if (priv->lib->bt_params) {
                /*
                 * default is 2-wire BT coexexistence support
                 */
index ff8cc75..a70c7b9 100644 (file)
@@ -97,6 +97,8 @@
 
 #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS         (0x00000800)
 
+#define APMG_RTC_INT_STT_RFKILL                (0x10000000)
+
 /* Device system time */
 #define DEVICE_SYSTEM_TIME_REG 0xA0206C
 
index 7e5e5c2..83da884 100644 (file)
@@ -134,7 +134,7 @@ struct wowlan_key_data {
        struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc;
        struct iwl_wowlan_tkip_params_cmd *tkip;
        bool error, use_rsc_tsc, use_tkip;
-       int gtk_key_idx;
+       int wep_key_idx;
 };
 
 static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
@@ -188,8 +188,8 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                        wkc.wep_key.key_offset = 0;
                } else {
                        /* others start at 1 */
-                       data->gtk_key_idx++;
-                       wkc.wep_key.key_offset = data->gtk_key_idx;
+                       data->wep_key_idx++;
+                       wkc.wep_key.key_offset = data->wep_key_idx;
                }
 
                ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, CMD_SYNC,
@@ -316,8 +316,13 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
                mvm->ptk_ivlen = key->iv_len;
                mvm->ptk_icvlen = key->icv_len;
        } else {
-               data->gtk_key_idx++;
-               key->hw_key_idx = data->gtk_key_idx;
+               /*
+                * firmware only supports TSC/RSC for a single key,
+                * so if there are multiple keep overwriting them
+                * with new ones -- this relies on mac80211 doing
+                * list_add_tail().
+                */
+               key->hw_key_idx = 1;
                mvm->gtk_ivlen = key->iv_len;
                mvm->gtk_icvlen = key->icv_len;
        }
index e56ed2a..c24a744 100644 (file)
@@ -988,7 +988,11 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        char buf[100];
 
-       if (!dbgfs_dir)
+       /*
+        * Check if debugfs directory already exist before creating it.
+        * This may happen when, for example, resetting hw or suspend-resume
+        */
+       if (!dbgfs_dir || mvmvif->dbgfs_dir)
                return;
 
        mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir);
index b60d141..365095a 100644 (file)
@@ -69,7 +69,6 @@
 /* Scan Commands, Responses, Notifications */
 
 /* Masks for iwl_scan_channel.type flags */
-#define SCAN_CHANNEL_TYPE_PASSIVE      0
 #define SCAN_CHANNEL_TYPE_ACTIVE       BIT(0)
 #define SCAN_CHANNEL_NARROW_BAND       BIT(22)
 
index e08683b..f19baf0 100644 (file)
@@ -257,7 +257,11 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       return ieee80211_register_hw(mvm->hw);
+       ret = ieee80211_register_hw(mvm->hw);
+       if (ret)
+               iwl_mvm_leds_exit(mvm);
+
+       return ret;
 }
 
 static void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
@@ -385,6 +389,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
        ieee80211_wake_queues(mvm->hw);
 
        mvm->vif_count = 0;
+       mvm->rx_ba_sessions = 0;
 }
 
 static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
@@ -507,6 +512,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                goto out_unlock;
 
        /*
+        * TODO: remove this temporary code.
+        * Currently MVM FW supports power management only on single MAC.
+        * If new interface added, disable PM on existing interface.
+        * P2P device is a special case, since it is handled by FW similary to
+        * scan. If P2P deviced is added, PM remains enabled on existing
+        * interface.
+        * Note: the method below does not count the new interface being added
+        * at this moment.
+        */
+       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
+               mvm->vif_count++;
+       if (mvm->vif_count > 1) {
+               IWL_DEBUG_MAC80211(mvm,
+                                  "Disable power on existing interfaces\n");
+               ieee80211_iterate_active_interfaces_atomic(
+                                           mvm->hw,
+                                           IEEE80211_IFACE_ITER_NORMAL,
+                                           iwl_mvm_pm_disable_iterator, mvm);
+       }
+
+       /*
         * The AP binding flow can be done only after the beacon
         * template is configured (which happens only in the mac80211
         * start_ap() flow), and adding the broadcast station can happen
@@ -529,27 +555,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
                goto out_unlock;
        }
 
-       /*
-        * TODO: remove this temporary code.
-        * Currently MVM FW supports power management only on single MAC.
-        * If new interface added, disable PM on existing interface.
-        * P2P device is a special case, since it is handled by FW similary to
-        * scan. If P2P deviced is added, PM remains enabled on existing
-        * interface.
-        * Note: the method below does not count the new interface being added
-        * at this moment.
-        */
-       if (vif->type != NL80211_IFTYPE_P2P_DEVICE)
-               mvm->vif_count++;
-       if (mvm->vif_count > 1) {
-               IWL_DEBUG_MAC80211(mvm,
-                                  "Disable power on existing interfaces\n");
-               ieee80211_iterate_active_interfaces_atomic(
-                                           mvm->hw,
-                                           IEEE80211_IFACE_ITER_NORMAL,
-                                           iwl_mvm_pm_disable_iterator, mvm);
-       }
-
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
                goto out_release;
@@ -1006,6 +1011,21 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        mutex_lock(&mvm->mutex);
        if (old_state == IEEE80211_STA_NOTEXIST &&
            new_state == IEEE80211_STA_NONE) {
+               /*
+                * Firmware bug - it'll crash if the beacon interval is less
+                * than 16. We can't avoid connecting at all, so refuse the
+                * station state change, this will cause mac80211 to abandon
+                * attempts to connect to this AP, and eventually wpa_s will
+                * blacklist the AP...
+                */
+               if (vif->type == NL80211_IFTYPE_STATION &&
+                   vif->bss_conf.beacon_int < 16) {
+                       IWL_ERR(mvm,
+                               "AP %pM beacon interval is %d, refusing due to firmware bug!\n",
+                               sta->addr, vif->bss_conf.beacon_int);
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
                ret = iwl_mvm_add_sta(mvm, vif, sta);
        } else if (old_state == IEEE80211_STA_NONE &&
                   new_state == IEEE80211_STA_AUTH) {
@@ -1038,6 +1058,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
        } else {
                ret = -EIO;
        }
+ out_unlock:
        mutex_unlock(&mvm->mutex);
 
        return ret;
index d40d7db..420e82d 100644 (file)
@@ -419,6 +419,7 @@ struct iwl_mvm {
        struct work_struct sta_drained_wk;
        unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
        atomic_t pending_frames[IWL_MVM_STATION_COUNT];
+       u8 rx_ba_sessions;
 
        /* configured by mac80211 */
        u32 rts_threshold;
index 2157b0f..acdff6b 100644 (file)
@@ -137,8 +137,8 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
 {
        int fw_idx, req_idx;
 
-       fw_idx = 0;
-       for (req_idx = req->n_ssids - 1; req_idx > 0; req_idx--) {
+       for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx > 0;
+            req_idx--, fw_idx++) {
                cmd->direct_scan[fw_idx].id = WLAN_EID_SSID;
                cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len;
                memcpy(cmd->direct_scan[fw_idx].ssid,
@@ -153,7 +153,9 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd,
  * just to notify that this scan is active and not passive.
  * In order to notify the FW of the number of SSIDs we wish to scan (including
  * the zero-length one), we need to set the corresponding bits in chan->type,
- * one for each SSID, and set the active bit (first).
+ * one for each SSID, and set the active bit (first). The first SSID is already
+ * included in the probe template, so we need to set only req->n_ssids - 1 bits
+ * in addition to the first bit.
  */
 static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
 {
@@ -176,19 +178,12 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
        struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
                (cmd->data + le16_to_cpu(cmd->tx_cmd.len));
        int i;
-       __le32 chan_type_value;
-
-       if (req->n_ssids > 0)
-               chan_type_value = cpu_to_le32(BIT(req->n_ssids + 1) - 1);
-       else
-               chan_type_value = SCAN_CHANNEL_TYPE_PASSIVE;
 
        for (i = 0; i < cmd->channel_count; i++) {
                chan->channel = cpu_to_le16(req->channels[i]->hw_value);
+               chan->type = cpu_to_le32(BIT(req->n_ssids) - 1);
                if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)
-                       chan->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       chan->type = chan_type_value;
+                       chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
                chan->active_dwell = cpu_to_le16(active_dwell);
                chan->passive_dwell = cpu_to_le16(passive_dwell);
                chan->iteration_count = cpu_to_le16(1);
index 62fe520..563f559 100644 (file)
@@ -608,6 +608,8 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct iwl_mvm_int_sta *bsta)
        return ret;
 }
 
+#define IWL_MAX_RX_BA_SESSIONS 16
+
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                       int tid, u16 ssn, bool start)
 {
@@ -618,11 +620,20 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
 
        lockdep_assert_held(&mvm->mutex);
 
+       if (start && mvm->rx_ba_sessions >= IWL_MAX_RX_BA_SESSIONS) {
+               IWL_WARN(mvm, "Not enough RX BA SESSIONS\n");
+               return -ENOSPC;
+       }
+
        cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
        cmd.sta_id = mvm_sta->sta_id;
        cmd.add_modify = STA_MODE_MODIFY;
-       cmd.add_immediate_ba_tid = (u8) tid;
-       cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       if (start) {
+               cmd.add_immediate_ba_tid = (u8) tid;
+               cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+       } else {
+               cmd.remove_immediate_ba_tid = (u8) tid;
+       }
        cmd.modify_mask = start ? STA_MODIFY_ADD_BA_TID :
                                  STA_MODIFY_REMOVE_BA_TID;
 
@@ -648,6 +659,14 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                break;
        }
 
+       if (!ret) {
+               if (start)
+                       mvm->rx_ba_sessions++;
+               else if (mvm->rx_ba_sessions > 0)
+                       /* check that restart flow didn't zero the counter */
+                       mvm->rx_ba_sessions--;
+       }
+
        return ret;
 }
 
@@ -896,6 +915,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        struct iwl_mvm_sta *mvmsta = (void *)sta->drv_priv;
        struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
        u16 txq_id;
+       enum iwl_mvm_agg_state old_state;
 
        /*
         * First set the agg state to OFF to avoid calling
@@ -905,13 +925,17 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        txq_id = tid_data->txq_id;
        IWL_DEBUG_TX_QUEUES(mvm, "Flush AGG: sta %d tid %d q %d state %d\n",
                            mvmsta->sta_id, tid, txq_id, tid_data->state);
+       old_state = tid_data->state;
        tid_data->state = IWL_AGG_OFF;
        spin_unlock_bh(&mvmsta->lock);
 
-       if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
-               IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+       if (old_state >= IWL_AGG_ON) {
+               if (iwl_mvm_flush_tx_path(mvm, BIT(txq_id), true))
+                       IWL_ERR(mvm, "Couldn't flush the AGG queue\n");
+
+               iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
+       }
 
-       iwl_trans_txq_disable(mvm->trans, tid_data->txq_id);
        mvm->queue_to_mac80211[tid_data->txq_id] =
                                IWL_INVALID_MAC80211_QUEUE;
 
index 81f3ea5..ff13458 100644 (file)
@@ -130,6 +130,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x423C, 0x1306, iwl5150_abg_cfg)}, /* Half Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1221, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423C, 0x1321, iwl5150_agn_cfg)}, /* Half Mini Card */
+       {IWL_PCI_DEVICE(0x423C, 0x1326, iwl5150_abg_cfg)}, /* Half Mini Card */
 
        {IWL_PCI_DEVICE(0x423D, 0x1211, iwl5150_agn_cfg)}, /* Mini Card */
        {IWL_PCI_DEVICE(0x423D, 0x1311, iwl5150_agn_cfg)}, /* Half Mini Card */
index fd848cd..f600e68 100644 (file)
@@ -888,6 +888,14 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
                if (hw_rfkill) {
+                       /*
+                        * Clear the interrupt in APMG if the NIC is going down.
+                        * Note that when the NIC exits RFkill (else branch), we
+                        * can't access prph and the NIC will be reset in
+                        * start_hw anyway.
+                        */
+                       iwl_write_prph(trans, APMG_RTC_INT_STT_REG,
+                                      APMG_RTC_INT_STT_RFKILL);
                        set_bit(STATUS_RFKILL, &trans_pcie->status);
                        if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
                                               &trans_pcie->status))
index 826c156..96cfcdd 100644 (file)
@@ -670,6 +670,11 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
                return err;
        }
 
+       /* Reset the entire device */
+       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+       usleep_range(10, 15);
+
        iwl_pcie_apm_init(trans);
 
        /* From now on, the op_mode will be kept updated about RF kill state */
index ef5fa89..89459db 100644 (file)
@@ -1716,9 +1716,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        int ret;
 
-       if (priv->bss_mode != NL80211_IFTYPE_STATION) {
+       if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
                wiphy_err(wiphy,
-                         "%s: reject infra assoc request in non-STA mode\n",
+                         "%s: reject infra assoc request in non-STA role\n",
                          dev->name);
                return -EINVAL;
        }
index 988552d..5178c46 100644 (file)
@@ -415,7 +415,8 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
        u32 k = 0;
        struct mwifiex_adapter *adapter = priv->adapter;
 
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                switch (adapter->config_bands) {
                case BAND_B:
                        dev_dbg(adapter->dev, "info: infra band=%d "
index caaf4bd..2cf8b96 100644 (file)
@@ -693,7 +693,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
                if (!ret) {
                        dev_notice(adapter->dev,
                                   "WLAN FW already running! Skip FW dnld\n");
-                       goto done;
+                       return 0;
                }
 
                poll_num = MAX_FIRMWARE_POLL_TRIES;
@@ -719,14 +719,8 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
 poll_fw:
        /* Check if the firmware is downloaded successfully or not */
        ret = adapter->if_ops.check_fw_status(adapter, poll_num);
-       if (ret) {
+       if (ret)
                dev_err(adapter->dev, "FW failed to be active in time\n");
-               return -1;
-       }
-done:
-       /* re-enable host interrupt for mwifiex after fw dnld is successful */
-       if (adapter->if_ops.enable_int)
-               adapter->if_ops.enable_int(adapter);
 
        return ret;
 }
index 1c8a771..12e7781 100644 (file)
@@ -1291,8 +1291,10 @@ int mwifiex_associate(struct mwifiex_private *priv,
 {
        u8 current_bssid[ETH_ALEN];
 
-       /* Return error if the adapter or table entry is not marked as infra */
-       if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
+       /* Return error if the adapter is not STA role or table entry
+        * is not marked as infra.
+        */
+       if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) ||
            (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
                return -1;
 
index e15ab72..1753431 100644 (file)
@@ -427,6 +427,10 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
                                "Cal data request_firmware() failed\n");
        }
 
+       /* enable host interrupt after fw dnld is successful */
+       if (adapter->if_ops.enable_int)
+               adapter->if_ops.enable_int(adapter);
+
        adapter->init_wait_q_woken = false;
        ret = mwifiex_init_fw(adapter);
        if (ret == -1) {
@@ -478,6 +482,8 @@ err_add_intf:
        mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
        rtnl_unlock();
 err_init_fw:
+       if (adapter->if_ops.disable_int)
+               adapter->if_ops.disable_int(adapter);
        pr_debug("info: %s: unregister device\n", __func__);
        adapter->if_ops.unregister_dev(adapter);
 done:
@@ -855,7 +861,7 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
 
        /* Register the device. Fill up the private data structure with relevant
-          information from the card and request for the required IRQ. */
+          information from the card. */
        if (adapter->if_ops.register_dev(adapter)) {
                pr_err("%s: failed to register mwifiex device\n", __func__);
                goto err_registerdev;
@@ -919,6 +925,11 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
        if (!adapter)
                goto exit_remove;
 
+       /* We can no longer handle interrupts once we start doing the teardown
+        * below. */
+       if (adapter->if_ops.disable_int)
+               adapter->if_ops.disable_int(adapter);
+
        adapter->surprise_removed = true;
 
        /* Stop data */
index 3da73d3..253e0bd 100644 (file)
@@ -601,6 +601,7 @@ struct mwifiex_if_ops {
        int (*register_dev) (struct mwifiex_adapter *);
        void (*unregister_dev) (struct mwifiex_adapter *);
        int (*enable_int) (struct mwifiex_adapter *);
+       void (*disable_int) (struct mwifiex_adapter *);
        int (*process_int_status) (struct mwifiex_adapter *);
        int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *,
                             struct mwifiex_tx_param *);
index 5ee5ed0..09185c9 100644 (file)
@@ -51,6 +51,7 @@ static struct mwifiex_if_ops sdio_ops;
 static struct semaphore add_remove_card_sem;
 
 static int mwifiex_sdio_resume(struct device *dev);
+static void mwifiex_sdio_interrupt(struct sdio_func *func);
 
 /*
  * SDIO probe.
@@ -296,6 +297,15 @@ static struct sdio_driver mwifiex_sdio = {
        }
 };
 
+/* Write data into SDIO card register. Caller claims SDIO device. */
+static int
+mwifiex_write_reg_locked(struct sdio_func *func, u32 reg, u8 data)
+{
+       int ret = -1;
+       sdio_writeb(func, data, reg, &ret);
+       return ret;
+}
+
 /*
  * This function writes data into SDIO card register.
  */
@@ -303,10 +313,10 @@ static int
 mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u8 data)
 {
        struct sdio_mmc_card *card = adapter->card;
-       int ret = -1;
+       int ret;
 
        sdio_claim_host(card->func);
-       sdio_writeb(card->func, data, reg, &ret);
+       ret = mwifiex_write_reg_locked(card->func, reg, data);
        sdio_release_host(card->func);
 
        return ret;
@@ -685,23 +695,15 @@ mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
  * The host interrupt mask is read, the disable bit is reset and
  * written back to the card host interrupt mask register.
  */
-static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
+static void mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
 {
-       u8 host_int_mask, host_int_disable = HOST_INT_DISABLE;
-
-       /* Read back the host_int_mask register */
-       if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
-               return -1;
-
-       /* Update with the mask and write back to the register */
-       host_int_mask &= ~host_int_disable;
-
-       if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
-               dev_err(adapter->dev, "disable host interrupt failed\n");
-               return -1;
-       }
+       struct sdio_mmc_card *card = adapter->card;
+       struct sdio_func *func = card->func;
 
-       return 0;
+       sdio_claim_host(func);
+       mwifiex_write_reg_locked(func, HOST_INT_MASK_REG, 0);
+       sdio_release_irq(func);
+       sdio_release_host(func);
 }
 
 /*
@@ -713,14 +715,29 @@ static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
 static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
 {
        struct sdio_mmc_card *card = adapter->card;
+       struct sdio_func *func = card->func;
+       int ret;
+
+       sdio_claim_host(func);
+
+       /* Request the SDIO IRQ */
+       ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
+       if (ret) {
+               dev_err(adapter->dev, "claim irq failed: ret=%d\n", ret);
+               goto out;
+       }
 
        /* Simply write the mask to the register */
-       if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG,
-                             card->reg->host_int_enable)) {
+       ret = mwifiex_write_reg_locked(func, HOST_INT_MASK_REG,
+                                      card->reg->host_int_enable);
+       if (ret) {
                dev_err(adapter->dev, "enable host interrupt failed\n");
-               return -1;
+               sdio_release_irq(func);
        }
-       return 0;
+
+out:
+       sdio_release_host(func);
+       return ret;
 }
 
 /*
@@ -997,9 +1014,6 @@ mwifiex_sdio_interrupt(struct sdio_func *func)
        }
        adapter = card->adapter;
 
-       if (adapter->surprise_removed)
-               return;
-
        if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
                adapter->ps_state = PS_STATE_AWAKE;
 
@@ -1625,8 +1639,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
        /* Allocate buffer and copy payload */
        blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
        buf_block_len = (pkt_len + blk_size - 1) / blk_size;
-       *(u16 *) &payload[0] = (u16) pkt_len;
-       *(u16 *) &payload[2] = type;
+       *(__le16 *)&payload[0] = cpu_to_le16((u16)pkt_len);
+       *(__le16 *)&payload[2] = cpu_to_le16(type);
 
        /*
         * This is SDIO specific header
@@ -1728,9 +1742,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
        struct sdio_mmc_card *card = adapter->card;
 
        if (adapter->card) {
-               /* Release the SDIO IRQ */
                sdio_claim_host(card->func);
-               sdio_release_irq(card->func);
                sdio_disable_func(card->func);
                sdio_release_host(card->func);
                sdio_set_drvdata(card->func, NULL);
@@ -1744,7 +1756,7 @@ mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
  */
 static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 {
-       int ret = 0;
+       int ret;
        struct sdio_mmc_card *card = adapter->card;
        struct sdio_func *func = card->func;
 
@@ -1753,22 +1765,14 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
 
        sdio_claim_host(func);
 
-       /* Request the SDIO IRQ */
-       ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
-       if (ret) {
-               pr_err("claim irq failed: ret=%d\n", ret);
-               goto disable_func;
-       }
-
        /* Set block size */
        ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
+       sdio_release_host(func);
        if (ret) {
                pr_err("cannot set SDIO block size\n");
-               ret = -1;
-               goto release_irq;
+               return ret;
        }
 
-       sdio_release_host(func);
        sdio_set_drvdata(func, card);
 
        adapter->dev = &func->dev;
@@ -1776,15 +1780,6 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        strcpy(adapter->fw_name, card->firmware);
 
        return 0;
-
-release_irq:
-       sdio_release_irq(func);
-disable_func:
-       sdio_disable_func(func);
-       sdio_release_host(func);
-       adapter->card = NULL;
-
-       return -1;
 }
 
 /*
@@ -1813,9 +1808,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
         */
        mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
 
-       /* Disable host interrupt mask register for SDIO */
-       mwifiex_sdio_disable_host_int(adapter);
-
        /* Get SDIO ioport */
        mwifiex_init_sdio_ioport(adapter);
 
@@ -1957,6 +1949,7 @@ static struct mwifiex_if_ops sdio_ops = {
        .register_dev = mwifiex_register_dev,
        .unregister_dev = mwifiex_unregister_dev,
        .enable_int = mwifiex_sdio_enable_host_int,
+       .disable_int = mwifiex_sdio_disable_host_int,
        .process_int_status = mwifiex_process_int_status,
        .host_to_card = mwifiex_sdio_host_to_card,
        .wakeup = mwifiex_pm_wakeup_card,
index 6d51dfd..532ae0a 100644 (file)
@@ -92,9 +92,6 @@
 /* Host Control Registers : Download host interrupt mask */
 #define DN_LD_HOST_INT_MASK            (0x2U)
 
-/* Disable Host interrupt mask */
-#define        HOST_INT_DISABLE                0xff
-
 /* Host Control Registers : Host interrupt status */
 #define HOST_INTSTATUS_REG             0x03
 /* Host Control Registers : Upload host interrupt status */
index 206c3e0..8af97ab 100644 (file)
@@ -257,10 +257,10 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                        goto done;
        }
 
-       if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+       if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+           priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {
                u8 config_bands;
 
-               /* Infra mode */
                ret = mwifiex_deauthenticate(priv, NULL);
                if (ret)
                        goto done;
index 9b915d3..3e60a31 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig RT2X00
        tristate "Ralink driver support"
-       depends on MAC80211
+       depends on MAC80211 && HAS_DMA
        ---help---
          This will enable the support for the Ralink drivers,
          developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
index 6c0a91f..aa95c6c 100644 (file)
@@ -936,13 +936,8 @@ void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
        spin_unlock_irqrestore(&queue->index_lock, irqflags);
 }
 
-void rt2x00queue_pause_queue(struct data_queue *queue)
+void rt2x00queue_pause_queue_nocheck(struct data_queue *queue)
 {
-       if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
-           !test_bit(QUEUE_STARTED, &queue->flags) ||
-           test_and_set_bit(QUEUE_PAUSED, &queue->flags))
-               return;
-
        switch (queue->qid) {
        case QID_AC_VO:
        case QID_AC_VI:
@@ -958,6 +953,15 @@ void rt2x00queue_pause_queue(struct data_queue *queue)
                break;
        }
 }
+void rt2x00queue_pause_queue(struct data_queue *queue)
+{
+       if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
+           !test_bit(QUEUE_STARTED, &queue->flags) ||
+           test_and_set_bit(QUEUE_PAUSED, &queue->flags))
+               return;
+
+       rt2x00queue_pause_queue_nocheck(queue);
+}
 EXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
 
 void rt2x00queue_unpause_queue(struct data_queue *queue)
@@ -1019,7 +1023,7 @@ void rt2x00queue_stop_queue(struct data_queue *queue)
                return;
        }
 
-       rt2x00queue_pause_queue(queue);
+       rt2x00queue_pause_queue_nocheck(queue);
 
        queue->rt2x00dev->ops->lib->stop_queue(queue);
 
index 7253de3..c2ffce7 100644 (file)
@@ -1,27 +1,20 @@
-config RTLWIFI
-       tristate "Realtek wireless card support"
-       depends on MAC80211
-       select FW_LOADER
-       ---help---
-         This is common code for RTL8192CE/RTL8192CU/RTL8192SE/RTL8723AE
-         drivers.  This module does nothing by itself - the various front-end
-         drivers need to be enabled to support any desired devices.
-
-         If you choose to build as a module, it'll be called rtlwifi.
-
-config RTLWIFI_DEBUG
-       bool "Debugging output for rtlwifi driver family"
-       depends on RTLWIFI
+menuconfig RTL_CARDS
+       tristate "Realtek rtlwifi family of devices"
+       depends on MAC80211 && (PCI || USB)
        default y
        ---help---
-       To use the module option that sets the dynamic-debugging level for,
-       the front-end driver, this parameter must be "Y". For memory-limited
-       systems, choose "N". If in doubt, choose "Y".
+         This option will enable support for the Realtek mac80211-based
+         wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de,
+         rtl8723eu, and rtl8188eu share some common code.
+
+if RTL_CARDS
 
 config RTL8192CE
        tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
        select RTL8192C_COMMON
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe
        wireless network adapters.
@@ -30,7 +23,9 @@ config RTL8192CE
 
 config RTL8192SE
        tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
        wireless network adapters.
@@ -39,7 +34,9 @@ config RTL8192SE
 
 config RTL8192DE
        tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe
        wireless network adapters.
@@ -48,7 +45,9 @@ config RTL8192DE
 
 config RTL8723AE
        tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8723AE 802.11n PCIe
        wireless network adapters.
@@ -57,7 +56,9 @@ config RTL8723AE
 
 config RTL8188EE
        tristate "Realtek RTL8188EE Wireless Network Adapter"
-       depends on RTLWIFI && PCI
+       depends on PCI
+       select RTLWIFI
+       select RTLWIFI_PCI
        ---help---
        This is the driver for Realtek RTL8188EE 802.11n PCIe
        wireless network adapters.
@@ -66,7 +67,9 @@ config RTL8188EE
 
 config RTL8192CU
        tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
-       depends on RTLWIFI && USB
+       depends on USB
+       select RTLWIFI
+       select RTLWIFI_USB
        select RTL8192C_COMMON
        ---help---
        This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB
@@ -74,7 +77,28 @@ config RTL8192CU
 
        If you choose to build it as a module, it will be called rtl8192cu
 
+config RTLWIFI
+       tristate
+       select FW_LOADER
+
+config RTLWIFI_PCI
+       tristate
+
+config RTLWIFI_USB
+       tristate
+
+config RTLWIFI_DEBUG
+       bool "Debugging output for rtlwifi driver family"
+       depends on RTLWIFI
+       default y
+       ---help---
+       To use the module option that sets the dynamic-debugging level for,
+       the front-end driver, this parameter must be "Y". For memory-limited
+       systems, choose "N". If in doubt, choose "Y".
+
 config RTL8192C_COMMON
        tristate
        depends on RTL8192CE || RTL8192CU
-       default m
+       default y
+
+endif
index ff02b87..d56f023 100644 (file)
@@ -12,13 +12,11 @@ rtlwifi-objs        :=              \
 
 rtl8192c_common-objs +=                \
 
-ifneq ($(CONFIG_PCI),)
-rtlwifi-objs   += pci.o
-endif
+obj-$(CONFIG_RTLWIFI_PCI)      += rtl_pci.o
+rtl_pci-objs   :=              pci.o
 
-ifneq ($(CONFIG_USB),)
-rtlwifi-objs   += usb.o
-endif
+obj-$(CONFIG_RTLWIFI_USB)      += rtl_usb.o
+rtl_usb-objs   :=              usb.o
 
 obj-$(CONFIG_RTL8192C_COMMON)  += rtl8192c/
 obj-$(CONFIG_RTL8192CE)                += rtl8192ce/
index 9d558ac..7651f5a 100644 (file)
@@ -172,6 +172,7 @@ u8 rtl_tid_to_ac(u8 tid)
 {
        return tid_to_ac[tid];
 }
+EXPORT_SYMBOL_GPL(rtl_tid_to_ac);
 
 static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
                                  struct ieee80211_sta_ht_cap *ht_cap)
@@ -406,6 +407,7 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
        cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
        cancel_delayed_work(&rtlpriv->works.fwevt_wq);
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_deferred_work);
 
 void rtl_init_rfkill(struct ieee80211_hw *hw)
 {
@@ -439,6 +441,7 @@ void rtl_deinit_rfkill(struct ieee80211_hw *hw)
 {
        wiphy_rfkill_stop_polling(hw->wiphy);
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_rfkill);
 
 int rtl_init_core(struct ieee80211_hw *hw)
 {
@@ -489,10 +492,12 @@ int rtl_init_core(struct ieee80211_hw *hw)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(rtl_init_core);
 
 void rtl_deinit_core(struct ieee80211_hw *hw)
 {
 }
+EXPORT_SYMBOL_GPL(rtl_deinit_core);
 
 void rtl_init_rx_config(struct ieee80211_hw *hw)
 {
@@ -501,6 +506,7 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
 
        rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
 }
+EXPORT_SYMBOL_GPL(rtl_init_rx_config);
 
 /*********************************************************
  *
@@ -879,6 +885,7 @@ bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(rtl_tx_mgmt_proc);
 
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
                      struct ieee80211_tx_info *info,
@@ -1052,6 +1059,7 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 
        return true;
 }
+EXPORT_SYMBOL_GPL(rtl_action_proc);
 
 /*should call before software enc*/
 u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
@@ -1125,6 +1133,7 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
 
        return false;
 }
+EXPORT_SYMBOL_GPL(rtl_is_special_data);
 
 /*********************************************************
  *
@@ -1300,6 +1309,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        rtlpriv->link_info.bcn_rx_inperiod++;
 }
+EXPORT_SYMBOL_GPL(rtl_beacon_statistic);
 
 void rtl_watchdog_wq_callback(void *data)
 {
@@ -1793,6 +1803,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
 
        mac->vendor = vendor;
 }
+EXPORT_SYMBOL_GPL(rtl_recognize_peer);
 
 /*********************************************************
  *
@@ -1849,6 +1860,7 @@ struct attribute_group rtl_attribute_group = {
        .name = "rtlsysfs",
        .attrs = rtl_sysfs_entries,
 };
+EXPORT_SYMBOL_GPL(rtl_attribute_group);
 
 MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
 MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
@@ -1856,7 +1868,8 @@ MODULE_AUTHOR("Larry Finger       <Larry.FInger@lwfinger.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek 802.11n PCI wireless core");
 
-struct rtl_global_var global_var = {};
+struct rtl_global_var rtl_global_var = {};
+EXPORT_SYMBOL_GPL(rtl_global_var);
 
 static int __init rtl_core_module_init(void)
 {
@@ -1864,8 +1877,8 @@ static int __init rtl_core_module_init(void)
                pr_err("Unable to register rtl_rc, use default RC !!\n");
 
        /* init some global vars */
-       INIT_LIST_HEAD(&global_var.glb_priv_list);
-       spin_lock_init(&global_var.glb_list_lock);
+       INIT_LIST_HEAD(&rtl_global_var.glb_priv_list);
+       spin_lock_init(&rtl_global_var.glb_list_lock);
 
        return 0;
 }
index 8576bc3..0e5fe09 100644 (file)
@@ -147,7 +147,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
 u8 rtl_tid_to_ac(u8 tid);
 extern struct attribute_group rtl_attribute_group;
 void rtl_easy_concurrent_retrytimer_callback(unsigned long data);
-extern struct rtl_global_var global_var;
+extern struct rtl_global_var rtl_global_var;
 int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
                         bool isht, u8 desc_rate, bool first_ampdu);
 bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
index ee84844..733b7ce 100644 (file)
@@ -1330,3 +1330,4 @@ const struct ieee80211_ops rtl_ops = {
        .rfkill_poll = rtl_op_rfkill_poll,
        .flush = rtl_op_flush,
 };
+EXPORT_SYMBOL_GPL(rtl_ops);
index 7d52d3d..76e2086 100644 (file)
@@ -51,3 +51,4 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw)
 
        /*Init Debug flag enable condition */
 }
+EXPORT_SYMBOL_GPL(rtl_dbgp_flag_init);
index 9e38941..838a1ed 100644 (file)
@@ -229,6 +229,7 @@ void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
 
        *pbuf = (u8) (value32 & 0xff);
 }
+EXPORT_SYMBOL_GPL(read_efuse_byte);
 
 void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
 {
index c97e9d3..703f839 100644 (file)
 #include "efuse.h"
 #include <linux/export.h>
 #include <linux/kmemleak.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCI basic driver for rtlwifi");
 
 static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
        PCI_VENDOR_ID_INTEL,
@@ -1008,19 +1015,6 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        return;
 }
 
-static void rtl_lps_change_work_callback(struct work_struct *work)
-{
-       struct rtl_works *rtlworks =
-           container_of(work, struct rtl_works, lps_change_work);
-       struct ieee80211_hw *hw = rtlworks->hw;
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-
-       if (rtlpriv->enter_ps)
-               rtl_lps_enter(hw);
-       else
-               rtl_lps_leave(hw);
-}
-
 static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1899,7 +1893,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
        rtlpriv->rtlhal.interface = INTF_PCI;
        rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
        rtlpriv->intf_ops = &rtl_pci_ops;
-       rtlpriv->glb_var = &global_var;
+       rtlpriv->glb_var = &rtl_global_var;
 
        /*
         *init dbgp flags before all
index 884bcea..298b615 100644 (file)
@@ -269,6 +269,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
 
        spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
 }
+EXPORT_SYMBOL_GPL(rtl_ips_nic_on);
 
 /*for FW LPS*/
 
@@ -518,6 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
                         "u_bufferd: %x, m_buffered: %x\n", u_buffed, m_buffed);
        }
 }
+EXPORT_SYMBOL_GPL(rtl_swlps_beacon);
 
 void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
 {
@@ -611,6 +613,19 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
                        MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
 }
 
+void rtl_lps_change_work_callback(struct work_struct *work)
+{
+       struct rtl_works *rtlworks =
+           container_of(work, struct rtl_works, lps_change_work);
+       struct ieee80211_hw *hw = rtlworks->hw;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->enter_ps)
+               rtl_lps_enter(hw);
+       else
+               rtl_lps_leave(hw);
+}
+EXPORT_SYMBOL_GPL(rtl_lps_change_work_callback);
 
 void rtl_swlps_wq_callback(void *data)
 {
@@ -922,3 +937,4 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
        else
                rtl_p2p_noa_ie(hw, data, len - FCS_LEN);
 }
+EXPORT_SYMBOL_GPL(rtl_p2p_info);
index 4d682b7..88bd76e 100644 (file)
@@ -49,5 +49,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
 void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
 void rtl_p2p_ps_cmd(struct ieee80211_hw *hw, u8 p2p_ps_state);
 void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl_lps_change_work_callback(struct work_struct *work);
 
 #endif
index a3532e0..e56778c 100644 (file)
 #include "ps.h"
 #include "rtl8192c/fw_common.h"
 #include <linux/export.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB basic driver for rtlwifi");
 
 #define        REALTEK_USB_VENQT_READ                  0xC0
 #define        REALTEK_USB_VENQT_WRITE                 0x40
@@ -1070,6 +1077,8 @@ int rtl_usb_probe(struct usb_interface *intf,
        spin_lock_init(&rtlpriv->locks.usb_lock);
        INIT_WORK(&rtlpriv->works.fill_h2c_cmd,
                  rtl_fill_h2c_cmd_work_callback);
+       INIT_WORK(&rtlpriv->works.lps_change_work,
+                 rtl_lps_change_work_callback);
 
        rtlpriv->usb_data_index = 0;
        init_completion(&rtlpriv->firmware_loading_complete);
index e79e006..9ee04b4 100644 (file)
@@ -811,18 +811,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
        return pcidev->irq;
 }
 
-static struct iosapic_info *first_isi = NULL;
+static struct iosapic_info *iosapic_list;
 
 #ifdef CONFIG_64BIT
-int iosapic_serial_irq(int num)
+int iosapic_serial_irq(struct parisc_device *dev)
 {
-       struct iosapic_info *isi = first_isi;
-       struct irt_entry *irte = NULL;  /* only used if PAT PDC */
+       struct iosapic_info *isi;
+       struct irt_entry *irte;
        struct vector_info *vi;
-       int isi_line;   /* line used by device */
+       int cnt;
+       int intin;
+
+       intin = (dev->mod_info >> 24) & 15;
 
        /* lookup IRT entry for isi/slot/pin set */
-       irte = &irt_cell[num];
+       for (cnt = 0; cnt < irt_num_entry; cnt++) {
+               irte = &irt_cell[cnt];
+               if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
+                   irte->dest_iosapic_intin == intin)
+                       break;
+       }
+       if (cnt >= irt_num_entry)
+               return 0; /* no irq found, force polling */
 
        DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
                irte,
@@ -834,11 +844,17 @@ int iosapic_serial_irq(int num)
                irte->src_seg_id,
                irte->dest_iosapic_intin,
                (u32) irte->dest_iosapic_addr);
-       isi_line = irte->dest_iosapic_intin;
+
+       /* search for iosapic */
+       for (isi = iosapic_list; isi; isi = isi->isi_next)
+               if (isi->isi_hpa == dev->mod0)
+                       break;
+       if (!isi)
+               return 0; /* no iosapic found, force polling */
 
        /* get vector info for this input line */
-       vi = isi->isi_vector + isi_line;
-       DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", isi_line, vi);
+       vi = isi->isi_vector + intin;
+       DBG_IRT("iosapic_serial_irq:  line %d vi 0x%p\n", iosapic_intin, vi);
 
        /* If this IRQ line has already been setup, skip it */
        if (vi->irte)
@@ -941,8 +957,8 @@ void *iosapic_register(unsigned long hpa)
                vip->irqline = (unsigned char) cnt;
                vip->iosapic = isi;
        }
-       if (!first_isi)
-               first_isi = isi;
+       isi->isi_next = iosapic_list;
+       iosapic_list = isi;
        return isi;
 }
 
index 13a633b..7bf3926 100644 (file)
@@ -86,10 +86,6 @@ struct mvebu_sw_pci_bridge {
        u16 secondary_status;
        u16 membase;
        u16 memlimit;
-       u16 prefmembase;
-       u16 prefmemlimit;
-       u32 prefbaseupper;
-       u32 preflimitupper;
        u16 iobaseupper;
        u16 iolimitupper;
        u8 cappointer;
@@ -419,15 +415,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
                break;
 
        case PCI_PREF_MEMORY_BASE:
-               *value = (bridge->prefmemlimit << 16 | bridge->prefmembase);
-               break;
-
-       case PCI_PREF_BASE_UPPER32:
-               *value = bridge->prefbaseupper;
-               break;
-
-       case PCI_PREF_LIMIT_UPPER32:
-               *value = bridge->preflimitupper;
+               *value = 0;
                break;
 
        case PCI_IO_BASE_UPPER16:
@@ -501,19 +489,6 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
                mvebu_pcie_handle_membase_change(port);
                break;
 
-       case PCI_PREF_MEMORY_BASE:
-               bridge->prefmembase = value & 0xffff;
-               bridge->prefmemlimit = value >> 16;
-               break;
-
-       case PCI_PREF_BASE_UPPER32:
-               bridge->prefbaseupper = value;
-               break;
-
-       case PCI_PREF_LIMIT_UPPER32:
-               bridge->preflimitupper = value;
-               break;
-
        case PCI_IO_BASE_UPPER16:
                bridge->iobaseupper = value & 0xffff;
                bridge->iolimitupper = value >> 16;
index bb7ebb2..d85009d 100644 (file)
@@ -3,16 +3,13 @@
 #
 
 menuconfig HOTPLUG_PCI
-       tristate "Support for PCI Hotplug"
+       bool "Support for PCI Hotplug"
        depends on PCI && SYSFS
        ---help---
          Say Y here if you have a motherboard with a PCI Hotplug controller.
          This allows you to add and remove PCI cards while the machine is
          powered up and running.
 
-         To compile this driver as a module, choose M here: the
-         module will be called pci_hotplug.
-
          When in doubt, say N.
 
 if HOTPLUG_PCI
index aac7a40..0e0d0f7 100644 (file)
@@ -92,7 +92,14 @@ int pciehp_unconfigure_device(struct slot *p_slot)
        if (ret)
                presence = 0;
 
-       list_for_each_entry_safe(dev, temp, &parent->devices, bus_list) {
+       /*
+        * Stopping an SR-IOV PF device removes all the associated VFs,
+        * which will update the bus->devices list and confuse the
+        * iterator.  Therefore, iterate in reverse so we remove the VFs
+        * first, then the PF.  We do the same in pci_stop_bus_device().
+        */
+       list_for_each_entry_safe_reverse(dev, temp, &parent->devices,
+                                        bus_list) {
                pci_dev_get(dev);
                if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && presence) {
                        pci_read_config_byte(dev, PCI_BRIDGE_CONTROL, &bctl);
index dbdc5f7..01e264f 100644 (file)
@@ -317,13 +317,20 @@ void acpi_pci_remove_bus(struct pci_bus *bus)
 /* ACPI bus type */
 static int acpi_pci_find_device(struct device *dev, acpi_handle *handle)
 {
-       struct pci_dev * pci_dev;
-       u64     addr;
+       struct pci_dev *pci_dev = to_pci_dev(dev);
+       bool is_bridge;
+       u64 addr;
 
-       pci_dev = to_pci_dev(dev);
+       /*
+        * pci_is_bridge() is not suitable here, because pci_dev->subordinate
+        * is set only after acpi_pci_find_device() has been called for the
+        * given device.
+        */
+       is_bridge = pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE
+                       || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS;
        /* Please ref to ACPI spec for the syntax of _ADR */
        addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
-       *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+       *handle = acpi_find_child(ACPI_HANDLE(dev->parent), addr, is_bridge);
        if (!*handle)
                return -ENODEV;
        return 0;
index 569f82f..3b94cfc 100644 (file)
@@ -14,15 +14,12 @@ config PCIEPORTBUS
 # Include service Kconfig here
 #
 config HOTPLUG_PCI_PCIE
-       tristate "PCI Express Hotplug driver"
+       bool "PCI Express Hotplug driver"
        depends on HOTPLUG_PCI && PCIEPORTBUS
        help
          Say Y here if you have a motherboard that supports PCI Express Native
          Hotplug
 
-         To compile this driver as a module, choose M here: the
-         module will be called pciehp.
-
          When in doubt, say N.
 
 source "drivers/pci/pcie/aer/Kconfig"
index d254e23..64a7de2 100644 (file)
@@ -300,6 +300,47 @@ static void assign_requested_resources_sorted(struct list_head *head,
        }
 }
 
+static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
+{
+       struct pci_dev_resource *fail_res;
+       unsigned long mask = 0;
+
+       /* check failed type */
+       list_for_each_entry(fail_res, fail_head, list)
+               mask |= fail_res->flags;
+
+       /*
+        * one pref failed resource will set IORESOURCE_MEM,
+        * as we can allocate pref in non-pref range.
+        * Will release all assigned non-pref sibling resources
+        * according to that bit.
+        */
+       return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
+}
+
+static bool pci_need_to_release(unsigned long mask, struct resource *res)
+{
+       if (res->flags & IORESOURCE_IO)
+               return !!(mask & IORESOURCE_IO);
+
+       /* check pref at first */
+       if (res->flags & IORESOURCE_PREFETCH) {
+               if (mask & IORESOURCE_PREFETCH)
+                       return true;
+               /* count pref if its parent is non-pref */
+               else if ((mask & IORESOURCE_MEM) &&
+                        !(res->parent->flags & IORESOURCE_PREFETCH))
+                       return true;
+               else
+                       return false;
+       }
+
+       if (res->flags & IORESOURCE_MEM)
+               return !!(mask & IORESOURCE_MEM);
+
+       return false;   /* should not get here */
+}
+
 static void __assign_resources_sorted(struct list_head *head,
                                 struct list_head *realloc_head,
                                 struct list_head *fail_head)
@@ -312,11 +353,24 @@ static void __assign_resources_sorted(struct list_head *head,
         *  if could do that, could get out early.
         *  if could not do that, we still try to assign requested at first,
         *    then try to reassign add_size for some resources.
+        *
+        * Separate three resource type checking if we need to release
+        * assigned resource after requested + add_size try.
+        *      1. if there is io port assign fail, will release assigned
+        *         io port.
+        *      2. if there is pref mmio assign fail, release assigned
+        *         pref mmio.
+        *         if assigned pref mmio's parent is non-pref mmio and there
+        *         is non-pref mmio assign fail, will release that assigned
+        *         pref mmio.
+        *      3. if there is non-pref mmio assign fail or pref mmio
+        *         assigned fail, will release assigned non-pref mmio.
         */
        LIST_HEAD(save_head);
        LIST_HEAD(local_fail_head);
        struct pci_dev_resource *save_res;
-       struct pci_dev_resource *dev_res;
+       struct pci_dev_resource *dev_res, *tmp_res;
+       unsigned long fail_type;
 
        /* Check if optional add_size is there */
        if (!realloc_head || list_empty(realloc_head))
@@ -348,6 +402,19 @@ static void __assign_resources_sorted(struct list_head *head,
                return;
        }
 
+       /* check failed type */
+       fail_type = pci_fail_res_type_mask(&local_fail_head);
+       /* remove not need to be released assigned res from head list etc */
+       list_for_each_entry_safe(dev_res, tmp_res, head, list)
+               if (dev_res->res->parent &&
+                   !pci_need_to_release(fail_type, dev_res->res)) {
+                       /* remove it from realloc_head list */
+                       remove_from_list(realloc_head, dev_res->res);
+                       remove_from_list(&save_head, dev_res->res);
+                       list_del(&dev_res->list);
+                       kfree(dev_res);
+               }
+
        free_list(&local_fail_head);
        /* Release assigned resource */
        list_for_each_entry(dev_res, head, list)
index f4f30af..2e8a20c 100644 (file)
@@ -1715,11 +1715,13 @@ int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
                    (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
                        port->nscan = NULL;
 
-       list_for_each_entry(scan, &rio_scans, node)
+       list_for_each_entry(scan, &rio_scans, node) {
                if (scan->mport_id == mport_id) {
                        list_del(&scan->node);
                        kfree(scan);
+                       break;
                }
+       }
 
        mutex_unlock(&rio_mport_list_lock);
 
index 767fee2..2601953 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include <linux/rtc.h>
 #include <linux/slab.h>
 #include <linux/of_device.h>
@@ -119,24 +120,39 @@ static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev)
 }
 #endif /* CONFIG_STMP3XXX_RTC_WATCHDOG */
 
-static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
+static int stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
 {
+       int timeout = 5000; /* 3ms according to i.MX28 Ref Manual */
        /*
-        * The datasheet doesn't say which way round the
-        * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0,
-        * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS
+        * The i.MX28 Applications Processor Reference Manual, Rev. 1, 2010
+        * states:
+        * | The order in which registers are updated is
+        * | Persistent 0, 1, 2, 3, 4, 5, Alarm, Seconds.
+        * | (This list is in bitfield order, from LSB to MSB, as they would
+        * | appear in the STALE_REGS and NEW_REGS bitfields of the HW_RTC_STAT
+        * | register. For example, the Seconds register corresponds to
+        * | STALE_REGS or NEW_REGS containing 0x80.)
         */
-       while (readl(rtc_data->io + STMP3XXX_RTC_STAT) &
-                       (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT))
-               cpu_relax();
+       do {
+               if (!(readl(rtc_data->io + STMP3XXX_RTC_STAT) &
+                               (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)))
+                       return 0;
+               udelay(1);
+       } while (--timeout > 0);
+       return (readl(rtc_data->io + STMP3XXX_RTC_STAT) &
+               (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) ? -ETIME : 0;
 }
 
 /* Time read/write */
 static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 {
+       int ret;
        struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
 
-       stmp3xxx_wait_time(rtc_data);
+       ret = stmp3xxx_wait_time(rtc_data);
+       if (ret)
+               return ret;
+
        rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm);
        return 0;
 }
@@ -146,8 +162,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t)
        struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
 
        writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS);
-       stmp3xxx_wait_time(rtc_data);
-       return 0;
+       return stmp3xxx_wait_time(rtc_data);
 }
 
 /* interrupt(s) handler */
index 02faf3c..c2e80d7 100644 (file)
@@ -524,6 +524,8 @@ static int twl_rtc_probe(struct platform_device *pdev)
        if (ret < 0)
                goto out1;
 
+       device_init_wakeup(&pdev->dev, 1);
+
        rtc = rtc_device_register(pdev->name,
                                  &pdev->dev, &twl_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc)) {
@@ -542,7 +544,6 @@ static int twl_rtc_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, rtc);
-       device_init_wakeup(&pdev->dev, 1);
        return 0;
 
 out2:
index 17150a7..451bf99 100644 (file)
@@ -2392,6 +2392,12 @@ int dasd_sleep_on_immediatly(struct dasd_ccw_req *cqr)
                rc = cqr->intrc;
        else
                rc = -EIO;
+
+       /* kick tasklets */
+       dasd_schedule_device_bh(device);
+       if (device->block)
+               dasd_schedule_block_bh(device->block);
+
        return rc;
 }
 
index b6d1f92..c18c681 100644 (file)
@@ -38,7 +38,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.5.0.22"
+#define DRV_VERSION            "1.5.0.23"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
index 5f09d18..42e15ee 100644 (file)
@@ -642,19 +642,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                INIT_WORK(&fnic->fip_frame_work, fnic_handle_fip_frame);
                INIT_WORK(&fnic->event_work, fnic_handle_event);
                skb_queue_head_init(&fnic->fip_frame_queue);
-               spin_lock_irqsave(&fnic_list_lock, flags);
-               if (!fnic_fip_queue) {
-                       fnic_fip_queue =
-                               create_singlethread_workqueue("fnic_fip_q");
-                       if (!fnic_fip_queue) {
-                               spin_unlock_irqrestore(&fnic_list_lock, flags);
-                               printk(KERN_ERR PFX "fnic FIP work queue "
-                                                "create failed\n");
-                               err = -ENOMEM;
-                               goto err_out_free_max_pool;
-                       }
-               }
-               spin_unlock_irqrestore(&fnic_list_lock, flags);
                INIT_LIST_HEAD(&fnic->evlist);
                INIT_LIST_HEAD(&fnic->vlans);
        } else {
@@ -960,6 +947,13 @@ static int __init fnic_init_module(void)
        spin_lock_init(&fnic_list_lock);
        INIT_LIST_HEAD(&fnic_list);
 
+       fnic_fip_queue = create_singlethread_workqueue("fnic_fip_q");
+       if (!fnic_fip_queue) {
+               printk(KERN_ERR PFX "fnic FIP work queue create failed\n");
+               err = -ENOMEM;
+               goto err_create_fip_workq;
+       }
+
        fnic_fc_transport = fc_attach_transport(&fnic_fc_functions);
        if (!fnic_fc_transport) {
                printk(KERN_ERR PFX "fc_attach_transport error\n");
@@ -978,6 +972,8 @@ static int __init fnic_init_module(void)
 err_pci_register:
        fc_release_transport(fnic_fc_transport);
 err_fc_transport:
+       destroy_workqueue(fnic_fip_queue);
+err_create_fip_workq:
        destroy_workqueue(fnic_event_queue);
 err_create_fnic_workq:
        kmem_cache_destroy(fnic_io_req_cache);
index 0177295..1f0ca68 100644 (file)
@@ -3547,11 +3547,21 @@ static int megasas_init_fw(struct megasas_instance *instance)
                break;
        }
 
-       /*
-        * We expect the FW state to be READY
-        */
-       if (megasas_transition_to_ready(instance, 0))
-               goto fail_ready_state;
+       if (megasas_transition_to_ready(instance, 0)) {
+               atomic_set(&instance->fw_reset_no_pci_access, 1);
+               instance->instancet->adp_reset
+                       (instance, instance->reg_set);
+               atomic_set(&instance->fw_reset_no_pci_access, 0);
+               dev_info(&instance->pdev->dev,
+                       "megasas: FW restarted successfully from %s!\n",
+                       __func__);
+
+               /*waitting for about 30 second before retry*/
+               ssleep(30);
+
+               if (megasas_transition_to_ready(instance, 0))
+                       goto fail_ready_state;
+       }
 
        /*
         * MSI-X host index 0 is common for all adapter.
index 3b1ea34..eaa808e 100644 (file)
@@ -1031,6 +1031,9 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
 {
        int i, result;
 
+       if (sdev->skip_vpd_pages)
+               goto fail;
+
        /* Ask for all the pages supported by this device */
        result = scsi_vpd_inquiry(sdev, buf, 0, buf_len);
        if (result)
index 2168258..74b88ef 100644 (file)
@@ -751,7 +751,7 @@ static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
 
                vscsi->affinity_hint_set = true;
        } else {
-               for (i = 0; i < vscsi->num_queues - VIRTIO_SCSI_VQ_BASE; i++)
+               for (i = 0; i < vscsi->num_queues; i++)
                        virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
 
                vscsi->affinity_hint_set = false;
index 222d3e3..707966b 100644 (file)
@@ -609,7 +609,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
                else
                        buf = (void *)t->tx_buf;
                t->tx_dma = dma_map_single(&spi->dev, buf,
-                               t->len, DMA_FROM_DEVICE);
+                               t->len, DMA_TO_DEVICE);
                if (!t->tx_dma) {
                        ret = -EFAULT;
                        goto err_tx_map;
index dcceed2..81972fa 100644 (file)
@@ -1811,10 +1811,12 @@ static int zcache_comp_init(void)
 #else
        if (*zcache_comp_name != '\0') {
                ret = crypto_has_comp(zcache_comp_name, 0, 0);
-               if (!ret)
+               if (!ret) {
                        pr_info("zcache: %s not supported\n",
                                        zcache_comp_name);
-               goto out;
+                       ret = 1;
+                       goto out;
+               }
        }
        if (!ret)
                strcpy(zcache_comp_name, "lzo");
index bb91b47..2e3ea1a 100644 (file)
@@ -31,9 +31,8 @@ static int __init serial_init_chip(struct parisc_device *dev)
        int err;
 
 #ifdef CONFIG_64BIT
-       extern int iosapic_serial_irq(int cellnum);
        if (!dev->irq && (dev->id.sversion == 0xad))
-               dev->irq = iosapic_serial_irq(dev->mod_index-1);
+               dev->irq = iosapic_serial_irq(dev);
 #endif
 
        if (!dev->irq) {
index cbf1d15..22f280a 100644 (file)
@@ -773,6 +773,6 @@ module_init(arc_serial_init);
 module_exit(arc_serial_exit);
 
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("plat-arcfpga/uart");
+MODULE_ALIAS("platform:" DRIVER_NAME);
 MODULE_AUTHOR("Vineet Gupta");
 MODULE_DESCRIPTION("ARC(Synopsys) On-Chip(fpga) serial driver");
index 4f5f161..f85b8e6 100644 (file)
@@ -678,11 +678,18 @@ static void mxs_auart_settermios(struct uart_port *u,
 
 static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
 {
-       u32 istatus, istat;
+       u32 istat;
        struct mxs_auart_port *s = context;
        u32 stat = readl(s->port.membase + AUART_STAT);
 
-       istatus = istat = readl(s->port.membase + AUART_INTR);
+       istat = readl(s->port.membase + AUART_INTR);
+
+       /* ack irq */
+       writel(istat & (AUART_INTR_RTIS
+               | AUART_INTR_TXIS
+               | AUART_INTR_RXIS
+               | AUART_INTR_CTSMIS),
+                       s->port.membase + AUART_INTR_CLR);
 
        if (istat & AUART_INTR_CTSMIS) {
                uart_handle_cts_change(&s->port, stat & AUART_STAT_CTS);
@@ -702,12 +709,6 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context)
                istat &= ~AUART_INTR_TXIS;
        }
 
-       writel(istatus & (AUART_INTR_RTIS
-               | AUART_INTR_TXIS
-               | AUART_INTR_RXIS
-               | AUART_INTR_CTSMIS),
-                       s->port.membase + AUART_INTR_CLR);
-
        return IRQ_HANDLED;
 }
 
@@ -850,7 +851,7 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
        struct mxs_auart_port *s;
        struct uart_port *port;
        unsigned int old_ctrl0, old_ctrl2;
-       unsigned int to = 1000;
+       unsigned int to = 20000;
 
        if (co->index >= MXS_AUART_PORTS || co->index < 0)
                return;
@@ -871,18 +872,23 @@ auart_console_write(struct console *co, const char *str, unsigned int count)
 
        uart_console_write(port, str, count, mxs_auart_console_putchar);
 
-       /*
-        * Finally, wait for transmitter to become empty
-        * and restore the TCR
-        */
+       /* Finally, wait for transmitter to become empty ... */
        while (readl(port->membase + AUART_STAT) & AUART_STAT_BUSY) {
+               udelay(1);
                if (!to--)
                        break;
-               udelay(1);
        }
 
-       writel(old_ctrl0, port->membase + AUART_CTRL0);
-       writel(old_ctrl2, port->membase + AUART_CTRL2);
+       /*
+        * ... and restore the TCR if we waited long enough for the transmitter
+        * to be idle. This might keep the transmitter enabled although it is
+        * unused, but that is better than to disable it while it is still
+        * transmitting.
+        */
+       if (!(readl(port->membase + AUART_STAT) & AUART_STAT_BUSY)) {
+               writel(old_ctrl0, port->membase + AUART_CTRL0);
+               writel(old_ctrl2, port->membase + AUART_CTRL2);
+       }
 
        clk_disable(s->clk);
 }
index 121aeb9..f597e88 100644 (file)
@@ -256,10 +256,9 @@ void tty_port_tty_hangup(struct tty_port *port, bool check_clocal)
 {
        struct tty_struct *tty = tty_port_tty_get(port);
 
-       if (tty && (!check_clocal || !C_CLOCAL(tty))) {
+       if (tty && (!check_clocal || !C_CLOCAL(tty)))
                tty_hangup(tty);
-               tty_kref_put(tty);
-       }
+       tty_kref_put(tty);
 }
 EXPORT_SYMBOL_GPL(tty_port_tty_hangup);
 
index eb2aa2e..d1bd8ef 100644 (file)
@@ -12,7 +12,7 @@ if USB_CHIPIDEA
 
 config USB_CHIPIDEA_UDC
        bool "ChipIdea device controller"
-       depends on USB_GADGET=y || USB_CHIPIDEA=m
+       depends on USB_GADGET=y || (USB_CHIPIDEA=m && USB_GADGET=m)
        help
          Say Y here to enable device controller functionality of the
          ChipIdea driver.
@@ -20,7 +20,7 @@ config USB_CHIPIDEA_UDC
 config USB_CHIPIDEA_HOST
        bool "ChipIdea host controller"
        depends on USB=y
-       depends on USB_EHCI_HCD=y || USB_CHIPIDEA=m
+       depends on USB_EHCI_HCD=y || (USB_CHIPIDEA=m && USB_EHCI_HCD=m)
        select USB_EHCI_ROOT_HUB_TT
        help
          Say Y here to enable host controller functionality of the
index aefa026..1b23e35 100644 (file)
@@ -50,7 +50,7 @@
 #define PORTSC_PTC            (0x0FUL << 16)
 /* PTS and PTW for non lpm version only */
 #define PORTSC_PTS(d)                                          \
-       ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
+       (u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
 #define PORTSC_PTW            BIT(28)
 #define PORTSC_STS            BIT(29)
 
@@ -59,7 +59,7 @@
 #define DEVLC_PSPD_HS         (0x02UL << 25)
 #define DEVLC_PTW             BIT(27)
 #define DEVLC_STS             BIT(28)
-#define DEVLC_PTS(d)          (((d) & 0x7) << 29)
+#define DEVLC_PTS(d)          (u32)(((d) & 0x7) << 29)
 
 /* Encoding for DEVLC_PTS and PORTSC_PTS */
 #define PTS_UTMI              0
index 609dbc2..83b4ef4 100644 (file)
@@ -1119,11 +1119,11 @@ static int usbtmc_probe(struct usb_interface *intf,
        /* Determine if it is a Rigol or not */
        data->rigol_quirk = 0;
        dev_dbg(&intf->dev, "Trying to find if device Vendor 0x%04X Product 0x%04X has the RIGOL quirk\n",
-               data->usb_dev->descriptor.idVendor,
-               data->usb_dev->descriptor.idProduct);
+               le16_to_cpu(data->usb_dev->descriptor.idVendor),
+               le16_to_cpu(data->usb_dev->descriptor.idProduct));
        for(n = 0; usbtmc_id_quirk[n].idVendor > 0; n++) {
-               if ((usbtmc_id_quirk[n].idVendor == data->usb_dev->descriptor.idVendor) &&
-                   (usbtmc_id_quirk[n].idProduct == data->usb_dev->descriptor.idProduct)) {
+               if ((usbtmc_id_quirk[n].idVendor == le16_to_cpu(data->usb_dev->descriptor.idVendor)) &&
+                   (usbtmc_id_quirk[n].idProduct == le16_to_cpu(data->usb_dev->descriptor.idProduct))) {
                        dev_dbg(&intf->dev, "Setting this device as having the RIGOL quirk\n");
                        data->rigol_quirk = 1;
                        break;
index 4a8a1d6..558313d 100644 (file)
@@ -4798,7 +4798,8 @@ static void hub_events(void)
                                        hub->ports[i - 1]->child;
 
                                dev_dbg(hub_dev, "warm reset port %d\n", i);
-                               if (!udev) {
+                               if (!udev || !(portstatus &
+                                               USB_PORT_STAT_CONNECTION)) {
                                        status = hub_port_reset(hub, i,
                                                        NULL, HUB_BH_RESET_TIME,
                                                        true);
@@ -4808,8 +4809,8 @@ static void hub_events(void)
                                        usb_lock_device(udev);
                                        status = usb_reset_device(udev);
                                        usb_unlock_device(udev);
+                                       connect_change = 0;
                                }
-                               connect_change = 0;
                        }
 
                        if (connect_change)
index a635988..5b44cd4 100644 (file)
@@ -78,6 +78,12 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x04d8, 0x000c), .driver_info =
                        USB_QUIRK_CONFIG_INTF_STRINGS },
 
+       /* CarrolTouch 4000U */
+       { USB_DEVICE(0x04e7, 0x0009), .driver_info = USB_QUIRK_RESET_RESUME },
+
+       /* CarrolTouch 4500U */
+       { USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* Samsung Android phone modem - ID conflict with SPH-I500 */
        { USB_DEVICE(0x04e8, 0x6601), .driver_info =
                        USB_QUIRK_CONFIG_INTF_STRINGS },
index f48712f..c1c113e 100644 (file)
@@ -449,14 +449,20 @@ fail:
 
 static int __exit eth_unbind(struct usb_composite_dev *cdev)
 {
-       if (has_rndis())
+       if (has_rndis()) {
+               usb_put_function(f_rndis);
                usb_put_function_instance(fi_rndis);
-       if (use_eem)
+       }
+       if (use_eem) {
+               usb_put_function(f_eem);
                usb_put_function_instance(fi_eem);
-       else if (can_support_ecm(cdev->gadget))
+       } else if (can_support_ecm(cdev->gadget)) {
+               usb_put_function(f_ecm);
                usb_put_function_instance(fi_ecm);
-       else
+       } else {
+               usb_put_function(f_geth);
                usb_put_function_instance(fi_geth);
+       }
        return 0;
 }
 
index 1bf26e9..eb3aa81 100644 (file)
@@ -488,7 +488,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_ep *ep;
        int status, i;
 
-#ifndef USBF_PHONET_INCLUDED
        struct f_phonet_opts *phonet_opts;
 
        phonet_opts = container_of(f->fi, struct f_phonet_opts, func_inst);
@@ -507,7 +506,6 @@ static int pn_bind(struct usb_configuration *c, struct usb_function *f)
                        return status;
                phonet_opts->bound = true;
        }
-#endif
 
        /* Reserve interface IDs */
        status = usb_interface_id(c, f);
index 032b96a..2a1ebef 100644 (file)
@@ -160,10 +160,8 @@ static __init int rndis_do_config(struct usb_configuration *c)
                return ret;
 
        f_acm_rndis = usb_get_function(fi_acm);
-       if (IS_ERR(f_acm_rndis)) {
-               ret = PTR_ERR(f_acm_rndis);
-               goto err_func_acm;
-       }
+       if (IS_ERR(f_acm_rndis))
+               return PTR_ERR(f_acm_rndis);
 
        ret = usb_add_function(c, f_acm_rndis);
        if (ret)
@@ -178,7 +176,6 @@ err_fsg:
        usb_remove_function(c, f_acm_rndis);
 err_conf:
        usb_put_function(f_acm_rndis);
-err_func_acm:
        return ret;
 }
 
@@ -226,7 +223,7 @@ static __init int cdc_do_config(struct usb_configuration *c)
        /* implicit port_num is zero */
        f_acm_multi = usb_get_function(fi_acm);
        if (IS_ERR(f_acm_multi))
-               goto err_func_acm;
+               return PTR_ERR(f_acm_multi);
 
        ret = usb_add_function(c, f_acm_multi);
        if (ret)
@@ -241,7 +238,6 @@ err_fsg:
        usb_remove_function(c, f_acm_multi);
 err_conf:
        usb_put_function(f_acm_multi);
-err_func_acm:
        return ret;
 }
 
index c28ac98..13e25f8 100644 (file)
@@ -109,7 +109,7 @@ void usb_gadget_set_state(struct usb_gadget *gadget,
                enum usb_device_state state)
 {
        gadget->state = state;
-       sysfs_notify(&gadget->dev.kobj, NULL, "status");
+       sysfs_notify(&gadget->dev.kobj, NULL, "state");
 }
 EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
index f80d033..8e3c878 100644 (file)
@@ -1391,21 +1391,20 @@ iso_stream_schedule (
 
                /* Behind the scheduling threshold? */
                if (unlikely(start < next)) {
+                       unsigned now2 = (now - base) & (mod - 1);
 
                        /* USB_ISO_ASAP: Round up to the first available slot */
                        if (urb->transfer_flags & URB_ISO_ASAP)
                                start += (next - start + period - 1) & -period;
 
                        /*
-                        * Not ASAP: Use the next slot in the stream.  If
-                        * the entire URB falls before the threshold, fail.
+                        * Not ASAP: Use the next slot in the stream,
+                        * no matter what.
                         */
-                       else if (start + span - period < next) {
-                               ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n",
+                       else if (start + span - period < now2) {
+                               ehci_dbg(ehci, "iso underrun %p (%u+%u < %u)\n",
                                                urb, start + base,
-                                               span - period, next + base);
-                               status = -EXDEV;
-                               goto fail;
+                                               span - period, now2 + base);
                        }
                }
 
index df6978a..6f8c2fd 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/dmapool.h>
+#include <linux/dma-mapping.h>
 
 #include "xhci.h"
 
index 41eb4fc..9478caa 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/dmi.h>
+#include <linux/dma-mapping.h>
 
 #include "xhci.h"
 
index eb3c8c1..eeb2720 100644 (file)
@@ -830,7 +830,7 @@ static int adu_probe(struct usb_interface *interface,
 
        /* let the user know what node this device is now attached to */
        dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n",
-                udev->descriptor.idProduct, dev->serial_number,
+                le16_to_cpu(udev->descriptor.idProduct), dev->serial_number,
                 (dev->minor - ADU_MINOR_BASE));
 exit:
        dbg(2, " %s : leave, return value %p (dev)", __func__, dev);
index 6708a3b..f44e8b5 100644 (file)
@@ -481,7 +481,7 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32);
 
 static int omap2430_probe(struct platform_device *pdev)
 {
-       struct resource                 musb_resources[2];
+       struct resource                 musb_resources[3];
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
        struct omap_musb_board_data     *data;
        struct platform_device          *musb;
@@ -581,6 +581,11 @@ static int omap2430_probe(struct platform_device *pdev)
        musb_resources[1].end = pdev->resource[1].end;
        musb_resources[1].flags = pdev->resource[1].flags;
 
+       musb_resources[2].name = pdev->resource[2].name;
+       musb_resources[2].start = pdev->resource[2].start;
+       musb_resources[2].end = pdev->resource[2].end;
+       musb_resources[2].flags = pdev->resource[2].flags;
+
        ret = platform_device_add_resources(musb, musb_resources,
                        ARRAY_SIZE(musb_resources));
        if (ret) {
index 2c06a89..6f8a9ca 100644 (file)
@@ -1156,7 +1156,7 @@ static u64 tusb_dmamask = DMA_BIT_MASK(32);
 
 static int tusb_probe(struct platform_device *pdev)
 {
-       struct resource musb_resources[2];
+       struct resource musb_resources[3];
        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
        struct platform_device          *musb;
        struct tusb6010_glue            *glue;
@@ -1199,6 +1199,11 @@ static int tusb_probe(struct platform_device *pdev)
        musb_resources[1].end = pdev->resource[1].end;
        musb_resources[1].flags = pdev->resource[1].flags;
 
+       musb_resources[2].name = pdev->resource[2].name;
+       musb_resources[2].start = pdev->resource[2].start;
+       musb_resources[2].end = pdev->resource[2].end;
+       musb_resources[2].flags = pdev->resource[2].flags;
+
        ret = platform_device_add_resources(musb, musb_resources,
                        ARRAY_SIZE(musb_resources));
        if (ret) {
index 8c3a42e..7eef9b3 100644 (file)
@@ -719,6 +719,13 @@ config USB_SERIAL_FLASHLOADER
          To compile this driver as a module, choose M here: the
          module will be called flashloader.
 
+config USB_SERIAL_SUUNTO
+       tristate "USB Suunto ANT+ driver"
+       help
+         Say Y here if you want to use the Suunto ANT+ USB device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called suunto.
 
 config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
index f713011..a14a870 100644 (file)
@@ -54,6 +54,7 @@ obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)          += siemens_mpi.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)                += sierra.o
 obj-$(CONFIG_USB_SERIAL_SPCP8X5)               += spcp8x5.o
 obj-$(CONFIG_USB_SERIAL_SSU100)                        += ssu100.o
+obj-$(CONFIG_USB_SERIAL_SUUNTO)                        += suunto.o
 obj-$(CONFIG_USB_SERIAL_SYMBOL)                        += symbolserial.o
 obj-$(CONFIG_USB_SERIAL_WWAN)                  += usb_wwan.o
 obj-$(CONFIG_USB_SERIAL_TI)                    += ti_usb_3410_5052.o
index 7260ec6..b65e657 100644 (file)
@@ -735,9 +735,34 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
                .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
        { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_CT29B_PID) },
-       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_RTS01_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29A_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29F_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S01_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_29C_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_81B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_82B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5D_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K4Y_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_K5G_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S05_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_60_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_61_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_62_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_63B_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_64_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_65_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_92D_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_W5R_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_A5R_PID) },
+       { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_PW1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
        { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
index 6dd7925..1b8af46 100644 (file)
 /*
  * RT Systems programming cables for various ham radios
  */
-#define RTSYSTEMS_VID                  0x2100  /* Vendor ID */
-#define RTSYSTEMS_SERIAL_VX7_PID       0x9e52  /* Serial converter for VX-7 Radios using FT232RL */
-#define RTSYSTEMS_CT29B_PID            0x9e54  /* CT29B Radio Cable */
-#define RTSYSTEMS_RTS01_PID            0x9e57  /* USB-RTS01 Radio Cable */
-
+#define RTSYSTEMS_VID          0x2100  /* Vendor ID */
+#define RTSYSTEMS_USB_S03_PID  0x9001  /* RTS-03 USB to Serial Adapter */
+#define RTSYSTEMS_USB_59_PID   0x9e50  /* USB-59 USB to 8 pin plug */
+#define RTSYSTEMS_USB_57A_PID  0x9e51  /* USB-57A USB to 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_57B_PID  0x9e52  /* USB-57B USB to extended 4pin 3.5mm plug */
+#define RTSYSTEMS_USB_29A_PID  0x9e53  /* USB-29A USB to 3.5mm stereo plug */
+#define RTSYSTEMS_USB_29B_PID  0x9e54  /* USB-29B USB to 6 pin mini din */
+#define RTSYSTEMS_USB_29F_PID  0x9e55  /* USB-29F USB to 6 pin modular plug */
+#define RTSYSTEMS_USB_62B_PID  0x9e56  /* USB-62B USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_S01_PID  0x9e57  /* USB-RTS01 USB to 3.5 mm stereo plug*/
+#define RTSYSTEMS_USB_63_PID   0x9e58  /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_29C_PID  0x9e59  /* USB-29C USB to 4 pin modular plug*/
+#define RTSYSTEMS_USB_81B_PID  0x9e5A  /* USB-81 USB to 8 pin mini din plug*/
+#define RTSYSTEMS_USB_82B_PID  0x9e5B  /* USB-82 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_K5D_PID  0x9e5C  /* USB-K5D USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_K4Y_PID  0x9e5D  /* USB-K4Y USB to 2.5/3.5 mm plugs*/
+#define RTSYSTEMS_USB_K5G_PID  0x9e5E  /* USB-K5G USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_S05_PID  0x9e5F  /* USB-RTS05 USB to 2.5 mm stereo plug*/
+#define RTSYSTEMS_USB_60_PID   0x9e60  /* USB-60 USB to 6 pin din*/
+#define RTSYSTEMS_USB_61_PID   0x9e61  /* USB-61 USB to 6 pin mini din*/
+#define RTSYSTEMS_USB_62_PID   0x9e62  /* USB-62 USB to 8 pin mini din*/
+#define RTSYSTEMS_USB_63B_PID  0x9e63  /* USB-63 USB to 9 pin female*/
+#define RTSYSTEMS_USB_64_PID   0x9e64  /* USB-64 USB to 9 pin male*/
+#define RTSYSTEMS_USB_65_PID   0x9e65  /* USB-65 USB to 9 pin female null modem*/
+#define RTSYSTEMS_USB_92_PID   0x9e66  /* USB-92 USB to 12 pin plug*/
+#define RTSYSTEMS_USB_92D_PID  0x9e67  /* USB-92D USB to 12 pin plug data*/
+#define RTSYSTEMS_USB_W5R_PID  0x9e68  /* USB-W5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_A5R_PID  0x9e69  /* USB-A5R USB to 8 pin modular plug*/
+#define RTSYSTEMS_USB_PW1_PID  0x9e6A  /* USB-PW1 USB to 8 pin modular plug*/
 
 /*
  * Physik Instrumente
index 5a97972..58c17fd 100644 (file)
@@ -2303,7 +2303,7 @@ static int keyspan_startup(struct usb_serial *serial)
        if (d_details == NULL) {
                dev_err(&serial->dev->dev, "%s - unknown product id %x\n",
                    __func__, le16_to_cpu(serial->dev->descriptor.idProduct));
-               return 1;
+               return -ENODEV;
        }
 
        /* Setup private data for serial driver */
index 51da424..b013001 100644 (file)
@@ -90,6 +90,7 @@ struct urbtracker {
        struct list_head        urblist_entry;
        struct kref             ref_count;
        struct urb              *urb;
+       struct usb_ctrlrequest  *setup;
 };
 
 enum mos7715_pp_modes {
@@ -271,6 +272,7 @@ static void destroy_urbtracker(struct kref *kref)
        struct mos7715_parport *mos_parport = urbtrack->mos_parport;
 
        usb_free_urb(urbtrack->urb);
+       kfree(urbtrack->setup);
        kfree(urbtrack);
        kref_put(&mos_parport->ref_count, destroy_mos_parport);
 }
@@ -355,7 +357,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
        struct urbtracker *urbtrack;
        int ret_val;
        unsigned long flags;
-       struct usb_ctrlrequest setup;
        struct usb_serial *serial = mos_parport->serial;
        struct usb_device *usbdev = serial->dev;
 
@@ -373,14 +374,20 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,
                kfree(urbtrack);
                return -ENOMEM;
        }
-       setup.bRequestType = (__u8)0x40;
-       setup.bRequest = (__u8)0x0e;
-       setup.wValue = get_reg_value(reg, dummy);
-       setup.wIndex = get_reg_index(reg);
-       setup.wLength = 0;
+       urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_KERNEL);
+       if (!urbtrack->setup) {
+               usb_free_urb(urbtrack->urb);
+               kfree(urbtrack);
+               return -ENOMEM;
+       }
+       urbtrack->setup->bRequestType = (__u8)0x40;
+       urbtrack->setup->bRequest = (__u8)0x0e;
+       urbtrack->setup->wValue = get_reg_value(reg, dummy);
+       urbtrack->setup->wIndex = get_reg_index(reg);
+       urbtrack->setup->wLength = 0;
        usb_fill_control_urb(urbtrack->urb, usbdev,
                             usb_sndctrlpipe(usbdev, 0),
-                            (unsigned char *)&setup,
+                            (unsigned char *)urbtrack->setup,
                             NULL, 0, async_complete, urbtrack);
        kref_init(&urbtrack->ref_count);
        INIT_LIST_HEAD(&urbtrack->urblist_entry);
index 603fb70..3bac469 100644 (file)
 #define LED_ON_MS      500
 #define LED_OFF_MS     500
 
-static int device_type;
+enum mos7840_flag {
+       MOS7840_FLAG_CTRL_BUSY,
+       MOS7840_FLAG_LED_BUSY,
+};
 
 static const struct usb_device_id id_table[] = {
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
@@ -238,9 +241,12 @@ struct moschip_port {
 
        /* For device(s) with LED indicator */
        bool has_led;
-       bool led_flag;
        struct timer_list led_timer1;   /* Timer for LED on */
        struct timer_list led_timer2;   /* Timer for LED off */
+       struct urb *led_urb;
+       struct usb_ctrlrequest *led_dr;
+
+       unsigned long flags;
 };
 
 /*
@@ -460,10 +466,10 @@ static void mos7840_control_callback(struct urb *urb)
        case -ESHUTDOWN:
                /* this urb is terminated, clean up */
                dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status);
-               return;
+               goto out;
        default:
                dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status);
-               return;
+               goto out;
        }
 
        dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length);
@@ -476,6 +482,8 @@ static void mos7840_control_callback(struct urb *urb)
                mos7840_handle_new_msr(mos7840_port, regval);
        else if (mos7840_port->MsrLsr == 1)
                mos7840_handle_new_lsr(mos7840_port, regval);
+out:
+       clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags);
 }
 
 static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
@@ -486,6 +494,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
        unsigned char *buffer = mcs->ctrl_buf;
        int ret;
 
+       if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags))
+               return -EBUSY;
+
        dr->bRequestType = MCS_RD_RTYPE;
        dr->bRequest = MCS_RDREQ;
        dr->wValue = cpu_to_le16(Wval); /* 0 */
@@ -497,6 +508,9 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
                             mos7840_control_callback, mcs);
        mcs->control_urb->transfer_buffer_length = 2;
        ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+       if (ret)
+               clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags);
+
        return ret;
 }
 
@@ -523,7 +537,7 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
                                __u16 reg)
 {
        struct usb_device *dev = mcs->port->serial->dev;
-       struct usb_ctrlrequest *dr = mcs->dr;
+       struct usb_ctrlrequest *dr = mcs->led_dr;
 
        dr->bRequestType = MCS_WR_RTYPE;
        dr->bRequest = MCS_WRREQ;
@@ -531,10 +545,10 @@ static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
        dr->wIndex = cpu_to_le16(reg);
        dr->wLength = cpu_to_le16(0);
 
-       usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
+       usb_fill_control_urb(mcs->led_urb, dev, usb_sndctrlpipe(dev, 0),
                (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
 
-       usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+       usb_submit_urb(mcs->led_urb, GFP_ATOMIC);
 }
 
 static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
@@ -560,7 +574,19 @@ static void mos7840_led_flag_off(unsigned long arg)
 {
        struct moschip_port *mcs = (struct moschip_port *) arg;
 
-       mcs->led_flag = false;
+       clear_bit_unlock(MOS7840_FLAG_LED_BUSY, &mcs->flags);
+}
+
+static void mos7840_led_activity(struct usb_serial_port *port)
+{
+       struct moschip_port *mos7840_port = usb_get_serial_port_data(port);
+
+       if (test_and_set_bit_lock(MOS7840_FLAG_LED_BUSY, &mos7840_port->flags))
+               return;
+
+       mos7840_set_led_async(mos7840_port, 0x0301, MODEM_CONTROL_REGISTER);
+       mod_timer(&mos7840_port->led_timer1,
+                               jiffies + msecs_to_jiffies(LED_ON_MS));
 }
 
 /*****************************************************************************
@@ -758,14 +784,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)
                return;
        }
 
-       /* Turn on LED */
-       if (mos7840_port->has_led && !mos7840_port->led_flag) {
-               mos7840_port->led_flag = true;
-               mos7840_set_led_async(mos7840_port, 0x0301,
-                                       MODEM_CONTROL_REGISTER);
-               mod_timer(&mos7840_port->led_timer1,
-                               jiffies + msecs_to_jiffies(LED_ON_MS));
-       }
+       if (mos7840_port->has_led)
+               mos7840_led_activity(port);
 
        mos7840_port->read_urb_busy = true;
        retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -816,18 +836,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
 /************************************************************************/
 /*       D R I V E R  T T Y  I N T E R F A C E  F U N C T I O N S       */
 /************************************************************************/
-#ifdef MCSSerialProbe
-static int mos7840_serial_probe(struct usb_serial *serial,
-                               const struct usb_device_id *id)
-{
-
-       /*need to implement the mode_reg reading and updating\
-          structures usb_serial_ device_type\
-          (i.e num_ports, num_bulkin,bulkout etc) */
-       /* Also we can update the changes  attach */
-       return 1;
-}
-#endif
 
 /*****************************************************************************
  * mos7840_open
@@ -1454,13 +1462,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
        data1 = urb->transfer_buffer;
        dev_dbg(&port->dev, "bulkout endpoint is %d\n", port->bulk_out_endpointAddress);
 
-       /* Turn on LED */
-       if (mos7840_port->has_led && !mos7840_port->led_flag) {
-               mos7840_port->led_flag = true;
-               mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
-               mod_timer(&mos7840_port->led_timer1,
-                               jiffies + msecs_to_jiffies(LED_ON_MS));
-       }
+       if (mos7840_port->has_led)
+               mos7840_led_activity(port);
 
        /* send it down the pipe */
        status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -2187,38 +2190,48 @@ static int mos7810_check(struct usb_serial *serial)
        return 0;
 }
 
-static int mos7840_calc_num_ports(struct usb_serial *serial)
+static int mos7840_probe(struct usb_serial *serial,
+                               const struct usb_device_id *id)
 {
-       __u16 data = 0x00;
+       u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
        u8 *buf;
-       int mos7840_num_ports;
+       int device_type;
+
+       if (product == MOSCHIP_DEVICE_ID_7810 ||
+               product == MOSCHIP_DEVICE_ID_7820) {
+               device_type = product;
+               goto out;
+       }
 
        buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
-       if (buf) {
-               usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+       if (!buf)
+               return -ENOMEM;
+
+       usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                        MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, buf,
                        VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
-               data = *buf;
-               kfree(buf);
-       }
 
-       if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
-               serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
-               device_type = serial->dev->descriptor.idProduct;
-       } else {
-               /* For a MCS7840 device GPIO0 must be set to 1 */
-               if ((data & 0x01) == 1)
-                       device_type = MOSCHIP_DEVICE_ID_7840;
-               else if (mos7810_check(serial))
-                       device_type = MOSCHIP_DEVICE_ID_7810;
-               else
-                       device_type = MOSCHIP_DEVICE_ID_7820;
-       }
+       /* For a MCS7840 device GPIO0 must be set to 1 */
+       if (buf[0] & 0x01)
+               device_type = MOSCHIP_DEVICE_ID_7840;
+       else if (mos7810_check(serial))
+               device_type = MOSCHIP_DEVICE_ID_7810;
+       else
+               device_type = MOSCHIP_DEVICE_ID_7820;
+
+       kfree(buf);
+out:
+       usb_set_serial_data(serial, (void *)(unsigned long)device_type);
+
+       return 0;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+       int device_type = (unsigned long)usb_get_serial_data(serial);
+       int mos7840_num_ports;
 
        mos7840_num_ports = (device_type >> 4) & 0x000F;
-       serial->num_bulk_in = mos7840_num_ports;
-       serial->num_bulk_out = mos7840_num_ports;
-       serial->num_ports = mos7840_num_ports;
 
        return mos7840_num_ports;
 }
@@ -2226,6 +2239,7 @@ static int mos7840_calc_num_ports(struct usb_serial *serial)
 static int mos7840_port_probe(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
+       int device_type = (unsigned long)usb_get_serial_data(serial);
        struct moschip_port *mos7840_port;
        int status;
        int pnum;
@@ -2401,6 +2415,14 @@ static int mos7840_port_probe(struct usb_serial_port *port)
        if (device_type == MOSCHIP_DEVICE_ID_7810) {
                mos7840_port->has_led = true;
 
+               mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL);
+               mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr),
+                                                               GFP_KERNEL);
+               if (!mos7840_port->led_urb || !mos7840_port->led_dr) {
+                       status = -ENOMEM;
+                       goto error;
+               }
+
                init_timer(&mos7840_port->led_timer1);
                mos7840_port->led_timer1.function = mos7840_led_off;
                mos7840_port->led_timer1.expires =
@@ -2413,8 +2435,6 @@ static int mos7840_port_probe(struct usb_serial_port *port)
                        jiffies + msecs_to_jiffies(LED_OFF_MS);
                mos7840_port->led_timer2.data = (unsigned long)mos7840_port;
 
-               mos7840_port->led_flag = false;
-
                /* Turn off LED */
                mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300);
        }
@@ -2436,6 +2456,8 @@ out:
        }
        return 0;
 error:
+       kfree(mos7840_port->led_dr);
+       usb_free_urb(mos7840_port->led_urb);
        kfree(mos7840_port->dr);
        kfree(mos7840_port->ctrl_buf);
        usb_free_urb(mos7840_port->control_urb);
@@ -2456,6 +2478,10 @@ static int mos7840_port_remove(struct usb_serial_port *port)
 
                del_timer_sync(&mos7840_port->led_timer1);
                del_timer_sync(&mos7840_port->led_timer2);
+
+               usb_kill_urb(mos7840_port->led_urb);
+               usb_free_urb(mos7840_port->led_urb);
+               kfree(mos7840_port->led_dr);
        }
        usb_kill_urb(mos7840_port->control_urb);
        usb_free_urb(mos7840_port->control_urb);
@@ -2482,9 +2508,7 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .throttle = mos7840_throttle,
        .unthrottle = mos7840_unthrottle,
        .calc_num_ports = mos7840_calc_num_ports,
-#ifdef MCSSerialProbe
-       .probe = mos7840_serial_probe,
-#endif
+       .probe = mos7840_probe,
        .ioctl = mos7840_ioctl,
        .set_termios = mos7840_set_termios,
        .break_ctl = mos7840_break,
diff --git a/drivers/usb/serial/suunto.c b/drivers/usb/serial/suunto.c
new file mode 100644 (file)
index 0000000..2248e7a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Suunto ANT+ USB Driver
+ *
+ * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+ * Copyright (C) 2013 Linux Foundation
+ *
+ * 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 only.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/uaccess.h>
+
+static const struct usb_device_id id_table[] = {
+       { USB_DEVICE(0x0fcf, 0x1008) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_serial_driver suunto_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         KBUILD_MODNAME,
+       },
+       .id_table =             id_table,
+       .num_ports =            1,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+       &suunto_device,
+       NULL,
+};
+
+module_usb_serial_driver(serial_drivers, id_table);
+MODULE_LICENSE("GPL");
index 375b5a4..5c9f9b1 100644 (file)
@@ -1536,14 +1536,15 @@ static int ti_download_firmware(struct ti_device *tdev)
        char buf[32];
 
        /* try ID specific firmware first, then try generic firmware */
-       sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor,
-           dev->descriptor.idProduct);
+       sprintf(buf, "ti_usb-v%04x-p%04x.fw",
+                       le16_to_cpu(dev->descriptor.idVendor),
+                       le16_to_cpu(dev->descriptor.idProduct));
        status = request_firmware(&fw_p, buf, &dev->dev);
 
        if (status != 0) {
                buf[0] = '\0';
-               if (dev->descriptor.idVendor == MTS_VENDOR_ID) {
-                       switch (dev->descriptor.idProduct) {
+               if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) {
+                       switch (le16_to_cpu(dev->descriptor.idProduct)) {
                        case MTS_CDMA_PRODUCT_ID:
                                strcpy(buf, "mts_cdma.fw");
                                break;
index 8257d30..8536578 100644 (file)
@@ -291,18 +291,18 @@ static void usb_wwan_indat_callback(struct urb *urb)
                        tty_flip_buffer_push(&port->port);
                } else
                        dev_dbg(dev, "%s: empty read urb received\n", __func__);
-
-               /* Resubmit urb so we continue receiving */
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err) {
-                       if (err != -EPERM) {
-                               dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err);
-                               /* busy also in error unless we are killed */
-                               usb_mark_last_busy(port->serial->dev);
-                       }
-               } else {
+       }
+       /* Resubmit urb so we continue receiving */
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err) {
+               if (err != -EPERM) {
+                       dev_err(dev, "%s: resubmit read urb failed. (%d)\n",
+                               __func__, err);
+                       /* busy also in error unless we are killed */
                        usb_mark_last_busy(port->serial->dev);
                }
+       } else {
+               usb_mark_last_busy(port->serial->dev);
        }
 }
 
index 16968c8..d3493ca 100644 (file)
@@ -1226,6 +1226,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)
        }
        spin_lock_irqsave(&xfer->lock, flags);
        rpipe = xfer->ep->hcpriv;
+       if (rpipe == NULL) {
+               pr_debug("%s: xfer id 0x%08X has no RPIPE.  %s",
+                       __func__, wa_xfer_id(xfer),
+                       "Probably already aborted.\n" );
+               goto out_unlock;
+       }
        /* Check the delayed list -> if there, release and complete */
        spin_lock_irqsave(&wa->xfer_list_lock, flags2);
        if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
@@ -1644,8 +1650,7 @@ static void wa_xfer_result_cb(struct urb *urb)
                        break;
                }
                usb_status = xfer_result->bTransferStatus & 0x3f;
-               if (usb_status == WA_XFER_STATUS_ABORTED
-                   || usb_status == WA_XFER_STATUS_NOT_FOUND)
+               if (usb_status == WA_XFER_STATUS_NOT_FOUND)
                        /* taken care of already */
                        break;
                xfer_id = xfer_result->dwTransferID;
index c5179e2..cef6002 100644 (file)
@@ -137,8 +137,27 @@ static void vfio_pci_disable(struct vfio_pci_device *vdev)
         */
        pci_write_config_word(pdev, PCI_COMMAND, PCI_COMMAND_INTX_DISABLE);
 
-       if (vdev->reset_works)
-               __pci_reset_function(pdev);
+       /*
+        * Careful, device_lock may already be held.  This is the case if
+        * a driver unbind is blocked.  Try to get the locks ourselves to
+        * prevent a deadlock.
+        */
+       if (vdev->reset_works) {
+               bool reset_done = false;
+
+               if (pci_cfg_access_trylock(pdev)) {
+                       if (device_trylock(&pdev->dev)) {
+                               __pci_reset_function_locked(pdev);
+                               reset_done = true;
+                               device_unlock(&pdev->dev);
+                       }
+                       pci_cfg_access_unlock(pdev);
+               }
+
+               if (!reset_done)
+                       pr_warn("%s: Unable to acquire locks for reset of %s\n",
+                               __func__, dev_name(&pdev->dev));
+       }
 
        pci_restore_state(pdev);
 }
index c488da5..842f450 100644 (file)
@@ -494,27 +494,6 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
        return 0;
 }
 
-static int vfio_group_nb_del_dev(struct vfio_group *group, struct device *dev)
-{
-       struct vfio_device *device;
-
-       /*
-        * Expect to fall out here.  If a device was in use, it would
-        * have been bound to a vfio sub-driver, which would have blocked
-        * in .remove at vfio_del_group_dev.  Sanity check that we no
-        * longer track the device, so it's safe to remove.
-        */
-       device = vfio_group_get_device(group, dev);
-       if (likely(!device))
-               return 0;
-
-       WARN("Device %s removed from live group %d!\n", dev_name(dev),
-            iommu_group_id(group->iommu_group));
-
-       vfio_device_put(device);
-       return 0;
-}
-
 static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev)
 {
        /* We don't care what happens when the group isn't in use */
@@ -531,13 +510,11 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
        struct device *dev = data;
 
        /*
-        * Need to go through a group_lock lookup to get a reference or
-        * we risk racing a group being removed.  Leave a WARN_ON for
-        * debuging, but if the group no longer exists, a spurious notify
-        * is harmless.
+        * Need to go through a group_lock lookup to get a reference or we
+        * risk racing a group being removed.  Ignore spurious notifies.
         */
        group = vfio_group_try_get(group);
-       if (WARN_ON(!group))
+       if (!group)
                return NOTIFY_OK;
 
        switch (action) {
@@ -545,7 +522,13 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
                vfio_group_nb_add_dev(group, dev);
                break;
        case IOMMU_GROUP_NOTIFY_DEL_DEVICE:
-               vfio_group_nb_del_dev(group, dev);
+               /*
+                * Nothing to do here.  If the device is in use, then the
+                * vfio sub-driver should block the remove callback until
+                * it is unused.  If the device is unused or attached to a
+                * stub driver, then it should be released and we don't
+                * care that it will be going away.
+                */
                break;
        case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
                pr_debug("%s: Device %s, group %d binding to driver\n",
index a89c15d..9b0f12c 100644 (file)
@@ -435,8 +435,8 @@ static int correct_chipset(struct atyfb_par *par)
        const char *name;
        int i;
 
-       for (i = ARRAY_SIZE(aty_chips); i > 0; i--)
-               if (par->pci_id == aty_chips[i - 1].pci_id)
+       for (i = (int)ARRAY_SIZE(aty_chips) - 1; i >= 0; i--)
+               if (par->pci_id == aty_chips[i].pci_id)
                        break;
 
        if (i < 0)
index 3ba3771..dc09ebe 100644 (file)
@@ -239,24 +239,6 @@ static const struct fb_bitfield def_rgb565[] = {
        }
 };
 
-static const struct fb_bitfield def_rgb666[] = {
-       [RED] = {
-               .offset = 16,
-               .length = 6,
-       },
-       [GREEN] = {
-               .offset = 8,
-               .length = 6,
-       },
-       [BLUE] = {
-               .offset = 0,
-               .length = 6,
-       },
-       [TRANSP] = {    /* no support for transparency */
-               .length = 0,
-       }
-};
-
 static const struct fb_bitfield def_rgb888[] = {
        [RED] = {
                .offset = 16,
@@ -309,9 +291,6 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
                        break;
                case STMLCDIF_16BIT:
                case STMLCDIF_18BIT:
-                       /* 24 bit to 18 bit mapping */
-                       rgb = def_rgb666;
-                       break;
                case STMLCDIF_24BIT:
                        /* real 24 bit */
                        rgb = def_rgb888;
@@ -453,11 +432,6 @@ static int mxsfb_set_par(struct fb_info *fb_info)
                        return -EINVAL;
                case STMLCDIF_16BIT:
                case STMLCDIF_18BIT:
-                       /* 24 bit to 18 bit mapping */
-                       ctrl |= CTRL_DF24; /* ignore the upper 2 bits in
-                                           *  each colour component
-                                           */
-                       break;
                case STMLCDIF_24BIT:
                        /* real 24 bit */
                        break;
index 8c527e5..796e511 100644 (file)
@@ -587,8 +587,7 @@ static int nuc900fb_probe(struct platform_device *pdev)
        fbinfo->flags                   = FBINFO_FLAG_DEFAULT;
        fbinfo->pseudo_palette          = &fbi->pseudo_pal;
 
-       ret = request_irq(irq, nuc900fb_irqhandler, 0,
-                         pdev->name, fbinfo);
+       ret = request_irq(irq, nuc900fb_irqhandler, 0, pdev->name, fbi);
        if (ret) {
                dev_err(&pdev->dev, "cannot register irq handler %d -err %d\n",
                        irq, ret);
index 5338f36..1b60698 100644 (file)
@@ -28,6 +28,20 @@ struct panel_drv_data {
        bool invert_polarity;
 };
 
+static const struct omap_video_timings tvc_pal_timings = {
+       .x_res          = 720,
+       .y_res          = 574,
+       .pixel_clock    = 13500,
+       .hsw            = 64,
+       .hfp            = 12,
+       .hbp            = 68,
+       .vsw            = 5,
+       .vfp            = 5,
+       .vbp            = 41,
+
+       .interlace      = true,
+};
+
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
 static int tvc_connect(struct omap_dss_device *dssdev)
@@ -212,14 +226,14 @@ static int tvc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ddata->timings = omap_dss_pal_timings;
+       ddata->timings = tvc_pal_timings;
 
        dssdev = &ddata->dssdev;
        dssdev->driver = &tvc_driver;
        dssdev->dev = &pdev->dev;
        dssdev->type = OMAP_DISPLAY_TYPE_VENC;
        dssdev->owner = THIS_MODULE;
-       dssdev->panel.timings = omap_dss_pal_timings;
+       dssdev->panel.timings = tvc_pal_timings;
 
        r = omapdss_register_display(dssdev);
        if (r) {
index b2a8912..a9ac3ce 100644 (file)
@@ -713,7 +713,7 @@ static int sgivwfb_mmap(struct fb_info *info,
        r = vm_iomap_memory(vma, sgivwfb_mem_phys, sgivwfb_mem_size);
 
        printk(KERN_DEBUG "sgivwfb: mmap framebuffer P(%lx)->V(%lx)\n",
-              offset, vma->vm_start);
+               sgivwfb_mem_phys + (vma->vm_pgoff << PAGE_SHIFT), vma->vm_start);
 
        return r;
 }
index a8c6c43..1265b25 100644 (file)
@@ -567,7 +567,7 @@ static int sh7760fb_remove(struct platform_device *dev)
        fb_dealloc_cmap(&info->cmap);
        sh7760fb_free_mem(info);
        if (par->irq >= 0)
-               free_irq(par->irq, par);
+               free_irq(par->irq, &par->vsync);
        iounmap(par->base);
        release_mem_region(par->ioarea->start, resource_size(par->ioarea));
        framebuffer_release(info);
index 830ded4..2827333 100644 (file)
@@ -1265,7 +1265,6 @@ static void vga16fb_imageblit(struct fb_info *info, const struct fb_image *image
 
 static void vga16fb_destroy(struct fb_info *info)
 {
-       struct platform_device *dev = container_of(info->device, struct platform_device, dev);
        iounmap(info->screen_base);
        fb_dealloc_cmap(&info->cmap);
        /* XXX unshare VGA regions */
index f3d4a69..6629b29 100644 (file)
@@ -341,8 +341,8 @@ static int xilinxfb_assign(struct platform_device *pdev,
 
        if (drvdata->flags & BUS_ACCESS_FLAG) {
                /* Put a banner in the log (for DEBUG) */
-               dev_dbg(dev, "regs: phys=%x, virt=%p\n", drvdata->regs_phys,
-                                       drvdata->regs);
+               dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
+                       &drvdata->regs_phys, drvdata->regs);
        }
        /* Put a banner in the log (for DEBUG) */
        dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
index 9e02d60..23eae5c 100644 (file)
@@ -145,7 +145,7 @@ config SWIOTLB_XEN
 
 config XEN_TMEM
        tristate
-       depends on !ARM
+       depends on !ARM && !ARM64
        default m if (CLEANCACHE || FRONTSWAP)
        help
          Shim to interface in-kernel Transcendent Memory hooks
index eabd0ee..14fe79d 100644 (file)
@@ -1,9 +1,8 @@
-ifneq ($(CONFIG_ARM),y)
-obj-y  += manage.o
+ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
 obj-$(CONFIG_HOTPLUG_CPU)              += cpu_hotplug.o
 endif
 obj-$(CONFIG_X86)                      += fallback.o
-obj-y  += grant-table.o features.o events.o balloon.o
+obj-y  += grant-table.o features.o events.o balloon.o manage.o
 obj-y  += xenbus/
 
 nostackp := $(call cc-option, -fno-stack-protector)
index 8feecf0..b6165e0 100644 (file)
@@ -379,18 +379,12 @@ static long evtchn_ioctl(struct file *file,
                if (unbind.port >= NR_EVENT_CHANNELS)
                        break;
 
-               spin_lock_irq(&port_user_lock);
-
                rc = -ENOTCONN;
-               if (get_port_user(unbind.port) != u) {
-                       spin_unlock_irq(&port_user_lock);
+               if (get_port_user(unbind.port) != u)
                        break;
-               }
 
                disable_irq(irq_from_evtchn(unbind.port));
 
-               spin_unlock_irq(&port_user_lock);
-
                evtchn_unbind_from_user(u, unbind.port);
 
                rc = 0;
@@ -490,26 +484,15 @@ static int evtchn_release(struct inode *inode, struct file *filp)
        int i;
        struct per_user_data *u = filp->private_data;
 
-       spin_lock_irq(&port_user_lock);
-
-       free_page((unsigned long)u->ring);
-
        for (i = 0; i < NR_EVENT_CHANNELS; i++) {
                if (get_port_user(i) != u)
                        continue;
 
                disable_irq(irq_from_evtchn(i));
-       }
-
-       spin_unlock_irq(&port_user_lock);
-
-       for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-               if (get_port_user(i) != u)
-                       continue;
-
                evtchn_unbind_from_user(get_port_user(i), i);
        }
 
+       free_page((unsigned long)u->ring);
        kfree(u->name);
        kfree(u);
 
index 6ed8a9d..34b20bf 100644 (file)
@@ -115,7 +115,6 @@ static int xenbus_frontend_dev_resume(struct device *dev)
                        return -EFAULT;
                }
 
-               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
                queue_work(xenbus_frontend_wq, &xdev->work);
 
                return 0;
@@ -124,6 +123,16 @@ static int xenbus_frontend_dev_resume(struct device *dev)
        return xenbus_dev_resume(dev);
 }
 
+static int xenbus_frontend_dev_probe(struct device *dev)
+{
+       if (xen_store_domain_type == XS_LOCAL) {
+               struct xenbus_device *xdev = to_xenbus_device(dev);
+               INIT_WORK(&xdev->work, xenbus_frontend_delayed_resume);
+       }
+
+       return xenbus_dev_probe(dev);
+}
+
 static const struct dev_pm_ops xenbus_pm_ops = {
        .suspend        = xenbus_dev_suspend,
        .resume         = xenbus_frontend_dev_resume,
@@ -142,7 +151,7 @@ static struct xen_bus_type xenbus_frontend = {
                .name           = "xen",
                .match          = xenbus_match,
                .uevent         = xenbus_uevent_frontend,
-               .probe          = xenbus_dev_probe,
+               .probe          = xenbus_frontend_dev_probe,
                .remove         = xenbus_dev_remove,
                .shutdown       = xenbus_dev_shutdown,
                .dev_attrs      = xenbus_dev_attrs,
@@ -474,7 +483,11 @@ static int __init xenbus_probe_frontend_init(void)
 
        register_xenstore_notifier(&xenstore_notifier);
 
-       xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+       if (xen_store_domain_type == XS_LOCAL) {
+               xenbus_frontend_wq = create_workqueue("xenbus_frontend");
+               if (!xenbus_frontend_wq)
+                       pr_warn("create xenbus frontend workqueue failed, S3 resume is likely to fail\n");
+       }
 
        return 0;
 }
index eaf1333..8bc5e8c 100644 (file)
@@ -36,16 +36,23 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,
                                u64 extent_item_pos,
                                struct extent_inode_elem **eie)
 {
-       u64 data_offset;
-       u64 data_len;
+       u64 offset = 0;
        struct extent_inode_elem *e;
 
-       data_offset = btrfs_file_extent_offset(eb, fi);
-       data_len = btrfs_file_extent_num_bytes(eb, fi);
+       if (!btrfs_file_extent_compression(eb, fi) &&
+           !btrfs_file_extent_encryption(eb, fi) &&
+           !btrfs_file_extent_other_encoding(eb, fi)) {
+               u64 data_offset;
+               u64 data_len;
 
-       if (extent_item_pos < data_offset ||
-           extent_item_pos >= data_offset + data_len)
-               return 1;
+               data_offset = btrfs_file_extent_offset(eb, fi);
+               data_len = btrfs_file_extent_num_bytes(eb, fi);
+
+               if (extent_item_pos < data_offset ||
+                   extent_item_pos >= data_offset + data_len)
+                       return 1;
+               offset = extent_item_pos - data_offset;
+       }
 
        e = kmalloc(sizeof(*e), GFP_NOFS);
        if (!e)
@@ -53,7 +60,7 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,
 
        e->next = *eie;
        e->inum = key->objectid;
-       e->offset = key->offset + (extent_item_pos - data_offset);
+       e->offset = key->offset + offset;
        *eie = e;
 
        return 0;
@@ -189,7 +196,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
        struct extent_buffer *eb;
        struct btrfs_key key;
        struct btrfs_file_extent_item *fi;
-       struct extent_inode_elem *eie = NULL;
+       struct extent_inode_elem *eie = NULL, *old = NULL;
        u64 disk_byte;
 
        if (level != 0) {
@@ -223,6 +230,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
 
                if (disk_byte == wanted_disk_byte) {
                        eie = NULL;
+                       old = NULL;
                        if (extent_item_pos) {
                                ret = check_extent_in_eb(&key, eb, fi,
                                                *extent_item_pos,
@@ -230,18 +238,20 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
                                if (ret < 0)
                                        break;
                        }
-                       if (!ret) {
-                               ret = ulist_add(parents, eb->start,
-                                               (uintptr_t)eie, GFP_NOFS);
-                               if (ret < 0)
-                                       break;
-                               if (!extent_item_pos) {
-                                       ret = btrfs_next_old_leaf(root, path,
-                                                       time_seq);
-                                       continue;
-                               }
+                       if (ret > 0)
+                               goto next;
+                       ret = ulist_add_merge(parents, eb->start,
+                                             (uintptr_t)eie,
+                                             (u64 *)&old, GFP_NOFS);
+                       if (ret < 0)
+                               break;
+                       if (!ret && extent_item_pos) {
+                               while (old->next)
+                                       old = old->next;
+                               old->next = eie;
                        }
                }
+next:
                ret = btrfs_next_old_item(root, path, time_seq);
        }
 
index 5bf4c39..ed50460 100644 (file)
@@ -1271,7 +1271,6 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
                BUG_ON(!eb_rewin);
        }
 
-       extent_buffer_get(eb_rewin);
        btrfs_tree_read_unlock(eb);
        free_extent_buffer(eb);
 
index 583d98b..fe443fe 100644 (file)
@@ -4048,7 +4048,7 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        }
 
        while (!end) {
-               u64 offset_in_extent;
+               u64 offset_in_extent = 0;
 
                /* break if the extent we found is outside the range */
                if (em->start >= max || extent_map_end(em) < off)
@@ -4064,9 +4064,12 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 
                /*
                 * record the offset from the start of the extent
-                * for adjusting the disk offset below
+                * for adjusting the disk offset below.  Only do this if the
+                * extent isn't compressed since our in ram offset may be past
+                * what we have actually allocated on disk.
                 */
-               offset_in_extent = em_start - em->start;
+               if (!test_bit(EXTENT_FLAG_COMPRESSED, &em->flags))
+                       offset_in_extent = em_start - em->start;
                em_end = extent_map_end(em);
                em_len = em_end - em_start;
                emflags = em->flags;
index a005fe2..8e686a4 100644 (file)
@@ -596,20 +596,29 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                if (no_splits)
                        goto next;
 
-               if (em->block_start < EXTENT_MAP_LAST_BYTE &&
-                   em->start < start) {
+               if (em->start < start) {
                        split->start = em->start;
                        split->len = start - em->start;
-                       split->orig_start = em->orig_start;
-                       split->block_start = em->block_start;
 
-                       if (compressed)
-                               split->block_len = em->block_len;
-                       else
-                               split->block_len = split->len;
-                       split->ram_bytes = em->ram_bytes;
-                       split->orig_block_len = max(split->block_len,
-                                                   em->orig_block_len);
+                       if (em->block_start < EXTENT_MAP_LAST_BYTE) {
+                               split->orig_start = em->orig_start;
+                               split->block_start = em->block_start;
+
+                               if (compressed)
+                                       split->block_len = em->block_len;
+                               else
+                                       split->block_len = split->len;
+                               split->orig_block_len = max(split->block_len,
+                                               em->orig_block_len);
+                               split->ram_bytes = em->ram_bytes;
+                       } else {
+                               split->orig_start = split->start;
+                               split->block_len = 0;
+                               split->block_start = em->block_start;
+                               split->orig_block_len = 0;
+                               split->ram_bytes = split->len;
+                       }
+
                        split->generation = gen;
                        split->bdev = em->bdev;
                        split->flags = flags;
@@ -620,8 +629,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split = split2;
                        split2 = NULL;
                }
-               if (em->block_start < EXTENT_MAP_LAST_BYTE &&
-                   testend && em->start + em->len > start + len) {
+               if (testend && em->start + em->len > start + len) {
                        u64 diff = start + len - em->start;
 
                        split->start = start + len;
@@ -630,18 +638,28 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
                        split->flags = flags;
                        split->compress_type = em->compress_type;
                        split->generation = gen;
-                       split->orig_block_len = max(em->block_len,
+
+                       if (em->block_start < EXTENT_MAP_LAST_BYTE) {
+                               split->orig_block_len = max(em->block_len,
                                                    em->orig_block_len);
-                       split->ram_bytes = em->ram_bytes;
 
-                       if (compressed) {
-                               split->block_len = em->block_len;
-                               split->block_start = em->block_start;
-                               split->orig_start = em->orig_start;
+                               split->ram_bytes = em->ram_bytes;
+                               if (compressed) {
+                                       split->block_len = em->block_len;
+                                       split->block_start = em->block_start;
+                                       split->orig_start = em->orig_start;
+                               } else {
+                                       split->block_len = split->len;
+                                       split->block_start = em->block_start
+                                               + diff;
+                                       split->orig_start = em->orig_start;
+                               }
                        } else {
-                               split->block_len = split->len;
-                               split->block_start = em->block_start + diff;
-                               split->orig_start = em->orig_start;
+                               split->ram_bytes = split->len;
+                               split->orig_start = split->start;
+                               split->block_len = 0;
+                               split->block_start = em->block_start;
+                               split->orig_block_len = 0;
                        }
 
                        ret = add_extent_mapping(em_tree, split, modified);
index 6d1b93c..021694c 100644 (file)
@@ -2166,16 +2166,23 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
                if (btrfs_file_extent_disk_bytenr(leaf, extent) != old->bytenr)
                        continue;
 
-               extent_offset = btrfs_file_extent_offset(leaf, extent);
-               if (key.offset - extent_offset != offset)
+               /*
+                * 'offset' refers to the exact key.offset,
+                * NOT the 'offset' field in btrfs_extent_data_ref, ie.
+                * (key.offset - extent_offset).
+                */
+               if (key.offset != offset)
                        continue;
 
+               extent_offset = btrfs_file_extent_offset(leaf, extent);
                num_bytes = btrfs_file_extent_num_bytes(leaf, extent);
+
                if (extent_offset >= old->extent_offset + old->offset +
                    old->len || extent_offset + num_bytes <=
                    old->extent_offset + old->offset)
                        continue;
 
+               ret = 0;
                break;
        }
 
@@ -2187,7 +2194,7 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
 
        backref->root_id = root_id;
        backref->inum = inum;
-       backref->file_pos = offset + extent_offset;
+       backref->file_pos = offset;
        backref->num_bytes = num_bytes;
        backref->extent_offset = extent_offset;
        backref->generation = btrfs_file_extent_generation(leaf, extent);
@@ -2210,7 +2217,8 @@ static noinline bool record_extent_backrefs(struct btrfs_path *path,
        new->path = path;
 
        list_for_each_entry_safe(old, tmp, &new->head, list) {
-               ret = iterate_inodes_from_logical(old->bytenr, fs_info,
+               ret = iterate_inodes_from_logical(old->bytenr +
+                                                 old->extent_offset, fs_info,
                                                  path, record_one_backref,
                                                  old);
                BUG_ON(ret < 0 && ret != -ENOENT);
@@ -4391,9 +4399,6 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
        int mask = attr->ia_valid;
        int ret;
 
-       if (newsize == oldsize)
-               return 0;
-
        /*
         * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a
         * special case where we need to update the times despite not having
@@ -5165,14 +5170,31 @@ next:
        }
 
        /* Reached end of directory/root. Bump pos past the last item. */
-       if (key_type == BTRFS_DIR_INDEX_KEY)
-               /*
-                * 32-bit glibc will use getdents64, but then strtol -
-                * so the last number we can serve is this.
-                */
-               ctx->pos = 0x7fffffff;
-       else
-               ctx->pos++;
+       ctx->pos++;
+
+       /*
+        * Stop new entries from being returned after we return the last
+        * entry.
+        *
+        * New directory entries are assigned a strictly increasing
+        * offset.  This means that new entries created during readdir
+        * are *guaranteed* to be seen in the future by that readdir.
+        * This has broken buggy programs which operate on names as
+        * they're returned by readdir.  Until we re-use freed offsets
+        * we have this hack to stop new entries from being returned
+        * under the assumption that they'll never reach this huge
+        * offset.
+        *
+        * This is being careful not to overflow 32bit loff_t unless the
+        * last entry requires it because doing so has broken 32bit apps
+        * in the past.
+        */
+       if (key_type == BTRFS_DIR_INDEX_KEY) {
+               if (ctx->pos >= INT_MAX)
+                       ctx->pos = LLONG_MAX;
+               else
+                       ctx->pos = INT_MAX;
+       }
 nopos:
        ret = 0;
 err:
index d58cce7..af1931a 100644 (file)
@@ -983,12 +983,12 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
  * a dirty root struct and adds it into the list of dead roots that need to
  * be deleted
  */
-int btrfs_add_dead_root(struct btrfs_root *root)
+void btrfs_add_dead_root(struct btrfs_root *root)
 {
        spin_lock(&root->fs_info->trans_lock);
-       list_add_tail(&root->root_list, &root->fs_info->dead_roots);
+       if (list_empty(&root->root_list))
+               list_add_tail(&root->root_list, &root->fs_info->dead_roots);
        spin_unlock(&root->fs_info->trans_lock);
-       return 0;
 }
 
 /*
@@ -1925,7 +1925,7 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
        }
        root = list_first_entry(&fs_info->dead_roots,
                        struct btrfs_root, root_list);
-       list_del(&root->root_list);
+       list_del_init(&root->root_list);
        spin_unlock(&fs_info->trans_lock);
 
        pr_debug("btrfs: cleaner removing %llu\n",
index 005b037..defbc42 100644 (file)
@@ -143,7 +143,7 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid);
 int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
                                     struct btrfs_root *root);
 
-int btrfs_add_dead_root(struct btrfs_root *root);
+void btrfs_add_dead_root(struct btrfs_root *root);
 int btrfs_defrag_root(struct btrfs_root *root);
 int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root);
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
index 2c67914..ff60d89 100644 (file)
@@ -3746,8 +3746,9 @@ next_slot:
        }
 
 log_extents:
+       btrfs_release_path(path);
+       btrfs_release_path(dst_path);
        if (fast_search) {
-               btrfs_release_path(dst_path);
                ret = btrfs_log_changed_extents(trans, root, inode, dst_path);
                if (ret) {
                        err = ret;
@@ -3764,8 +3765,6 @@ log_extents:
        }
 
        if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) {
-               btrfs_release_path(path);
-               btrfs_release_path(dst_path);
                ret = log_directory_changes(trans, root, inode, path, dst_path);
                if (ret) {
                        err = ret;
index 45e57cc..fc6f4f3 100644 (file)
@@ -43,17 +43,18 @@ cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
        server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
        if (IS_ERR(server->secmech.md5)) {
                cifs_dbg(VFS, "could not allocate crypto md5\n");
-               return PTR_ERR(server->secmech.md5);
+               rc = PTR_ERR(server->secmech.md5);
+               server->secmech.md5 = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
                        crypto_shash_descsize(server->secmech.md5);
        server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
        if (!server->secmech.sdescmd5) {
-               rc = -ENOMEM;
                crypto_free_shash(server->secmech.md5);
                server->secmech.md5 = NULL;
-               return rc;
+               return -ENOMEM;
        }
        server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
        server->secmech.sdescmd5->shash.flags = 0x0;
@@ -421,7 +422,7 @@ find_domain_name(struct cifs_ses *ses, const struct nls_table *nls_cp)
                if (blobptr + attrsize > blobend)
                        break;
                if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
-                       if (!attrsize)
+                       if (!attrsize || attrsize >= CIFS_MAX_DOMAINNAME_LEN)
                                break;
                        if (!ses->domainName) {
                                ses->domainName =
@@ -591,6 +592,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
 
 static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
 {
+       int rc;
        unsigned int size;
 
        /* check if already allocated */
@@ -600,7 +602,9 @@ static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
        server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
        if (IS_ERR(server->secmech.hmacmd5)) {
                cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
-               return PTR_ERR(server->secmech.hmacmd5);
+               rc = PTR_ERR(server->secmech.hmacmd5);
+               server->secmech.hmacmd5 = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
index 4bdd547..85ea98d 100644 (file)
@@ -147,18 +147,17 @@ cifs_read_super(struct super_block *sb)
                goto out_no_root;
        }
 
+       if (cifs_sb_master_tcon(cifs_sb)->nocase)
+               sb->s_d_op = &cifs_ci_dentry_ops;
+       else
+               sb->s_d_op = &cifs_dentry_ops;
+
        sb->s_root = d_make_root(inode);
        if (!sb->s_root) {
                rc = -ENOMEM;
                goto out_no_root;
        }
 
-       /* do that *after* d_make_root() - we want NULL ->d_op for root here */
-       if (cifs_sb_master_tcon(cifs_sb)->nocase)
-               sb->s_d_op = &cifs_ci_dentry_ops;
-       else
-               sb->s_d_op = &cifs_dentry_ops;
-
 #ifdef CONFIG_CIFS_NFSD_EXPORT
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                cifs_dbg(FYI, "export ops supported\n");
index 1fdc370..52ca861 100644 (file)
@@ -44,6 +44,7 @@
 #define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
 #define MAX_SERVER_SIZE 15
 #define MAX_SHARE_SIZE 80
+#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */
 #define MAX_USERNAME_SIZE 256  /* reasonable maximum for current servers */
 #define MAX_PASSWORD_SIZE 512  /* max for windows seems to be 256 wide chars */
 
@@ -369,6 +370,9 @@ struct smb_version_operations {
        void (*generate_signingkey)(struct TCP_Server_Info *server);
        int (*calc_signature)(struct smb_rqst *rqst,
                                   struct TCP_Server_Info *server);
+       int (*query_mf_symlink)(const unsigned char *path, char *pbuf,
+                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
+                       unsigned int xid);
 };
 
 struct smb_version_values {
index f7e584d..b29a012 100644 (file)
@@ -497,5 +497,7 @@ void cifs_writev_complete(struct work_struct *work);
 struct cifs_writedata *cifs_writedata_alloc(unsigned int nr_pages,
                                                work_func_t complete);
 void cifs_writedata_release(struct kref *refcount);
-
+int open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
+                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
+                       unsigned int xid);
 #endif                 /* _CIFSPROTO_H */
index fa68813..d67c550 100644 (file)
@@ -1675,7 +1675,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        if (string == NULL)
                                goto out_nomem;
 
-                       if (strnlen(string, 256) == 256) {
+                       if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
+                                       == CIFS_MAX_DOMAINNAME_LEN) {
                                printk(KERN_WARNING "CIFS: domain name too"
                                                    " long\n");
                                goto cifs_parse_mount_err;
@@ -2276,8 +2277,8 @@ cifs_put_smb_ses(struct cifs_ses *ses)
 
 #ifdef CONFIG_KEYS
 
-/* strlen("cifs:a:") + INET6_ADDRSTRLEN + 1 */
-#define CIFSCREDS_DESC_SIZE (7 + INET6_ADDRSTRLEN + 1)
+/* strlen("cifs:a:") + CIFS_MAX_DOMAINNAME_LEN + 1 */
+#define CIFSCREDS_DESC_SIZE (7 + CIFS_MAX_DOMAINNAME_LEN + 1)
 
 /* Populate username and pw fields from keyring if possible */
 static int
index 1e57f36..7e36ae3 100644 (file)
@@ -647,6 +647,7 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
                                     oflags, &oplock, &cfile->fid.netfid, xid);
                if (rc == 0) {
                        cifs_dbg(FYI, "posix reopen succeeded\n");
+                       oparms.reconnect = true;
                        goto reopen_success;
                }
                /*
index b83c3f5..562044f 100644 (file)
@@ -305,67 +305,89 @@ CIFSCouldBeMFSymlink(const struct cifs_fattr *fattr)
 }
 
 int
-CIFSCheckMFSymlink(struct cifs_fattr *fattr,
-                  const unsigned char *path,
-                  struct cifs_sb_info *cifs_sb, unsigned int xid)
+open_query_close_cifs_symlink(const unsigned char *path, char *pbuf,
+                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
+                       unsigned int xid)
 {
        int rc;
        int oplock = 0;
        __u16 netfid = 0;
        struct tcon_link *tlink;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *ptcon;
        struct cifs_io_parms io_parms;
-       u8 *buf;
-       char *pbuf;
-       unsigned int bytes_read = 0;
        int buf_type = CIFS_NO_BUFFER;
-       unsigned int link_len = 0;
        FILE_ALL_INFO file_info;
 
-       if (!CIFSCouldBeMFSymlink(fattr))
-               /* it's not a symlink */
-               return 0;
-
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
-       pTcon = tlink_tcon(tlink);
+       ptcon = tlink_tcon(tlink);
 
-       rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ,
+       rc = CIFSSMBOpen(xid, ptcon, path, FILE_OPEN, GENERIC_READ,
                         CREATE_NOT_DIR, &netfid, &oplock, &file_info,
                         cifs_sb->local_nls,
                         cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-       if (rc != 0)
-               goto out;
+       if (rc != 0) {
+               cifs_put_tlink(tlink);
+               return rc;
+       }
 
        if (file_info.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
-               CIFSSMBClose(xid, pTcon, netfid);
+               CIFSSMBClose(xid, ptcon, netfid);
+               cifs_put_tlink(tlink);
                /* it's not a symlink */
-               goto out;
+               return rc;
        }
 
-       buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
-       if (!buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
-       pbuf = buf;
        io_parms.netfid = netfid;
        io_parms.pid = current->tgid;
-       io_parms.tcon = pTcon;
+       io_parms.tcon = ptcon;
        io_parms.offset = 0;
        io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
 
-       rc = CIFSSMBRead(xid, &io_parms, &bytes_read, &pbuf, &buf_type);
-       CIFSSMBClose(xid, pTcon, netfid);
-       if (rc != 0) {
-               kfree(buf);
+       rc = CIFSSMBRead(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
+       CIFSSMBClose(xid, ptcon, netfid);
+       cifs_put_tlink(tlink);
+       return rc;
+}
+
+
+int
+CIFSCheckMFSymlink(struct cifs_fattr *fattr,
+                  const unsigned char *path,
+                  struct cifs_sb_info *cifs_sb, unsigned int xid)
+{
+       int rc = 0;
+       u8 *buf = NULL;
+       unsigned int link_len = 0;
+       unsigned int bytes_read = 0;
+       struct cifs_tcon *ptcon;
+
+       if (!CIFSCouldBeMFSymlink(fattr))
+               /* it's not a symlink */
+               return 0;
+
+       buf = kmalloc(CIFS_MF_SYMLINK_FILE_SIZE, GFP_KERNEL);
+       if (!buf) {
+               rc = -ENOMEM;
                goto out;
        }
 
+       ptcon = tlink_tcon(cifs_sb_tlink(cifs_sb));
+       if ((ptcon->ses) && (ptcon->ses->server->ops->query_mf_symlink))
+               rc = ptcon->ses->server->ops->query_mf_symlink(path, buf,
+                                                &bytes_read, cifs_sb, xid);
+       else
+               goto out;
+
+       if (rc != 0)
+               goto out;
+
+       if (bytes_read == 0) /* not a symlink */
+               goto out;
+
        rc = CIFSParseMFSymlink(buf, bytes_read, &link_len, NULL);
-       kfree(buf);
        if (rc == -EINVAL) {
                /* it's not a symlink */
                rc = 0;
@@ -381,7 +403,7 @@ CIFSCheckMFSymlink(struct cifs_fattr *fattr,
        fattr->cf_mode |= S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
        fattr->cf_dtype = DT_LNK;
 out:
-       cifs_put_tlink(tlink);
+       kfree(buf);
        return rc;
 }
 
index ab87784..69d2c82 100644 (file)
@@ -111,6 +111,14 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
                        return;
        }
 
+       /*
+        * If we know that the inode will need to be revalidated immediately,
+        * then don't create a new dentry for it. We'll end up doing an on
+        * the wire call either way and this spares us an invalidation.
+        */
+       if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
+               return;
+
        dentry = d_alloc(parent, name);
        if (!dentry)
                return;
index 79358e3..08dd37b 100644 (file)
@@ -197,7 +197,7 @@ static void unicode_domain_string(char **pbcc_area, struct cifs_ses *ses,
                bytes_ret = 0;
        } else
                bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->domainName,
-                                           256, nls_cp);
+                                           CIFS_MAX_DOMAINNAME_LEN, nls_cp);
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2;  /* account for null terminator */
 
@@ -255,8 +255,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
 
        /* copy domain */
        if (ses->domainName != NULL) {
-               strncpy(bcc_ptr, ses->domainName, 256);
-               bcc_ptr += strnlen(ses->domainName, 256);
+               strncpy(bcc_ptr, ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
+               bcc_ptr += strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LEN);
        } /* else we will send a null domain name
             so the server will default to its own domain */
        *bcc_ptr = 0;
index 6457690..6094397 100644 (file)
@@ -944,6 +944,7 @@ struct smb_version_operations smb1_operations = {
        .mand_lock = cifs_mand_lock,
        .mand_unlock_range = cifs_unlock_range,
        .push_mand_locks = cifs_push_mandatory_locks,
+       .query_mf_symlink = open_query_close_cifs_symlink,
 };
 
 struct smb_version_values smb1_values = {
index 301b191..4f2300d 100644 (file)
@@ -42,6 +42,7 @@
 static int
 smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
 {
+       int rc;
        unsigned int size;
 
        if (server->secmech.sdeschmacsha256 != NULL)
@@ -50,7 +51,9 @@ smb2_crypto_shash_allocate(struct TCP_Server_Info *server)
        server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
        if (IS_ERR(server->secmech.hmacsha256)) {
                cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
-               return PTR_ERR(server->secmech.hmacsha256);
+               rc = PTR_ERR(server->secmech.hmacsha256);
+               server->secmech.hmacsha256 = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
@@ -87,7 +90,9 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
                server->secmech.sdeschmacsha256 = NULL;
                crypto_free_shash(server->secmech.hmacsha256);
                server->secmech.hmacsha256 = NULL;
-               return PTR_ERR(server->secmech.cmacaes);
+               rc = PTR_ERR(server->secmech.cmacaes);
+               server->secmech.cmacaes = NULL;
+               return rc;
        }
 
        size = sizeof(struct shash_desc) +
index 4888cb3..c7c83ff 100644 (file)
@@ -533,8 +533,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove);
  */
 void debugfs_remove_recursive(struct dentry *dentry)
 {
-       struct dentry *child;
-       struct dentry *parent;
+       struct dentry *child, *next, *parent;
 
        if (IS_ERR_OR_NULL(dentry))
                return;
@@ -544,61 +543,37 @@ void debugfs_remove_recursive(struct dentry *dentry)
                return;
 
        parent = dentry;
+ down:
        mutex_lock(&parent->d_inode->i_mutex);
+       list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) {
+               if (!debugfs_positive(child))
+                       continue;
 
-       while (1) {
-               /*
-                * When all dentries under "parent" has been removed,
-                * walk up the tree until we reach our starting point.
-                */
-               if (list_empty(&parent->d_subdirs)) {
-                       mutex_unlock(&parent->d_inode->i_mutex);
-                       if (parent == dentry)
-                               break;
-                       parent = parent->d_parent;
-                       mutex_lock(&parent->d_inode->i_mutex);
-               }
-               child = list_entry(parent->d_subdirs.next, struct dentry,
-                               d_u.d_child);
- next_sibling:
-
-               /*
-                * If "child" isn't empty, walk down the tree and
-                * remove all its descendants first.
-                */
+               /* perhaps simple_empty(child) makes more sense */
                if (!list_empty(&child->d_subdirs)) {
                        mutex_unlock(&parent->d_inode->i_mutex);
                        parent = child;
-                       mutex_lock(&parent->d_inode->i_mutex);
-                       continue;
+                       goto down;
                }
-               __debugfs_remove(child, parent);
-               if (parent->d_subdirs.next == &child->d_u.d_child) {
-                       /*
-                        * Try the next sibling.
-                        */
-                       if (child->d_u.d_child.next != &parent->d_subdirs) {
-                               child = list_entry(child->d_u.d_child.next,
-                                                  struct dentry,
-                                                  d_u.d_child);
-                               goto next_sibling;
-                       }
-
-                       /*
-                        * Avoid infinite loop if we fail to remove
-                        * one dentry.
-                        */
-                       mutex_unlock(&parent->d_inode->i_mutex);
-                       break;
-               }
-               simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+ up:
+               if (!__debugfs_remove(child, parent))
+                       simple_release_fs(&debugfs_mount, &debugfs_mount_count);
        }
 
-       parent = dentry->d_parent;
+       mutex_unlock(&parent->d_inode->i_mutex);
+       child = parent;
+       parent = parent->d_parent;
        mutex_lock(&parent->d_inode->i_mutex);
-       __debugfs_remove(dentry, parent);
+
+       if (child != dentry) {
+               next = list_entry(child->d_u.d_child.next, struct dentry,
+                                       d_u.d_child);
+               goto up;
+       }
+
+       if (!__debugfs_remove(child, parent))
+               simple_release_fs(&debugfs_mount, &debugfs_mount_count);
        mutex_unlock(&parent->d_inode->i_mutex);
-       simple_release_fs(&debugfs_mount, &debugfs_mount_count);
 }
 EXPORT_SYMBOL_GPL(debugfs_remove_recursive);
 
index 911649a..8121491 100644 (file)
@@ -686,7 +686,6 @@ static int device_close(struct inode *inode, struct file *file)
           device_remove_lockspace() */
 
        sigprocmask(SIG_SETMASK, &tmpsig, NULL);
-       recalc_sigpending();
 
        return 0;
 }
index 9c73def..fd774c7 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -608,7 +608,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
                return -ENOMEM;
 
        lru_add_drain();
-       tlb_gather_mmu(&tlb, mm, 0);
+       tlb_gather_mmu(&tlb, mm, old_start, old_end);
        if (new_end > old_start) {
                /*
                 * when the old and new regions overlap clear from new_end.
@@ -625,7 +625,7 @@ static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift)
                free_pgd_range(&tlb, old_start, old_end, new_end,
                        vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING);
        }
-       tlb_finish_mmu(&tlb, new_end, old_end);
+       tlb_finish_mmu(&tlb, old_start, old_end);
 
        /*
         * Shrink the vma to just the new range.  Always succeeds.
index b577e45..0ab26fb 100644 (file)
@@ -2086,6 +2086,7 @@ extern int  ext4_sync_inode(handle_t *, struct inode *);
 extern void ext4_dirty_inode(struct inode *, int);
 extern int ext4_change_inode_journal_flag(struct inode *, int);
 extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
+extern int ext4_inode_attach_jinode(struct inode *inode);
 extern int ext4_can_truncate(struct inode *inode);
 extern void ext4_truncate(struct inode *);
 extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);
index 72a3600..17ac112 100644 (file)
@@ -255,10 +255,10 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
        set_buffer_prio(bh);
        if (ext4_handle_valid(handle)) {
                err = jbd2_journal_dirty_metadata(handle, bh);
-               if (err) {
-                       /* Errors can only happen if there is a bug */
-                       handle->h_err = err;
-                       __ext4_journal_stop(where, line, handle);
+               /* Errors can only happen if there is a bug */
+               if (WARN_ON_ONCE(err)) {
+                       ext4_journal_abort_handle(where, line, __func__, bh,
+                                                 handle, err);
                }
        } else {
                if (inode)
index a618738..72ba470 100644 (file)
@@ -4412,7 +4412,7 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode)
 retry:
        err = ext4_es_remove_extent(inode, last_block,
                                    EXT_MAX_BLOCKS - last_block);
-       if (err == ENOMEM) {
+       if (err == -ENOMEM) {
                cond_resched();
                congestion_wait(BLK_RW_ASYNC, HZ/50);
                goto retry;
index 6f4cc56..319c9d2 100644 (file)
@@ -219,7 +219,6 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
 {
        struct super_block *sb = inode->i_sb;
        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
-       struct ext4_inode_info *ei = EXT4_I(inode);
        struct vfsmount *mnt = filp->f_path.mnt;
        struct path path;
        char buf[64], *cp;
@@ -259,22 +258,10 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
         * Set up the jbd2_inode if we are opening the inode for
         * writing and the journal is present
         */
-       if (sbi->s_journal && !ei->jinode && (filp->f_mode & FMODE_WRITE)) {
-               struct jbd2_inode *jinode = jbd2_alloc_inode(GFP_KERNEL);
-
-               spin_lock(&inode->i_lock);
-               if (!ei->jinode) {
-                       if (!jinode) {
-                               spin_unlock(&inode->i_lock);
-                               return -ENOMEM;
-                       }
-                       ei->jinode = jinode;
-                       jbd2_journal_init_jbd_inode(ei->jinode, inode);
-                       jinode = NULL;
-               }
-               spin_unlock(&inode->i_lock);
-               if (unlikely(jinode != NULL))
-                       jbd2_free_inode(jinode);
+       if (filp->f_mode & FMODE_WRITE) {
+               int ret = ext4_inode_attach_jinode(inode);
+               if (ret < 0)
+                       return ret;
        }
        return dquot_file_open(inode, filp);
 }
index f03598c..8bf5999 100644 (file)
@@ -734,11 +734,8 @@ repeat_in_this_group:
                ino = ext4_find_next_zero_bit((unsigned long *)
                                              inode_bitmap_bh->b_data,
                                              EXT4_INODES_PER_GROUP(sb), ino);
-               if (ino >= EXT4_INODES_PER_GROUP(sb)) {
-                       if (++group == ngroups)
-                               group = 0;
-                       continue;
-               }
+               if (ino >= EXT4_INODES_PER_GROUP(sb))
+                       goto next_group;
                if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) {
                        ext4_error(sb, "reserved inode found cleared - "
                                   "inode=%lu", ino + 1);
@@ -769,6 +766,9 @@ repeat_in_this_group:
                        goto got; /* we grabbed the inode! */
                if (ino < EXT4_INODES_PER_GROUP(sb))
                        goto repeat_in_this_group;
+next_group:
+               if (++group == ngroups)
+                       group = 0;
        }
        err = -ENOSPC;
        goto out;
index ba33c67..c2ca04e 100644 (file)
@@ -555,14 +555,13 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
                int ret;
                unsigned long long status;
 
-#ifdef ES_AGGRESSIVE_TEST
-               if (retval != map->m_len) {
-                       printk("ES len assertion failed for inode: %lu "
-                              "retval %d != map->m_len %d "
-                              "in %s (lookup)\n", inode->i_ino, retval,
-                              map->m_len, __func__);
+               if (unlikely(retval != map->m_len)) {
+                       ext4_warning(inode->i_sb,
+                                    "ES len assertion failed for inode "
+                                    "%lu: retval %d != map->m_len %d",
+                                    inode->i_ino, retval, map->m_len);
+                       WARN_ON(1);
                }
-#endif
 
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
@@ -656,14 +655,13 @@ found:
                int ret;
                unsigned long long status;
 
-#ifdef ES_AGGRESSIVE_TEST
-               if (retval != map->m_len) {
-                       printk("ES len assertion failed for inode: %lu "
-                              "retval %d != map->m_len %d "
-                              "in %s (allocation)\n", inode->i_ino, retval,
-                              map->m_len, __func__);
+               if (unlikely(retval != map->m_len)) {
+                       ext4_warning(inode->i_sb,
+                                    "ES len assertion failed for inode "
+                                    "%lu: retval %d != map->m_len %d",
+                                    inode->i_ino, retval, map->m_len);
+                       WARN_ON(1);
                }
-#endif
 
                /*
                 * If the extent has been zeroed out, we don't need to update
@@ -1637,14 +1635,13 @@ add_delayed:
                int ret;
                unsigned long long status;
 
-#ifdef ES_AGGRESSIVE_TEST
-               if (retval != map->m_len) {
-                       printk("ES len assertion failed for inode: %lu "
-                              "retval %d != map->m_len %d "
-                              "in %s (lookup)\n", inode->i_ino, retval,
-                              map->m_len, __func__);
+               if (unlikely(retval != map->m_len)) {
+                       ext4_warning(inode->i_sb,
+                                    "ES len assertion failed for inode "
+                                    "%lu: retval %d != map->m_len %d",
+                                    inode->i_ino, retval, map->m_len);
+                       WARN_ON(1);
                }
-#endif
 
                status = map->m_flags & EXT4_MAP_UNWRITTEN ?
                                EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
@@ -3536,6 +3533,18 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
                   offset;
        }
 
+       if (offset & (sb->s_blocksize - 1) ||
+           (offset + length) & (sb->s_blocksize - 1)) {
+               /*
+                * Attach jinode to inode for jbd2 if we do any zeroing of
+                * partial block
+                */
+               ret = ext4_inode_attach_jinode(inode);
+               if (ret < 0)
+                       goto out_mutex;
+
+       }
+
        first_block_offset = round_up(offset, sb->s_blocksize);
        last_block_offset = round_down((offset + length), sb->s_blocksize) - 1;
 
@@ -3604,6 +3613,31 @@ out_mutex:
        return ret;
 }
 
+int ext4_inode_attach_jinode(struct inode *inode)
+{
+       struct ext4_inode_info *ei = EXT4_I(inode);
+       struct jbd2_inode *jinode;
+
+       if (ei->jinode || !EXT4_SB(inode->i_sb)->s_journal)
+               return 0;
+
+       jinode = jbd2_alloc_inode(GFP_KERNEL);
+       spin_lock(&inode->i_lock);
+       if (!ei->jinode) {
+               if (!jinode) {
+                       spin_unlock(&inode->i_lock);
+                       return -ENOMEM;
+               }
+               ei->jinode = jinode;
+               jbd2_journal_init_jbd_inode(ei->jinode, inode);
+               jinode = NULL;
+       }
+       spin_unlock(&inode->i_lock);
+       if (unlikely(jinode != NULL))
+               jbd2_free_inode(jinode);
+       return 0;
+}
+
 /*
  * ext4_truncate()
  *
@@ -3664,6 +3698,12 @@ void ext4_truncate(struct inode *inode)
                        return;
        }
 
+       /* If we zero-out tail of the page, we have to create jinode for jbd2 */
+       if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
+               if (ext4_inode_attach_jinode(inode) < 0)
+                       return;
+       }
+
        if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
                credits = ext4_writepage_trans_blocks(inode);
        else
index 9491ac0..c0427e2 100644 (file)
@@ -77,8 +77,10 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
        memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data));
        memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags));
        memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize));
-       memswap(&ei1->i_es_tree, &ei2->i_es_tree, sizeof(ei1->i_es_tree));
-       memswap(&ei1->i_es_lru_nr, &ei2->i_es_lru_nr, sizeof(ei1->i_es_lru_nr));
+       ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS);
+       ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS);
+       ext4_es_lru_del(inode1);
+       ext4_es_lru_del(inode2);
 
        isize = i_size_read(inode1);
        i_size_write(inode1, i_size_read(inode2));
index bca26f3..b59373b 100644 (file)
@@ -1359,7 +1359,7 @@ static const struct mount_opts {
        {Opt_delalloc, EXT4_MOUNT_DELALLOC,
         MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
        {Opt_nodelalloc, EXT4_MOUNT_DELALLOC,
-        MOPT_EXT4_ONLY | MOPT_CLEAR | MOPT_EXPLICIT},
+        MOPT_EXT4_ONLY | MOPT_CLEAR},
        {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
         MOPT_EXT4_ONLY | MOPT_SET},
        {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
@@ -3483,7 +3483,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
                if (test_opt(sb, DIOREAD_NOLOCK)) {
                        ext4_msg(sb, KERN_ERR, "can't mount with "
-                                "both data=journal and delalloc");
+                                "both data=journal and dioread_nolock");
                        goto failed_mount;
                }
                if (test_opt(sb, DELALLOC))
@@ -4727,6 +4727,21 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                goto restore_opts;
        }
 
+       if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) {
+               if (test_opt2(sb, EXPLICIT_DELALLOC)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "both data=journal and delalloc");
+                       err = -EINVAL;
+                       goto restore_opts;
+               }
+               if (test_opt(sb, DIOREAD_NOLOCK)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "both data=journal and dioread_nolock");
+                       err = -EINVAL;
+                       goto restore_opts;
+               }
+       }
+
        if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
                ext4_abort(sb, "Abort forced by user");
 
@@ -5481,6 +5496,7 @@ static void __exit ext4_exit_fs(void)
        kset_unregister(ext4_kset);
        ext4_exit_system_zone();
        ext4_exit_pageio();
+       ext4_exit_es();
 }
 
 MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
index 6599222..65343c3 100644 (file)
@@ -730,14 +730,14 @@ static int __init fcntl_init(void)
         * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
         * is defined as O_NONBLOCK on some platforms and not on others.
         */
-       BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
+       BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
                O_RDONLY        | O_WRONLY      | O_RDWR        |
                O_CREAT         | O_EXCL        | O_NOCTTY      |
                O_TRUNC         | O_APPEND      | /* O_NONBLOCK | */
                __O_SYNC        | O_DSYNC       | FASYNC        |
                O_DIRECT        | O_LARGEFILE   | O_DIRECTORY   |
                O_NOFOLLOW      | O_NOATIME     | O_CLOEXEC     |
-               __FMODE_EXEC    | O_PATH
+               __FMODE_EXEC    | O_PATH        | __O_TMPFILE
                ));
 
        fasync_cache = kmem_cache_create("fasync_cache",
index a3f868a..3442397 100644 (file)
@@ -463,6 +463,14 @@ static struct inode *hugetlbfs_get_root(struct super_block *sb,
        return inode;
 }
 
+/*
+ * Hugetlbfs is not reclaimable; therefore its i_mmap_mutex will never
+ * be taken from reclaim -- unlike regular filesystems. This needs an
+ * annotation because huge_pmd_share() does an allocation under
+ * i_mmap_mutex.
+ */
+struct lock_class_key hugetlbfs_i_mmap_mutex_key;
+
 static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                                        struct inode *dir,
                                        umode_t mode, dev_t dev)
@@ -474,6 +482,8 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
                struct hugetlbfs_inode_info *info;
                inode->i_ino = get_next_ino();
                inode_init_owner(inode, dir, mode);
+               lockdep_set_class(&inode->i_mapping->i_mmap_mutex,
+                               &hugetlbfs_i_mmap_mutex_key);
                inode->i_mapping->a_ops = &hugetlbfs_aops;
                inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
                inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
index 01bfe76..41e491b 100644 (file)
@@ -64,12 +64,17 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
                                   nlm_init->protocol, nlm_version,
                                   nlm_init->hostname, nlm_init->noresvport,
                                   nlm_init->net);
-       if (host == NULL) {
-               lockd_down(nlm_init->net);
-               return ERR_PTR(-ENOLCK);
-       }
+       if (host == NULL)
+               goto out_nohost;
+       if (host->h_rpcclnt == NULL && nlm_bind_host(host) == NULL)
+               goto out_nobind;
 
        return host;
+out_nobind:
+       nlmclnt_release_host(host);
+out_nohost:
+       lockd_down(nlm_init->net);
+       return ERR_PTR(-ENOLCK);
 }
 EXPORT_SYMBOL_GPL(nlmclnt_init);
 
index 9760ecb..acd3947 100644 (file)
@@ -125,14 +125,15 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
 {
        struct nlm_args *argp = &req->a_args;
        struct nlm_lock *lock = &argp->lock;
+       char *nodename = req->a_host->h_rpcclnt->cl_nodename;
 
        nlmclnt_next_cookie(&argp->cookie);
        memcpy(&lock->fh, NFS_FH(file_inode(fl->fl_file)), sizeof(struct nfs_fh));
-       lock->caller  = utsname()->nodename;
+       lock->caller  = nodename;
        lock->oh.data = req->a_owner;
        lock->oh.len  = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
                                (unsigned int)fl->fl_u.nfs_fl.owner->pid,
-                               utsname()->nodename);
+                               nodename);
        lock->svid = fl->fl_u.nfs_fl.owner->pid;
        lock->fl.fl_start = fl->fl_start;
        lock->fl.fl_end = fl->fl_end;
index 8b61d10..89a612e 100644 (file)
@@ -3671,15 +3671,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
        if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
                return -EINVAL;
        /*
-        * To use null names we require CAP_DAC_READ_SEARCH
-        * This ensures that not everyone will be able to create
-        * handlink using the passed filedescriptor.
+        * Using empty names is equivalent to using AT_SYMLINK_FOLLOW
+        * on /proc/self/fd/<fd>.
         */
-       if (flags & AT_EMPTY_PATH) {
-               if (!capable(CAP_DAC_READ_SEARCH))
-                       return -ENOENT;
+       if (flags & AT_EMPTY_PATH)
                how = LOOKUP_EMPTY;
-       }
 
        if (flags & AT_SYMLINK_FOLLOW)
                how |= LOOKUP_FOLLOW;
index af6e806..941246f 100644 (file)
@@ -463,7 +463,6 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
-               nfs_setsecurity(inode, fattr, label);
        dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
                (long long)NFS_FILEID(inode),
@@ -963,9 +962,15 @@ EXPORT_SYMBOL_GPL(nfs_revalidate_inode);
 static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
-       
+       int ret;
+
        if (mapping->nrpages != 0) {
-               int ret = invalidate_inode_pages2(mapping);
+               if (S_ISREG(inode->i_mode)) {
+                       ret = nfs_sync_mapping(mapping);
+                       if (ret < 0)
+                               return ret;
+               }
+               ret = invalidate_inode_pages2(mapping);
                if (ret < 0)
                        return ret;
        }
index cf11799..108a774 100644 (file)
@@ -3071,15 +3071,13 @@ struct rpc_clnt *
 nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
                            struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+       struct rpc_clnt *client = NFS_CLIENT(dir);
        int status;
-       struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
 
        status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
-       if (status < 0) {
-               rpc_shutdown_client(client);
+       if (status < 0)
                return ERR_PTR(status);
-       }
-       return client;
+       return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
 }
 
 static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
index 71fdc0d..f6db66d 100644 (file)
@@ -2478,6 +2478,10 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
        if (server->flags & NFS_MOUNT_NOAC)
                sb_mntdata.mntflags |= MS_SYNCHRONOUS;
 
+       if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
+               if (mount_info->cloned->sb->s_flags & MS_SYNCHRONOUS)
+                       sb_mntdata.mntflags |= MS_SYNCHRONOUS;
+
        /* Get a superblock - note that we may end up sharing one that already exists */
        s = sget(nfs_mod->nfs_fs, compare_super, nfs_set_super, flags, &sb_mntdata);
        if (IS_ERR(s)) {
index 0d4c410..419572f 100644 (file)
@@ -1524,7 +1524,7 @@ static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
        return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\
-               1 + 1 + 0 + /* eir_flags, spr_how, SP4_NONE (for now) */\
+               1 + 1 + 2 + /* eir_flags, spr_how, spo_must_enforce & _allow */\
                2 + /*eir_server_owner.so_minor_id */\
                /* eir_server_owner.so_major_id<> */\
                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
index 280acef..43f4229 100644 (file)
@@ -1264,6 +1264,8 @@ static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
        struct svc_cred *cr = &rqstp->rq_cred;
        u32 service;
 
+       if (!cr->cr_gss_mech)
+               return false;
        service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor);
        return service == RPC_GSS_SVC_INTEGRITY ||
               service == RPC_GSS_SVC_PRIVACY;
index 0c0f3ea..c2a4701 100644 (file)
@@ -3360,7 +3360,8 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
                8 /* eir_clientid */ +
                4 /* eir_sequenceid */ +
                4 /* eir_flags */ +
-               4 /* spr_how (SP4_NONE) */ +
+               4 /* spr_how */ +
+               8 /* spo_must_enforce, spo_must_allow */ +
                8 /* so_minor_id */ +
                4 /* so_major_id.len */ +
                (XDR_QUADLEN(major_id_sz) * 4) +
@@ -3372,8 +3373,6 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
        WRITE32(exid->seqid);
        WRITE32(exid->flags);
 
-       /* state_protect4_r. Currently only support SP4_NONE */
-       BUG_ON(exid->spa_how != SP4_NONE);
        WRITE32(exid->spa_how);
        switch (exid->spa_how) {
        case SP4_NONE:
index 79736a2..2abf97b 100644 (file)
@@ -1757,7 +1757,7 @@ try_again:
                goto out;
        } else if (ret == 1) {
                clusters_need = wc->w_clen;
-               ret = ocfs2_refcount_cow(inode, filp, di_bh,
+               ret = ocfs2_refcount_cow(inode, di_bh,
                                         wc->w_cpos, wc->w_clen, UINT_MAX);
                if (ret) {
                        mlog_errno(ret);
index eb760d8..30544ce 100644 (file)
@@ -2153,11 +2153,9 @@ int ocfs2_empty_dir(struct inode *inode)
 {
        int ret;
        struct ocfs2_empty_dir_priv priv = {
-               .ctx.actor = ocfs2_empty_dir_filldir
+               .ctx.actor = ocfs2_empty_dir_filldir,
        };
 
-       memset(&priv, 0, sizeof(priv));
-
        if (ocfs2_dir_indexed(inode)) {
                ret = ocfs2_empty_dir_dx(inode, &priv);
                if (ret)
index 41000f2..3261d71 100644 (file)
@@ -370,7 +370,7 @@ static int ocfs2_cow_file_pos(struct inode *inode,
        if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
                goto out;
 
-       return ocfs2_refcount_cow(inode, NULL, fe_bh, cpos, 1, cpos+1);
+       return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
 
 out:
        return status;
@@ -899,7 +899,7 @@ static int ocfs2_zero_extend_get_range(struct inode *inode,
                zero_clusters = last_cpos - zero_cpos;
 
        if (needs_cow) {
-               rc = ocfs2_refcount_cow(inode, NULL, di_bh, zero_cpos,
+               rc = ocfs2_refcount_cow(inode, di_bh, zero_cpos,
                                        zero_clusters, UINT_MAX);
                if (rc) {
                        mlog_errno(rc);
@@ -2078,7 +2078,7 @@ static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
 
        *meta_level = 1;
 
-       ret = ocfs2_refcount_cow(inode, file, di_bh, cpos, clusters, UINT_MAX);
+       ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
        if (ret)
                mlog_errno(ret);
 out:
index 96f9ac2..0a99273 100644 (file)
@@ -537,7 +537,7 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,
        extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth);
 
        return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks +
-              ocfs2_quota_trans_credits(sb) + bits_wanted;
+              ocfs2_quota_trans_credits(sb);
 }
 
 static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
index f1fc172..452068b 100644 (file)
@@ -69,7 +69,7 @@ static int __ocfs2_move_extent(handle_t *handle,
        u64 ino = ocfs2_metadata_cache_owner(context->et.et_ci);
        u64 old_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cpos);
 
-       ret = ocfs2_duplicate_clusters_by_page(handle, context->file, cpos,
+       ret = ocfs2_duplicate_clusters_by_page(handle, inode, cpos,
                                               p_cpos, new_p_cpos, len);
        if (ret) {
                mlog_errno(ret);
index 998b17e..a70d604 100644 (file)
@@ -49,7 +49,6 @@
 
 struct ocfs2_cow_context {
        struct inode *inode;
-       struct file *file;
        u32 cow_start;
        u32 cow_len;
        struct ocfs2_extent_tree data_et;
@@ -66,7 +65,7 @@ struct ocfs2_cow_context {
                            u32 *num_clusters,
                            unsigned int *extent_flags);
        int (*cow_duplicate_clusters)(handle_t *handle,
-                                     struct file *file,
+                                     struct inode *inode,
                                      u32 cpos, u32 old_cluster,
                                      u32 new_cluster, u32 new_len);
 };
@@ -2922,14 +2921,12 @@ static int ocfs2_clear_cow_buffer(handle_t *handle, struct buffer_head *bh)
 }
 
 int ocfs2_duplicate_clusters_by_page(handle_t *handle,
-                                    struct file *file,
+                                    struct inode *inode,
                                     u32 cpos, u32 old_cluster,
                                     u32 new_cluster, u32 new_len)
 {
        int ret = 0, partial;
-       struct inode *inode = file_inode(file);
-       struct ocfs2_caching_info *ci = INODE_CACHE(inode);
-       struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
+       struct super_block *sb = inode->i_sb;
        u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
        struct page *page;
        pgoff_t page_index;
@@ -2965,6 +2962,11 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                        to = map_end & (PAGE_CACHE_SIZE - 1);
 
                page = find_or_create_page(mapping, page_index, GFP_NOFS);
+               if (!page) {
+                       ret = -ENOMEM;
+                       mlog_errno(ret);
+                       break;
+               }
 
                /*
                 * In case PAGE_CACHE_SIZE <= CLUSTER_SIZE, This page
@@ -2973,13 +2975,6 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
                        BUG_ON(PageDirty(page));
 
-               if (PageReadahead(page)) {
-                       page_cache_async_readahead(mapping,
-                                                  &file->f_ra, file,
-                                                  page, page_index,
-                                                  readahead_pages);
-               }
-
                if (!PageUptodate(page)) {
                        ret = block_read_full_page(page, ocfs2_get_block);
                        if (ret) {
@@ -2999,7 +2994,8 @@ int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                        }
                }
 
-               ocfs2_map_and_dirty_page(inode, handle, from, to,
+               ocfs2_map_and_dirty_page(inode,
+                                        handle, from, to,
                                         page, 0, &new_block);
                mark_page_accessed(page);
 unlock:
@@ -3015,12 +3011,11 @@ unlock:
 }
 
 int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
-                                   struct file *file,
+                                   struct inode *inode,
                                    u32 cpos, u32 old_cluster,
                                    u32 new_cluster, u32 new_len)
 {
        int ret = 0;
-       struct inode *inode = file_inode(file);
        struct super_block *sb = inode->i_sb;
        struct ocfs2_caching_info *ci = INODE_CACHE(inode);
        int i, blocks = ocfs2_clusters_to_blocks(sb, new_len);
@@ -3145,7 +3140,7 @@ static int ocfs2_replace_clusters(handle_t *handle,
 
        /*If the old clusters is unwritten, no need to duplicate. */
        if (!(ext_flags & OCFS2_EXT_UNWRITTEN)) {
-               ret = context->cow_duplicate_clusters(handle, context->file,
+               ret = context->cow_duplicate_clusters(handle, context->inode,
                                                      cpos, old, new, len);
                if (ret) {
                        mlog_errno(ret);
@@ -3423,35 +3418,12 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context)
        return ret;
 }
 
-static void ocfs2_readahead_for_cow(struct inode *inode,
-                                   struct file *file,
-                                   u32 start, u32 len)
-{
-       struct address_space *mapping;
-       pgoff_t index;
-       unsigned long num_pages;
-       int cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits;
-
-       if (!file)
-               return;
-
-       mapping = file->f_mapping;
-       num_pages = (len << cs_bits) >> PAGE_CACHE_SHIFT;
-       if (!num_pages)
-               num_pages = 1;
-
-       index = ((loff_t)start << cs_bits) >> PAGE_CACHE_SHIFT;
-       page_cache_sync_readahead(mapping, &file->f_ra, file,
-                                 index, num_pages);
-}
-
 /*
  * Starting at cpos, try to CoW write_len clusters.  Don't CoW
  * past max_cpos.  This will stop when it runs into a hole or an
  * unrefcounted extent.
  */
 static int ocfs2_refcount_cow_hunk(struct inode *inode,
-                                  struct file *file,
                                   struct buffer_head *di_bh,
                                   u32 cpos, u32 write_len, u32 max_cpos)
 {
@@ -3480,8 +3452,6 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
 
        BUG_ON(cow_len == 0);
 
-       ocfs2_readahead_for_cow(inode, file, cow_start, cow_len);
-
        context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
        if (!context) {
                ret = -ENOMEM;
@@ -3503,7 +3473,6 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
        context->ref_root_bh = ref_root_bh;
        context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
        context->get_clusters = ocfs2_di_get_clusters;
-       context->file = file;
 
        ocfs2_init_dinode_extent_tree(&context->data_et,
                                      INODE_CACHE(inode), di_bh);
@@ -3532,7 +3501,6 @@ out:
  * clusters between cpos and cpos+write_len are safe to modify.
  */
 int ocfs2_refcount_cow(struct inode *inode,
-                      struct file *file,
                       struct buffer_head *di_bh,
                       u32 cpos, u32 write_len, u32 max_cpos)
 {
@@ -3552,7 +3520,7 @@ int ocfs2_refcount_cow(struct inode *inode,
                        num_clusters = write_len;
 
                if (ext_flags & OCFS2_EXT_REFCOUNTED) {
-                       ret = ocfs2_refcount_cow_hunk(inode, file, di_bh, cpos,
+                       ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos,
                                                      num_clusters, max_cpos);
                        if (ret) {
                                mlog_errno(ret);
index 7754608..6422bbc 100644 (file)
@@ -53,7 +53,7 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
                                          int *credits,
                                          int *ref_blocks);
 int ocfs2_refcount_cow(struct inode *inode,
-                      struct file *filep, struct buffer_head *di_bh,
+                      struct buffer_head *di_bh,
                       u32 cpos, u32 write_len, u32 max_cpos);
 
 typedef int (ocfs2_post_refcount_func)(struct inode *inode,
@@ -85,11 +85,11 @@ int ocfs2_refcount_cow_xattr(struct inode *inode,
                             u32 cpos, u32 write_len,
                             struct ocfs2_post_refcount *post);
 int ocfs2_duplicate_clusters_by_page(handle_t *handle,
-                                    struct file *file,
+                                    struct inode *inode,
                                     u32 cpos, u32 old_cluster,
                                     u32 new_cluster, u32 new_len);
 int ocfs2_duplicate_clusters_by_jbd(handle_t *handle,
-                                   struct file *file,
+                                   struct inode *inode,
                                    u32 cpos, u32 old_cluster,
                                    u32 new_cluster, u32 new_len);
 int ocfs2_cow_sync_writeback(struct super_block *sb,
index d53e298..7931f76 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -823,7 +823,7 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
        int lookup_flags = 0;
        int acc_mode;
 
-       if (flags & O_CREAT)
+       if (flags & (O_CREAT | __O_TMPFILE))
                op->mode = (mode & S_IALLUGO) | S_IFREG;
        else
                op->mode = 0;
index dbf61f6..107d026 100644 (file)
@@ -730,8 +730,16 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma,
         * of how soft-dirty works.
         */
        pte_t ptent = *pte;
-       ptent = pte_wrprotect(ptent);
-       ptent = pte_clear_flags(ptent, _PAGE_SOFT_DIRTY);
+
+       if (pte_present(ptent)) {
+               ptent = pte_wrprotect(ptent);
+               ptent = pte_clear_flags(ptent, _PAGE_SOFT_DIRTY);
+       } else if (is_swap_pte(ptent)) {
+               ptent = pte_swp_clear_soft_dirty(ptent);
+       } else if (pte_file(ptent)) {
+               ptent = pte_file_clear_soft_dirty(ptent);
+       }
+
        set_pte_at(vma->vm_mm, addr, pte, ptent);
 #endif
 }
@@ -752,14 +760,15 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        for (; addr != end; pte++, addr += PAGE_SIZE) {
                ptent = *pte;
-               if (!pte_present(ptent))
-                       continue;
 
                if (cp->type == CLEAR_REFS_SOFT_DIRTY) {
                        clear_soft_dirty(vma, addr, pte);
                        continue;
                }
 
+               if (!pte_present(ptent))
+                       continue;
+
                page = vm_normal_page(vma, addr, ptent);
                if (!page)
                        continue;
@@ -859,7 +868,7 @@ typedef struct {
 } pagemap_entry_t;
 
 struct pagemapread {
-       int pos, len;
+       int pos, len;           /* units: PM_ENTRY_BYTES, not bytes */
        pagemap_entry_t *buffer;
        bool v2;
 };
@@ -867,7 +876,7 @@ struct pagemapread {
 #define PAGEMAP_WALK_SIZE      (PMD_SIZE)
 #define PAGEMAP_WALK_MASK      (PMD_MASK)
 
-#define PM_ENTRY_BYTES      sizeof(u64)
+#define PM_ENTRY_BYTES      sizeof(pagemap_entry_t)
 #define PM_STATUS_BITS      3
 #define PM_STATUS_OFFSET    (64 - PM_STATUS_BITS)
 #define PM_STATUS_MASK      (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
@@ -930,8 +939,10 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
                flags = PM_PRESENT;
                page = vm_normal_page(vma, addr, pte);
        } else if (is_swap_pte(pte)) {
-               swp_entry_t entry = pte_to_swp_entry(pte);
-
+               swp_entry_t entry;
+               if (pte_swp_soft_dirty(pte))
+                       flags2 |= __PM_SOFT_DIRTY;
+               entry = pte_to_swp_entry(pte);
                frame = swp_type(entry) |
                        (swp_offset(entry) << MAX_SWAPFILES_SHIFT);
                flags = PM_SWAP;
@@ -1116,8 +1127,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
                goto out_task;
 
        pm.v2 = soft_dirty_cleared;
-       pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
-       pm.buffer = kmalloc(pm.len, GFP_TEMPORARY);
+       pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT);
+       pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY);
        ret = -ENOMEM;
        if (!pm.buffer)
                goto out_task;
index 33532f7..a958444 100644 (file)
 /*
  * LOCKING:
  *
- * We rely on new Alexander Viro's super-block locking.
+ * These guys are evicted from procfs as the very first step in ->kill_sb().
  *
  */
 
-static int show_version(struct seq_file *m, struct super_block *sb)
+static int show_version(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        char *format;
 
        if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6)) {
@@ -66,8 +67,9 @@ static int show_version(struct seq_file *m, struct super_block *sb)
 #define DJP( x ) le32_to_cpu( jp -> x )
 #define JF( x ) ( r -> s_journal -> x )
 
-static int show_super(struct seq_file *m, struct super_block *sb)
+static int show_super(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
 
        seq_printf(m, "state: \t%s\n"
@@ -128,8 +130,9 @@ static int show_super(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_per_level(struct seq_file *m, struct super_block *sb)
+static int show_per_level(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
        int level;
 
@@ -186,8 +189,9 @@ static int show_per_level(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_bitmap(struct seq_file *m, struct super_block *sb)
+static int show_bitmap(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
 
        seq_printf(m, "free_block: %lu\n"
@@ -218,8 +222,9 @@ static int show_bitmap(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
+static int show_on_disk_super(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
        struct reiserfs_super_block *rs = sb_info->s_rs;
        int hash_code = DFL(s_hash_function_code);
@@ -261,8 +266,9 @@ static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_oidmap(struct seq_file *m, struct super_block *sb)
+static int show_oidmap(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
        struct reiserfs_super_block *rs = sb_info->s_rs;
        unsigned int mapsize = le16_to_cpu(rs->s_v1.s_oid_cursize);
@@ -291,8 +297,9 @@ static int show_oidmap(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-static int show_journal(struct seq_file *m, struct super_block *sb)
+static int show_journal(struct seq_file *m, void *unused)
 {
+       struct super_block *sb = m->private;
        struct reiserfs_sb_info *r = REISERFS_SB(sb);
        struct reiserfs_super_block *rs = r->s_rs;
        struct journal_params *jp = &rs->s_v1.s_journal;
@@ -383,92 +390,24 @@ static int show_journal(struct seq_file *m, struct super_block *sb)
        return 0;
 }
 
-/* iterator */
-static int test_sb(struct super_block *sb, void *data)
-{
-       return data == sb;
-}
-
-static int set_sb(struct super_block *sb, void *data)
-{
-       return -ENOENT;
-}
-
-struct reiserfs_seq_private {
-       struct super_block *sb;
-       int (*show) (struct seq_file *, struct super_block *);
-};
-
-static void *r_start(struct seq_file *m, loff_t * pos)
-{
-       struct reiserfs_seq_private *priv = m->private;
-       loff_t l = *pos;
-
-       if (l)
-               return NULL;
-
-       if (IS_ERR(sget(&reiserfs_fs_type, test_sb, set_sb, 0, priv->sb)))
-               return NULL;
-
-       up_write(&priv->sb->s_umount);
-       return priv->sb;
-}
-
-static void *r_next(struct seq_file *m, void *v, loff_t * pos)
-{
-       ++*pos;
-       if (v)
-               deactivate_super(v);
-       return NULL;
-}
-
-static void r_stop(struct seq_file *m, void *v)
-{
-       if (v)
-               deactivate_super(v);
-}
-
-static int r_show(struct seq_file *m, void *v)
-{
-       struct reiserfs_seq_private *priv = m->private;
-       return priv->show(m, v);
-}
-
-static const struct seq_operations r_ops = {
-       .start = r_start,
-       .next = r_next,
-       .stop = r_stop,
-       .show = r_show,
-};
-
 static int r_open(struct inode *inode, struct file *file)
 {
-       struct reiserfs_seq_private *priv;
-       int ret = seq_open_private(file, &r_ops,
-                                  sizeof(struct reiserfs_seq_private));
-
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               priv = m->private;
-               priv->sb = proc_get_parent_data(inode);
-               priv->show = PDE_DATA(inode);
-       }
-       return ret;
+       return single_open(file, PDE_DATA(inode), 
+                               proc_get_parent_data(inode));
 }
 
 static const struct file_operations r_file_operations = {
        .open = r_open,
        .read = seq_read,
        .llseek = seq_lseek,
-       .release = seq_release_private,
-       .owner = THIS_MODULE,
+       .release = single_release,
 };
 
 static struct proc_dir_entry *proc_info_root = NULL;
 static const char proc_info_root_name[] = "fs/reiserfs";
 
 static void add_file(struct super_block *sb, char *name,
-                    int (*func) (struct seq_file *, struct super_block *))
+                    int (*func) (struct seq_file *, void *))
 {
        proc_create_data(name, 0, REISERFS_SB(sb)->procdir,
                         &r_file_operations, func);
index f8a23c3..e2e202a 100644 (file)
@@ -499,6 +499,7 @@ int remove_save_link(struct inode *inode, int truncate)
 static void reiserfs_kill_sb(struct super_block *s)
 {
        if (REISERFS_SB(s)) {
+               reiserfs_proc_info_done(s);
                /*
                 * Force any pending inode evictions to occur now. Any
                 * inodes to be removed that have extended attributes
@@ -554,8 +555,6 @@ static void reiserfs_put_super(struct super_block *s)
                                 REISERFS_SB(s)->reserved_blocks);
        }
 
-       reiserfs_proc_info_done(s);
-
        reiserfs_write_unlock(s);
        mutex_destroy(&REISERFS_SB(s)->lock);
        kfree(s->s_fs_info);
index 56e6b68..94383a7 100644 (file)
@@ -274,15 +274,12 @@ struct acpi_device_wakeup {
 };
 
 struct acpi_device_physical_node {
-       u8 node_id;
+       unsigned int node_id;
        struct list_head node;
        struct device *dev;
        bool put_online:1;
 };
 
-/* set maximum of physical nodes to 32 for expansibility */
-#define ACPI_MAX_PHYSICAL_NODE 32
-
 /* Device */
 struct acpi_device {
        int device_type;
@@ -302,10 +299,9 @@ struct acpi_device {
        struct acpi_driver *driver;
        void *driver_data;
        struct device dev;
-       u8 physical_node_count;
+       unsigned int physical_node_count;
        struct list_head physical_node_list;
        struct mutex physical_node_lock;
-       DECLARE_BITMAP(physical_node_id_bitmap, ACPI_MAX_PHYSICAL_NODE);
        struct list_head power_dependent;
        void (*remove)(struct acpi_device *);
 };
@@ -445,7 +441,11 @@ struct acpi_pci_root {
 };
 
 /* helper */
-acpi_handle acpi_get_child(acpi_handle, u64);
+acpi_handle acpi_find_child(acpi_handle, u64, bool);
+static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr)
+{
+       return acpi_find_child(handle, addr, false);
+}
 int acpi_is_root_bridge(acpi_handle);
 struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle);
 #define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)ACPI_HANDLE(dev))
index 2f47ade..0807ddf 100644 (file)
@@ -417,6 +417,36 @@ static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
 {
        return pmd;
 }
+
+static inline pte_t pte_swp_mksoft_dirty(pte_t pte)
+{
+       return pte;
+}
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+       return 0;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+       return pte;
+}
+
+static inline pte_t pte_file_clear_soft_dirty(pte_t pte)
+{
+       return pte;
+}
+
+static inline pte_t pte_file_mksoft_dirty(pte_t pte)
+{
+       return pte;
+}
+
+static inline int pte_file_soft_dirty(pte_t pte)
+{
+       return 0;
+}
 #endif
 
 #ifndef __HAVE_PFNMAP_TRACKING
index 13821c3..5672d7e 100644 (file)
@@ -112,7 +112,7 @@ struct mmu_gather {
 
 #define HAVE_GENERIC_MMU_GATHER
 
-void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm);
+void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end);
 void tlb_flush_mmu(struct mmu_gather *tlb);
 void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start,
                                                        unsigned long end);
index f5e1168..d639049 100644 (file)
@@ -84,12 +84,12 @@ static inline int drm_fixp2int(int64_t a)
        return ((s64)a) >> DRM_FIXED_POINT;
 }
 
-static inline s64 drm_fixp_msbset(int64_t a)
+static inline unsigned drm_fixp_msbset(int64_t a)
 {
        unsigned shift, sign = (a >> 63) & 1;
 
        for (shift = 62; shift > 0; --shift)
-               if ((a >> shift) != sign)
+               if (((a >> shift) & 1) != sign)
                        return shift;
 
        return 0;
@@ -100,9 +100,9 @@ static inline s64 drm_fixp_mul(s64 a, s64 b)
        unsigned shift = drm_fixp_msbset(a) + drm_fixp_msbset(b);
        s64 result;
 
-       if (shift > 63) {
-               shift = shift - 63;
-               a >>= shift >> 1;
+       if (shift > 61) {
+               shift = shift - 61;
+               a >>= (shift >> 1) + (shift & 1);
                b >>= shift >> 1;
        } else
                shift = 0;
@@ -120,7 +120,7 @@ static inline s64 drm_fixp_mul(s64 a, s64 b)
 
 static inline s64 drm_fixp_div(s64 a, s64 b)
 {
-       unsigned shift = 63 - drm_fixp_msbset(a);
+       unsigned shift = 62 - drm_fixp_msbset(a);
        s64 result;
 
        a <<= shift;
@@ -154,7 +154,7 @@ static inline s64 drm_fixp_exp(s64 x)
        }
 
        if (x < 0)
-               sum = drm_fixp_div(1, sum);
+               sum = drm_fixp_div(DRM_FIXED_ONE, sum);
 
        return sum;
 }
diff --git a/include/dt-bindings/sound/fsl-imx-audmux.h b/include/dt-bindings/sound/fsl-imx-audmux.h
new file mode 100644 (file)
index 0000000..50b09e9
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef __DT_FSL_IMX_AUDMUX_H
+#define __DT_FSL_IMX_AUDMUX_H
+
+#define MX27_AUDMUX_HPCR1_SSI0         0
+#define MX27_AUDMUX_HPCR2_SSI1         1
+#define MX27_AUDMUX_HPCR3_SSI_PINS_4   2
+#define MX27_AUDMUX_PPCR1_SSI_PINS_1   3
+#define MX27_AUDMUX_PPCR2_SSI_PINS_2   4
+#define MX27_AUDMUX_PPCR3_SSI_PINS_3   5
+
+#define MX31_AUDMUX_PORT1_SSI0         0
+#define MX31_AUDMUX_PORT2_SSI1         1
+#define MX31_AUDMUX_PORT3_SSI_PINS_3   2
+#define MX31_AUDMUX_PORT4_SSI_PINS_4   3
+#define MX31_AUDMUX_PORT5_SSI_PINS_5   4
+#define MX31_AUDMUX_PORT6_SSI_PINS_6   5
+#define MX31_AUDMUX_PORT7_SSI_PINS_7   6
+
+#define MX51_AUDMUX_PORT1_SSI0         0
+#define MX51_AUDMUX_PORT2_SSI1         1
+#define MX51_AUDMUX_PORT3              2
+#define MX51_AUDMUX_PORT4              3
+#define MX51_AUDMUX_PORT5              4
+#define MX51_AUDMUX_PORT6              5
+#define MX51_AUDMUX_PORT7              6
+
+/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
+#define IMX_AUDMUX_V1_PCR_INMMASK(x)   ((x) & 0xff)
+#define IMX_AUDMUX_V1_PCR_INMEN                (1 << 8)
+#define IMX_AUDMUX_V1_PCR_TXRXEN       (1 << 10)
+#define IMX_AUDMUX_V1_PCR_SYN          (1 << 12)
+#define IMX_AUDMUX_V1_PCR_RXDSEL(x)    (((x) & 0x7) << 13)
+#define IMX_AUDMUX_V1_PCR_RFCSEL(x)    (((x) & 0xf) << 20)
+#define IMX_AUDMUX_V1_PCR_RCLKDIR      (1 << 24)
+#define IMX_AUDMUX_V1_PCR_RFSDIR       (1 << 25)
+#define IMX_AUDMUX_V1_PCR_TFCSEL(x)    (((x) & 0xf) << 26)
+#define IMX_AUDMUX_V1_PCR_TCLKDIR      (1 << 30)
+#define IMX_AUDMUX_V1_PCR_TFSDIR       (1 << 31)
+
+/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */
+#define IMX_AUDMUX_V2_PTCR_TFSDIR      (1 << 31)
+#define IMX_AUDMUX_V2_PTCR_TFSEL(x)    (((x) & 0xf) << 27)
+#define IMX_AUDMUX_V2_PTCR_TCLKDIR     (1 << 26)
+#define IMX_AUDMUX_V2_PTCR_TCSEL(x)    (((x) & 0xf) << 22)
+#define IMX_AUDMUX_V2_PTCR_RFSDIR      (1 << 21)
+#define IMX_AUDMUX_V2_PTCR_RFSEL(x)    (((x) & 0xf) << 17)
+#define IMX_AUDMUX_V2_PTCR_RCLKDIR     (1 << 16)
+#define IMX_AUDMUX_V2_PTCR_RCSEL(x)    (((x) & 0xf) << 12)
+#define IMX_AUDMUX_V2_PTCR_SYN         (1 << 11)
+
+#define IMX_AUDMUX_V2_PDCR_RXDSEL(x)   (((x) & 0x7) << 13)
+#define IMX_AUDMUX_V2_PDCR_TXRXEN      (1 << 12)
+#define IMX_AUDMUX_V2_PDCR_MODE(x)     (((x) & 0x3) << 8)
+#define IMX_AUDMUX_V2_PDCR_INMMASK(x)  ((x) & 0xff)
+
+#endif /* __DT_FSL_IMX_AUDMUX_H */
index deb0ae5..66a0e53 100644 (file)
@@ -11,7 +11,7 @@ struct atmel_ssc_platform_data {
 
 struct ssc_device {
        struct list_head        list;
-       resource_size_t         phybase;
+       dma_addr_t              phybase;
        void __iomem            *regs;
        struct platform_device  *pdev;
        struct atmel_ssc_platform_data *pdata;
index 3b0e820..5d7782e 100644 (file)
@@ -436,6 +436,7 @@ struct fw_iso_context {
        int type;
        int channel;
        int speed;
+       bool drop_overflow_headers;
        size_t header_size;
        union {
                fw_iso_callback_t sc;
index 4372658..120d57a 100644 (file)
@@ -78,6 +78,11 @@ struct trace_iterator {
        /* trace_seq for __print_flags() and __print_symbolic() etc. */
        struct trace_seq        tmp_seq;
 
+       cpumask_var_t           started;
+
+       /* it's true when current open file is snapshot */
+       bool                    snapshot;
+
        /* The below is zeroed out in pipe_read */
        struct trace_seq        seq;
        struct trace_entry      *ent;
@@ -90,10 +95,7 @@ struct trace_iterator {
        loff_t                  pos;
        long                    idx;
 
-       cpumask_var_t           started;
-
-       /* it's true when current open file is snapshot */
-       bool                    snapshot;
+       /* All new field here will be zeroed out in pipe_read */
 };
 
 enum trace_iter_flags {
@@ -332,7 +334,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type,
                              const char *name, int offset, int size,
                              int is_signed, int filter_type);
 extern int trace_add_event_call(struct ftrace_event_call *call);
-extern void trace_remove_event_call(struct ftrace_event_call *call);
+extern int trace_remove_event_call(struct ftrace_event_call *call);
 
 #define is_signed_type(type)   (((type)(-1)) < (type)1)
 
index 3869c52..369cf2c 100644 (file)
@@ -8,6 +8,7 @@
  */
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/atomic.h>
 
 #ifndef _IIO_TRIGGER_H_
 #define _IIO_TRIGGER_H_
@@ -61,7 +62,7 @@ struct iio_trigger {
 
        struct list_head                list;
        struct list_head                alloc_list;
-       int use_count;
+       atomic_t                        use_count;
 
        struct irq_chip                 subirq_chip;
        int                             subirq_base;
index 3bef14c..482ad2d 100644 (file)
@@ -629,7 +629,7 @@ extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode);
 static inline void tracing_start(void) { }
 static inline void tracing_stop(void) { }
 static inline void ftrace_off_permanent(void) { }
-static inline void trace_dump_stack(void) { }
+static inline void trace_dump_stack(int skip) { }
 
 static inline void tracing_on(void) { }
 static inline void tracing_off(void) { }
diff --git a/include/linux/mfd/arizona/gpio.h b/include/linux/mfd/arizona/gpio.h
new file mode 100644 (file)
index 0000000..d2146bb
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * GPIO configuration for Arizona devices
+ *
+ * Copyright 2013 Wolfson Microelectronics. PLC.
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _ARIZONA_GPIO_H
+#define _ARIZONA_GPIO_H
+
+#define ARIZONA_GP_FN_TXLRCLK                    0x00
+#define ARIZONA_GP_FN_GPIO                       0x01
+#define ARIZONA_GP_FN_IRQ1                       0x02
+#define ARIZONA_GP_FN_IRQ2                       0x03
+#define ARIZONA_GP_FN_OPCLK                      0x04
+#define ARIZONA_GP_FN_FLL1_OUT                   0x05
+#define ARIZONA_GP_FN_FLL2_OUT                   0x06
+#define ARIZONA_GP_FN_PWM1                       0x08
+#define ARIZONA_GP_FN_PWM2                       0x09
+#define ARIZONA_GP_FN_SYSCLK_UNDERCLOCKED        0x0A
+#define ARIZONA_GP_FN_ASYNCCLK_UNDERCLOCKED      0x0B
+#define ARIZONA_GP_FN_FLL1_LOCK                  0x0C
+#define ARIZONA_GP_FN_FLL2_LOCK                  0x0D
+#define ARIZONA_GP_FN_FLL1_CLOCK_OK              0x0F
+#define ARIZONA_GP_FN_FLL2_CLOCK_OK              0x10
+#define ARIZONA_GP_FN_HEADPHONE_DET              0x12
+#define ARIZONA_GP_FN_MIC_DET                    0x13
+#define ARIZONA_GP_FN_WSEQ_STATUS                0x15
+#define ARIZONA_GP_FN_CIF_ADDRESS_ERROR          0x16
+#define ARIZONA_GP_FN_ASRC1_LOCK                 0x1A
+#define ARIZONA_GP_FN_ASRC2_LOCK                 0x1B
+#define ARIZONA_GP_FN_ASRC_CONFIG_ERROR          0x1C
+#define ARIZONA_GP_FN_DRC1_SIGNAL_DETECT         0x1D
+#define ARIZONA_GP_FN_DRC1_ANTICLIP              0x1E
+#define ARIZONA_GP_FN_DRC1_DECAY                 0x1F
+#define ARIZONA_GP_FN_DRC1_NOISE                 0x20
+#define ARIZONA_GP_FN_DRC1_QUICK_RELEASE         0x21
+#define ARIZONA_GP_FN_DRC2_SIGNAL_DETECT         0x22
+#define ARIZONA_GP_FN_DRC2_ANTICLIP              0x23
+#define ARIZONA_GP_FN_DRC2_DECAY                 0x24
+#define ARIZONA_GP_FN_DRC2_NOISE                 0x25
+#define ARIZONA_GP_FN_DRC2_QUICK_RELEASE         0x26
+#define ARIZONA_GP_FN_MIXER_DROPPED_SAMPLE       0x27
+#define ARIZONA_GP_FN_AIF1_CONFIG_ERROR          0x28
+#define ARIZONA_GP_FN_AIF2_CONFIG_ERROR          0x29
+#define ARIZONA_GP_FN_AIF3_CONFIG_ERROR          0x2A
+#define ARIZONA_GP_FN_SPK_TEMP_SHUTDOWN          0x2B
+#define ARIZONA_GP_FN_SPK_TEMP_WARNING           0x2C
+#define ARIZONA_GP_FN_UNDERCLOCKED               0x2D
+#define ARIZONA_GP_FN_OVERCLOCKED                0x2E
+#define ARIZONA_GP_FN_DSP_IRQ1                   0x35
+#define ARIZONA_GP_FN_DSP_IRQ2                   0x36
+#define ARIZONA_GP_FN_ASYNC_OPCLK                0x3D
+#define ARIZONA_GP_FN_BOOT_DONE                  0x44
+#define ARIZONA_GP_FN_DSP1_RAM_READY             0x45
+#define ARIZONA_GP_FN_SYSCLK_ENA_STATUS          0x4B
+#define ARIZONA_GP_FN_ASYNCCLK_ENA_STATUS        0x4C
+
+#define ARIZONA_GPN_DIR                          0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_MASK                     0x8000  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_SHIFT                        15  /* GPN_DIR */
+#define ARIZONA_GPN_DIR_WIDTH                         1  /* GPN_DIR */
+#define ARIZONA_GPN_PU                           0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_MASK                      0x4000  /* GPN_PU */
+#define ARIZONA_GPN_PU_SHIFT                         14  /* GPN_PU */
+#define ARIZONA_GPN_PU_WIDTH                          1  /* GPN_PU */
+#define ARIZONA_GPN_PD                           0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_MASK                      0x2000  /* GPN_PD */
+#define ARIZONA_GPN_PD_SHIFT                         13  /* GPN_PD */
+#define ARIZONA_GPN_PD_WIDTH                          1  /* GPN_PD */
+#define ARIZONA_GPN_LVL                          0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_MASK                     0x0800  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_SHIFT                        11  /* GPN_LVL */
+#define ARIZONA_GPN_LVL_WIDTH                         1  /* GPN_LVL */
+#define ARIZONA_GPN_POL                          0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_MASK                     0x0400  /* GPN_POL */
+#define ARIZONA_GPN_POL_SHIFT                        10  /* GPN_POL */
+#define ARIZONA_GPN_POL_WIDTH                         1  /* GPN_POL */
+#define ARIZONA_GPN_OP_CFG                       0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_MASK                  0x0200  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_SHIFT                      9  /* GPN_OP_CFG */
+#define ARIZONA_GPN_OP_CFG_WIDTH                      1  /* GPN_OP_CFG */
+#define ARIZONA_GPN_DB                           0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_MASK                      0x0100  /* GPN_DB */
+#define ARIZONA_GPN_DB_SHIFT                          8  /* GPN_DB */
+#define ARIZONA_GPN_DB_WIDTH                          1  /* GPN_DB */
+#define ARIZONA_GPN_FN_MASK                      0x007F  /* GPN_DB */
+#define ARIZONA_GPN_FN_SHIFT                          0  /* GPN_DB */
+#define ARIZONA_GPN_FN_WIDTH                          7  /* GPN_DB */
+
+#endif
index 8d73fe2..db1791b 100644 (file)
 #define CNTRLREG_8WIRE         CNTRLREG_AFE_CTRL(3)
 #define CNTRLREG_TSCENB                BIT(7)
 
+/* FIFO READ Register */
+#define FIFOREAD_DATA_MASK (0xfff << 0)
+#define FIFOREAD_CHNLID_MASK (0xf << 16)
+
+/* Sequencer Status */
+#define SEQ_STATUS BIT(5)
+
 #define ADC_CLK                        3000000
 #define        MAX_CLK_DIV             7
 #define TOTAL_STEPS            16
 #define TOTAL_CHANNELS         8
 
+/*
+* ADC runs at 3MHz, and it takes
+* 15 cycles to latch one data output.
+* Hence the idle time for ADC to
+* process one sample data would be
+* around 5 micro seconds.
+*/
+#define IDLE_TIMEOUT 5 /* microsec */
+
 #define TSCADC_CELLS           2
 
 struct ti_tscadc_dev {
index 8de8d8f..68029b3 100644 (file)
@@ -309,21 +309,20 @@ struct mlx5_hca_cap {
        __be16  max_desc_sz_rq;
        u8      rsvd21[2];
        __be16  max_desc_sz_sq_dc;
-       u8      rsvd22[4];
-       __be16  max_qp_mcg;
-       u8      rsvd23;
+       __be32  max_qp_mcg;
+       u8      rsvd22[3];
        u8      log_max_mcg;
-       u8      rsvd24;
+       u8      rsvd23;
        u8      log_max_pd;
-       u8      rsvd25;
+       u8      rsvd24;
        u8      log_max_xrcd;
-       u8      rsvd26[42];
+       u8      rsvd25[42];
        __be16  log_uar_page_sz;
-       u8      rsvd27[28];
+       u8      rsvd26[28];
        u8      log_msx_atomic_size_qp;
-       u8      rsvd28[2];
+       u8      rsvd27[2];
        u8      log_msx_atomic_size_dc;
-       u8      rsvd29[76];
+       u8      rsvd28[76];
 };
 
 
@@ -472,9 +471,8 @@ struct mlx5_eqe_cmd {
 struct mlx5_eqe_page_req {
        u8              rsvd0[2];
        __be16          func_id;
-       u8              rsvd1[2];
-       __be16          num_pages;
-       __be32          rsvd2[5];
+       __be32          num_pages;
+       __be32          rsvd1[5];
 };
 
 union ev_data {
@@ -690,6 +688,26 @@ struct mlx5_query_cq_mbox_out {
        __be64                  pas[0];
 };
 
+struct mlx5_enable_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_enable_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_disable_hca_mbox_in {
+       struct mlx5_inbox_hdr   hdr;
+       u8                      rsvd[8];
+};
+
+struct mlx5_disable_hca_mbox_out {
+       struct mlx5_outbox_hdr  hdr;
+       u8                      rsvd[8];
+};
+
 struct mlx5_eq_context {
        u8                      status;
        u8                      ec_oi;
index f22e441..8888381 100644 (file)
@@ -101,6 +101,8 @@ enum {
        MLX5_CMD_OP_QUERY_ADAPTER               = 0x101,
        MLX5_CMD_OP_INIT_HCA                    = 0x102,
        MLX5_CMD_OP_TEARDOWN_HCA                = 0x103,
+       MLX5_CMD_OP_ENABLE_HCA                  = 0x104,
+       MLX5_CMD_OP_DISABLE_HCA                 = 0x105,
        MLX5_CMD_OP_QUERY_PAGES                 = 0x107,
        MLX5_CMD_OP_MANAGE_PAGES                = 0x108,
        MLX5_CMD_OP_SET_HCA_CAP                 = 0x109,
@@ -356,7 +358,7 @@ struct mlx5_caps {
        u32     reserved_lkey;
        u8      local_ca_ack_delay;
        u8      log_max_mcg;
-       u16     max_qp_mcg;
+       u32     max_qp_mcg;
        int     min_page_sz;
 };
 
@@ -689,8 +691,8 @@ void mlx5_pagealloc_cleanup(struct mlx5_core_dev *dev);
 int mlx5_pagealloc_start(struct mlx5_core_dev *dev);
 void mlx5_pagealloc_stop(struct mlx5_core_dev *dev);
 void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id,
-                                s16 npages);
-int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev);
+                                s32 npages);
+int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot);
 int mlx5_reclaim_startup_pages(struct mlx5_core_dev *dev);
 void mlx5_register_debugfs(void);
 void mlx5_unregister_debugfs(void);
@@ -729,9 +731,6 @@ void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev);
 int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db);
 void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db);
 
-typedef void (*health_handler_t)(struct pci_dev *pdev, struct health_buffer __iomem *buf, int size);
-int mlx5_register_health_report_handler(health_handler_t handler);
-void mlx5_unregister_health_report_handler(void);
 const char *mlx5_command_str(int command);
 int mlx5_cmdif_debugfs_init(struct mlx5_core_dev *dev);
 void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev);
index b62d4af..45e9214 100644 (file)
@@ -361,7 +361,8 @@ struct ssb_device_id {
        __u16   vendor;
        __u16   coreid;
        __u8    revision;
-};
+       __u8    __pad;
+} __attribute__((packed, aligned(2)));
 #define SSB_DEVICE(_vendor, _coreid, _revision)  \
        { .vendor = _vendor, .coreid = _coreid, .revision = _revision, }
 #define SSB_DEVTABLE_END  \
@@ -377,7 +378,7 @@ struct bcma_device_id {
        __u16   id;
        __u8    rev;
        __u8    class;
-};
+} __attribute__((packed,aligned(2)));
 #define BCMA_CORE(_manuf, _id, _rev, _class)  \
        { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, }
 #define BCMA_CORETABLE_END  \
index 0741a1e..9a41568 100644 (file)
@@ -973,7 +973,7 @@ struct net_device_ops {
                                                     gfp_t gfp);
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        int                     (*ndo_busy_poll)(struct napi_struct *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
index 8827259..9efc04d 100644 (file)
@@ -36,6 +36,7 @@ struct samsung_i2s {
  */
 #define QUIRK_NO_MUXPSR                (1 << 2)
 #define QUIRK_NEED_RSTCLR      (1 << 3)
+#define QUIRK_SUPPORTS_TDM     (1 << 4)
        /* Quirks of the I2S controller */
        u32 quirks;
        dma_addr_t idma_addr;
diff --git a/include/linux/platform_data/omap-abe-twl6040.h b/include/linux/platform_data/omap-abe-twl6040.h
deleted file mode 100644 (file)
index 5d298ac..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * omap-abe-twl6040.h - ASoC machine driver OMAP4+ devices, header.
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
- * All rights reserved.
- *
- * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef _OMAP_ABE_TWL6040_H_
-#define _OMAP_ABE_TWL6040_H_
-
-/* To select if only one channel is connected in a stereo port */
-#define ABE_TWL6040_LEFT       (1 << 0)
-#define ABE_TWL6040_RIGHT      (1 << 1)
-
-struct omap_abe_twl6040_data {
-       char *card_name;
-       /* Feature flags for connected audio pins */
-       u8      has_hs;
-       u8      has_hf;
-       bool    has_ep;
-       u8      has_aux;
-       u8      has_vibra;
-       bool    has_dmic;
-       bool    has_hsmic;
-       bool    has_mainmic;
-       bool    has_submic;
-       u8      has_afm;
-       /* Other features */
-       bool    jack_detection; /* board can detect jack events */
-       int     mclk_freq;      /* MCLK frequency speed for twl6040 */
-};
-
-#endif /* _OMAP_ABE_TWL6040_H_ */
index 467cc63..4944420 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/of.h>
+
 
 /*
  * SSP Serial Port Registers
@@ -190,6 +192,8 @@ struct ssp_device {
        int             irq;
        int             drcmr_rx;
        int             drcmr_tx;
+
+       struct device_node      *of_node;
 };
 
 /**
@@ -218,11 +222,18 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
 #ifdef CONFIG_ARCH_PXA
 struct ssp_device *pxa_ssp_request(int port, const char *label);
 void pxa_ssp_free(struct ssp_device *);
+struct ssp_device *pxa_ssp_request_of(const struct device_node *of_node,
+                                     const char *label);
 #else
 static inline struct ssp_device *pxa_ssp_request(int port, const char *label)
 {
        return NULL;
 }
+static inline struct ssp_device *pxa_ssp_request_of(const struct device_node *n,
+                                                   const char *name)
+{
+       return NULL;
+}
 static inline void pxa_ssp_free(struct ssp_device *ssp) {}
 #endif
 
index 75981d0..580a532 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/list.h>
 #include <linux/rbtree.h>
+#include <linux/err.h>
 
 struct module;
 struct device;
index 50d04b9..e9995eb 100644 (file)
@@ -314,6 +314,7 @@ struct nsproxy;
 struct user_namespace;
 
 #ifdef CONFIG_MMU
+extern unsigned long mmap_legacy_base(void);
 extern void arch_pick_mmap_layout(struct mm_struct *mm);
 extern unsigned long
 arch_get_unmapped_area(struct file *, unsigned long, unsigned long,
@@ -1532,6 +1533,8 @@ static inline pid_t task_pgrp_nr(struct task_struct *tsk)
  * Test if a process is not yet dead (at most zombie state)
  * If pid_alive fails, then pointers within the task structure
  * can be stale and must not be dereferenced.
+ *
+ * Return: 1 if the process is alive. 0 otherwise.
  */
 static inline int pid_alive(struct task_struct *p)
 {
@@ -1543,6 +1546,8 @@ static inline int pid_alive(struct task_struct *p)
  * @tsk: Task structure to be checked.
  *
  * Check if a task structure is the first user space task the kernel created.
+ *
+ * Return: 1 if the task structure is init. 0 otherwise.
  */
 static inline int is_global_init(struct task_struct *tsk)
 {
@@ -1628,6 +1633,7 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
 #define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
 #define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezable */
+#define PF_SUSPEND_TASK 0x80000000      /* this thread called freeze_processes and should not be frozen */
 
 /*
  * Only the _current_ task can read/write to tsk->flags, but other
@@ -1893,6 +1899,8 @@ extern struct task_struct *idle_task(int cpu);
 /**
  * is_idle_task - is the specified task an idle task?
  * @p: the task in question.
+ *
+ * Return: 1 if @p is an idle task. 0 otherwise.
  */
 static inline bool is_idle_task(const struct task_struct *p)
 {
index 5afefa0..3b71a4e 100644 (file)
@@ -501,7 +501,7 @@ struct sk_buff {
        /* 7/9 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
-#if defined CONFIG_NET_DMA || defined CONFIG_NET_LL_RX_POLL
+#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
        union {
                unsigned int    napi_id;
                dma_cookie_t    dma_cookie;
index 7d537ce..75f3494 100644 (file)
@@ -117,9 +117,17 @@ do {                                                               \
 #endif /*arch_spin_is_contended*/
 #endif
 
-/* The lock does not imply full memory barrier. */
-#ifndef ARCH_HAS_SMP_MB_AFTER_LOCK
-static inline void smp_mb__after_lock(void) { smp_mb(); }
+/*
+ * Despite its name it doesn't necessarily has to be a full barrier.
+ * It should only guarantee that a STORE before the critical section
+ * can not be reordered with a LOAD inside this section.
+ * spin_lock() is the one-way barrier, this LOAD can not escape out
+ * of the region. So the default implementation simply ensures that
+ * a STORE can not move into the critical section, smp_wmb() should
+ * serialize it with another STORE done by spin_lock().
+ */
+#ifndef smp_mb__before_spinlock
+#define smp_mb__before_spinlock()      smp_wmb()
 #endif
 
 /**
index 6d87035..1821445 100644 (file)
@@ -121,6 +121,7 @@ struct rpc_task_setup {
 #define RPC_TASK_SOFTCONN      0x0400          /* Fail if can't connect */
 #define RPC_TASK_SENT          0x0800          /* message was sent */
 #define RPC_TASK_TIMEOUT       0x1000          /* fail with ETIMEDOUT on timeout */
+#define RPC_TASK_NOCONNECT     0x2000          /* return ENOTCONN if not connected */
 
 #define RPC_IS_ASYNC(t)                ((t)->tk_flags & RPC_TASK_ASYNC)
 #define RPC_IS_SWAPPER(t)      ((t)->tk_flags & RPC_TASK_SWAPPER)
index c5fd30d..8d4fa82 100644 (file)
@@ -67,6 +67,8 @@ static inline swp_entry_t pte_to_swp_entry(pte_t pte)
        swp_entry_t arch_entry;
 
        BUG_ON(pte_file(pte));
+       if (pte_swp_soft_dirty(pte))
+               pte = pte_swp_clear_soft_dirty(pte);
        arch_entry = __pte_to_swp_entry(pte);
        return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry));
 }
index 4147d70..84662ec 100644 (file)
@@ -802,9 +802,14 @@ asmlinkage long sys_vfork(void);
 asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, int,
               int __user *);
 #else
+#ifdef CONFIG_CLONE_BACKWARDS3
+asmlinkage long sys_clone(unsigned long, unsigned long, int, int __user *,
+                         int __user *, int);
+#else
 asmlinkage long sys_clone(unsigned long, unsigned long, int __user *,
               int __user *, int);
 #endif
+#endif
 
 asmlinkage long sys_execve(const char __user *filename,
                const char __user *const __user *argv,
index 9180f4b..62bd8b7 100644 (file)
@@ -174,10 +174,4 @@ static inline void tick_nohz_task_switch(struct task_struct *tsk) { }
 #endif
 
 
-# ifdef CONFIG_CPU_IDLE_GOV_MENU
-extern void menu_hrtimer_cancel(void);
-# else
-static inline void menu_hrtimer_cancel(void) {}
-# endif /* CONFIG_CPU_IDLE_GOV_MENU */
-
 #endif
index b6b215f..14105c2 100644 (file)
@@ -23,6 +23,7 @@ struct user_namespace {
        struct uid_gid_map      projid_map;
        atomic_t                count;
        struct user_namespace   *parent;
+       int                     level;
        kuid_t                  owner;
        kgid_t                  group;
        unsigned int            proc_inum;
index 76be077..7dc17e2 100644 (file)
@@ -12,7 +12,7 @@ struct vmpressure {
        unsigned long scanned;
        unsigned long reclaimed;
        /* The lock is used to keep the scanned/reclaimed above in sync. */
-       struct mutex sr_lock;
+       struct spinlock sr_lock;
 
        /* The list of vmpressure_event structs. */
        struct list_head events;
@@ -30,6 +30,7 @@ extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
 extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio);
 
 extern void vmpressure_init(struct vmpressure *vmpr);
+extern void vmpressure_cleanup(struct vmpressure *vmpr);
 extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg);
 extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr);
 extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css);
index 7343a27..47ada23 100644 (file)
@@ -22,6 +22,7 @@
 #define _V4L2_CTRLS_H
 
 #include <linux/list.h>
+#include <linux/mutex.h>
 #include <linux/videodev2.h>
 
 /* forward references */
index a14339c..8a358a2 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/netdevice.h>
 #include <net/ip.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 
 struct napi_struct;
 extern unsigned int sysctl_net_busy_read __read_mostly;
@@ -122,7 +122,7 @@ static inline bool sk_busy_loop(struct sock *sk, int nonblock)
                if (rc > 0)
                        /* local bh are disabled so it is ok to use _BH */
                        NET_ADD_STATS_BH(sock_net(sk),
-                                        LINUX_MIB_LOWLATENCYRXPACKETS, rc);
+                                        LINUX_MIB_BUSYPOLLRXPACKETS, rc);
 
        } while (!nonblock && skb_queue_empty(&sk->sk_receive_queue) &&
                 !need_resched() && !busy_loop_timeout(end_time));
@@ -146,7 +146,7 @@ static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb)
        sk->sk_napi_id = skb->napi_id;
 }
 
-#else /* CONFIG_NET_LL_RX_POLL */
+#else /* CONFIG_NET_RX_BUSY_POLL */
 static inline unsigned long net_busy_loop_on(void)
 {
        return 0;
@@ -162,11 +162,6 @@ static inline bool sk_can_busy_loop(struct sock *sk)
        return false;
 }
 
-static inline bool sk_busy_poll(struct sock *sk, int nonblock)
-{
-       return false;
-}
-
 static inline void skb_mark_napi_id(struct sk_buff *skb,
                                    struct napi_struct *napi)
 {
@@ -181,5 +176,10 @@ static inline bool busy_loop_timeout(unsigned long end_time)
        return true;
 }
 
-#endif /* CONFIG_NET_LL_RX_POLL */
+static inline bool sk_busy_loop(struct sock *sk, int nonblock)
+{
+       return false;
+}
+
+#endif /* CONFIG_NET_RX_BUSY_POLL */
 #endif /* _LINUX_NET_BUSY_POLL_H */
index 2a601e7..48ec25a 100644 (file)
@@ -300,7 +300,7 @@ extern void                 inet6_rt_notify(int event, struct rt6_info *rt,
                                                struct nl_info *info);
 
 extern void                    fib6_run_gc(unsigned long expires,
-                                           struct net *net);
+                                           struct net *net, bool force);
 
 extern void                    fib6_gc_cleanup(void);
 
index 781b3cf..a354db5 100644 (file)
@@ -145,20 +145,6 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
        return INET_ECN_encapsulate(tos, inner);
 }
 
-static inline void tunnel_ip_select_ident(struct sk_buff *skb,
-                                         const struct iphdr  *old_iph,
-                                         struct dst_entry *dst)
-{
-       struct iphdr *iph = ip_hdr(skb);
-
-       /* Use inner packet iph-id if possible. */
-       if (skb->protocol == htons(ETH_P_IP) && old_iph->id)
-               iph->id = old_iph->id;
-       else
-               __ip_select_ident(iph, dst,
-                                 (skb_shinfo(skb)->gso_segs ?: 1) - 1);
-}
-
 int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto);
 int iptunnel_xmit(struct net *net, struct rtable *rt,
                  struct sk_buff *skb,
index 949d775..6fea323 100644 (file)
@@ -119,7 +119,7 @@ extern struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len,
  * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may
  * also need a pad of 2.
  */
-static int ndisc_addr_option_pad(unsigned short type)
+static inline int ndisc_addr_option_pad(unsigned short type)
 {
        switch (type) {
        case ARPHRD_INFINIBAND: return 2;
index 0af851c..b64b7bc 100644 (file)
@@ -59,7 +59,7 @@ struct nfc_hci_ops {
                              struct nfc_target *target);
        int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event,
                              struct sk_buff *skb);
-       int (*fw_upload)(struct nfc_hci_dev *hdev, const char *firmware_name);
+       int (*fw_download)(struct nfc_hci_dev *hdev, const char *firmware_name);
        int (*discover_se)(struct nfc_hci_dev *dev);
        int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx);
        int (*disable_se)(struct nfc_hci_dev *dev, u32 se_idx);
index 0e353f1..5f286b7 100644 (file)
@@ -68,7 +68,7 @@ struct nfc_ops {
                             void *cb_context);
        int (*tm_send)(struct nfc_dev *dev, struct sk_buff *skb);
        int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target);
-       int (*fw_upload)(struct nfc_dev *dev, const char *firmware_name);
+       int (*fw_download)(struct nfc_dev *dev, const char *firmware_name);
 
        /* Secure Element API */
        int (*discover_se)(struct nfc_dev *dev);
@@ -127,7 +127,7 @@ struct nfc_dev {
        int targets_generation;
        struct device dev;
        bool dev_up;
-       bool fw_upload_in_progress;
+       bool fw_download_in_progress;
        u8 rf_mode;
        bool polling;
        struct nfc_target *active_target;
index 6eab633..e5ae0c5 100644 (file)
@@ -683,13 +683,19 @@ struct psched_ratecfg {
        u64     rate_bytes_ps; /* bytes per second */
        u32     mult;
        u16     overhead;
+       u8      linklayer;
        u8      shift;
 };
 
 static inline u64 psched_l2t_ns(const struct psched_ratecfg *r,
                                unsigned int len)
 {
-       return ((u64)(len + r->overhead) * r->mult) >> r->shift;
+       len += r->overhead;
+
+       if (unlikely(r->linklayer == TC_LINKLAYER_ATM))
+               return ((u64)(DIV_ROUND_UP(len,48)*53) * r->mult) >> r->shift;
+
+       return ((u64)len * r->mult) >> r->shift;
 }
 
 extern void psched_ratecfg_precompute(struct psched_ratecfg *r, const struct tc_ratespec *conf);
@@ -700,6 +706,7 @@ static inline void psched_ratecfg_getrate(struct tc_ratespec *res,
        memset(res, 0, sizeof(*res));
        res->rate = r->rate_bytes_ps;
        res->overhead = r->overhead;
+       res->linklayer = (r->linklayer & TC_LINKLAYER_MASK);
 }
 
 #endif
index 95a5a2c..31d5cfb 100644 (file)
@@ -327,7 +327,7 @@ struct sock {
 #ifdef CONFIG_RPS
        __u32                   sk_rxhash;
 #endif
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        unsigned int            sk_napi_id;
        unsigned int            sk_ll_usec;
 #endif
index 2fd3d25..56e818e 100644 (file)
@@ -6,13 +6,6 @@
 
 /* PCM */
 
-struct pxa2xx_pcm_dma_params {
-       char *name;                     /* stream identifier */
-       u32 dcmd;                       /* DMA descriptor dcmd field */
-       volatile u32 *drcmr;            /* the DMA request channel to use */
-       u32 dev_addr;                   /* device physical address for DMA */
-};
-
 extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params);
 extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
new file mode 100644 (file)
index 0000000..d35412a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RCAR_SND_H
+#define RCAR_SND_H
+
+#include <linux/sh_clk.h>
+
+#define RSND_GEN1_SRU  0
+#define RSND_GEN1_ADG  1
+#define RSND_GEN1_SSI  2
+
+#define RSND_GEN2_SRU  0
+#define RSND_GEN2_ADG  1
+#define RSND_GEN2_SSIU 2
+#define RSND_GEN2_SSI  3
+
+#define RSND_BASE_MAX  4
+
+/*
+ * flags
+ *
+ * 0xAB000000
+ *
+ * A : clock sharing settings
+ * B : SSI direction
+ */
+#define RSND_SSI_CLK_PIN_SHARE         (1 << 31)
+#define RSND_SSI_CLK_FROM_ADG          (1 << 30) /* clock parent is master */
+#define RSND_SSI_SYNC                  (1 << 29) /* SSI34_sync etc */
+#define RSND_SSI_DEPENDENT             (1 << 28) /* SSI needs SRU/SCU */
+
+#define RSND_SSI_PLAY                  (1 << 24)
+
+#define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags)       \
+{ .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
+#define RSND_SSI_UNUSED \
+{ .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 }
+
+struct rsnd_ssi_platform_info {
+       int dai_id;
+       int dma_id;
+       int pio_irq;
+       u32 flags;
+};
+
+/*
+ * flags
+ */
+#define RSND_SCU_USB_HPBIF             (1 << 31) /* it needs RSND_SSI_DEPENDENT */
+
+struct rsnd_scu_platform_info {
+       u32 flags;
+};
+
+/*
+ * flags
+ *
+ * 0x0000000A
+ *
+ * A : generation
+ */
+#define RSND_GEN1      (1 << 0) /* fixme */
+#define RSND_GEN2      (2 << 0) /* fixme */
+
+struct rcar_snd_info {
+       u32 flags;
+       struct rsnd_ssi_platform_info *ssi_info;
+       int ssi_info_nr;
+       struct rsnd_scu_platform_info *scu_info;
+       int scu_info_nr;
+       int (*start)(int id);
+       int (*stop)(int id);
+};
+
+#endif
index 3e479f4..c728d28 100644 (file)
@@ -70,121 +70,144 @@ struct device;
        .num_kcontrols = 0, .reg = SND_SOC_NOPM, .event = wevent, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD}
 
+#define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
+       .reg = wreg, .mask = 1, .shift = wshift, \
+       .on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
+
 /* path domain */
 #define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
         wcontrols, wncontrols) \
-{      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{      .id = snd_soc_dapm_out_drv, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, \
         wcontrols, wncontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = wncontrols}
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
 #define SND_SOC_DAPM_MICBIAS(wname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_micbias, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = NULL, .num_kcontrols = 0}
+{      .id = snd_soc_dapm_micbias, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = NULL, .num_kcontrols = 0}
 #define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{      .id = snd_soc_dapm_switch, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1}
+{      .id = snd_soc_dapm_virt_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
-{      .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = 1}
+{      .id = snd_soc_dapm_value_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
         wcontrols) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 #define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, \
         wcontrols)\
-{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = ARRAY_SIZE(wcontrols)}
+{       .id = snd_soc_dapm_mixer_named_ctl, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}
 
 /* path domain with event - event handler must return 0 for success */
 #define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{      .id = snd_soc_dapm_out_drv, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
        wncontrols, wevent, wflags) \
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = wncontrols, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MIXER_NAMED_CTL_E(wname, wreg, wshift, winvert, \
        wcontrols, wncontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, \
+{       .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, \
        .num_kcontrols = wncontrols, .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_switch, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{      .id = snd_soc_dapm_switch, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{      .id = snd_soc_dapm_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = 1, \
+{      .id = snd_soc_dapm_virt_mux, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = 1, \
        .event = wevent, .event_flags = wflags}
 
 /* additional sequencing control within an event type */
 #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .event = wevent, .event_flags = wflags, \
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .event = wevent, .event_flags = wflags, \
        .subseq = wsubseq}
 #define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
        wflags) \
-{      .id = snd_soc_dapm_supply, .name = wname, .reg = wreg,  \
-       .shift = wshift, .invert = winvert, .event = wevent, \
-       .event_flags = wflags, .subseq = wsubseq}
+{      .id = snd_soc_dapm_supply, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .event = wevent, .event_flags = wflags, .subseq = wsubseq}
 
 /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
 #define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+{      .id = snd_soc_dapm_pga, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
        wevent, wflags) \
-{      .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+{      .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
        .event = wevent, .event_flags = wflags}
 #define SOC_MIXER_NAMED_CTL_E_ARRAY(wname, wreg, wshift, winvert, \
        wcontrols, wevent, wflags) \
-{       .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
-       .invert = winvert, .kcontrol_news = wcontrols, \
-       .num_kcontrols = ARRAY_SIZE(wcontrols), .event = wevent, .event_flags = wflags}
+{       .id = snd_soc_dapm_mixer, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols), \
+       .event = wevent, .event_flags = wflags}
 
 /* events that are pre and post DAPM */
 #define SND_SOC_DAPM_PRE(wname, wevent) \
@@ -199,35 +222,36 @@ struct device;
 /* stream domain */
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert }
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
                              wevent, wflags)                           \
 {      .id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert }
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
                             wevent, wflags)                            \
 {      .id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
-       .reg = wreg, .shift = wshift, .invert = winvert, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert}
+{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
 #define SND_SOC_DAPM_DAC_E(wname, stname, wreg, wshift, winvert, \
                           wevent, wflags)                              \
-{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, \
+{      .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
+
 #define SND_SOC_DAPM_ADC(wname, stname, wreg, wshift, winvert) \
-{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert}
+{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), }
 #define SND_SOC_DAPM_ADC_E(wname, stname, wreg, wshift, winvert, \
                           wevent, wflags)                              \
-{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, .reg = wreg, \
-       .shift = wshift, .invert = winvert, \
+{      .id = snd_soc_dapm_adc, .name = wname, .sname = stname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
        .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_CLOCK_SUPPLY(wname) \
 {      .id = snd_soc_dapm_clock_supply, .name = wname, \
@@ -241,14 +265,14 @@ struct device;
        .on_val = won_val, .off_val = woff_val, .event = dapm_reg_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD}
 #define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
-{      .id = snd_soc_dapm_supply, .name = wname, .reg = wreg,  \
-       .shift = wshift, .invert = winvert, .event = wevent, \
-       .event_flags = wflags}
+{      .id = snd_soc_dapm_supply, .name = wname, \
+       SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
+       .event = wevent, .event_flags = wflags}
 #define SND_SOC_DAPM_REGULATOR_SUPPLY(wname, wdelay, wflags)       \
 {      .id = snd_soc_dapm_regulator_supply, .name = wname, \
        .reg = SND_SOC_NOPM, .shift = wdelay, .event = dapm_regulator_event, \
        .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
-       .invert = wflags}
+       .on_val = wflags}
 
 
 /* dapm kcontrol types */
@@ -256,14 +280,26 @@ struct device;
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+#define SOC_DAPM_SINGLE_AUTODISABLE(xname, reg, shift, max, invert) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 1) }
 #define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
        .tlv.p = (tlv_array), \
        .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
+#define SOC_DAPM_SINGLE_TLV_AUTODISABLE(xname, reg, shift, max, invert, tlv_array) \
+{      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+       .info = snd_soc_info_volsw, \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE,\
+       .tlv.p = (tlv_array), \
+       .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 #define SOC_DAPM_ENUM(xname, xenum) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_enum_double, \
@@ -333,6 +369,7 @@ struct snd_soc_dapm_route;
 struct snd_soc_dapm_context;
 struct regulator;
 struct snd_soc_dapm_widget_list;
+struct snd_soc_dapm_update;
 
 int dapm_reg_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event);
@@ -391,10 +428,12 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
 void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* external DAPM widget events */
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-               struct snd_kcontrol *kcontrol, int connect);
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-                                struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e);
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
+               struct snd_kcontrol *kcontrol, int connect,
+               struct snd_soc_dapm_update *update);
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
+               struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
+               struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);
@@ -424,6 +463,8 @@ void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
 int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
        struct snd_soc_dapm_widget_list **list);
 
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol);
+
 /* dapm widget types */
 enum snd_soc_dapm_type {
        snd_soc_dapm_input = 0,         /* input pin */
@@ -455,6 +496,7 @@ enum snd_soc_dapm_type {
        snd_soc_dapm_dai_in,            /* link to DAI structure */
        snd_soc_dapm_dai_out,
        snd_soc_dapm_dai_link,          /* link between two DAI structures */
+       snd_soc_dapm_kcontrol,          /* Auto-disabled kcontrol */
 };
 
 enum snd_soc_dapm_subclass {
@@ -485,7 +527,6 @@ struct snd_soc_dapm_path {
        /* source (input) and sink (output) widgets */
        struct snd_soc_dapm_widget *source;
        struct snd_soc_dapm_widget *sink;
-       struct snd_kcontrol *kcontrol;
 
        /* status */
        u32 connect:1;  /* source and sink widgets are connected */
@@ -498,6 +539,7 @@ struct snd_soc_dapm_path {
 
        struct list_head list_source;
        struct list_head list_sink;
+       struct list_head list_kcontrol;
        struct list_head list;
 };
 
@@ -518,12 +560,10 @@ struct snd_soc_dapm_widget {
        /* dapm control */
        int reg;                                /* negative reg = no direct dapm */
        unsigned char shift;                    /* bits to shift */
-       unsigned int value;                             /* widget current value */
        unsigned int mask;                      /* non-shifted mask */
        unsigned int on_val;                    /* on state value */
        unsigned int off_val;                   /* off state value */
        unsigned char power:1;                  /* block power status */
-       unsigned char invert:1;                 /* invert the power bit */
        unsigned char active:1;                 /* active stream on DAC, ADC's */
        unsigned char connected:1;              /* connected codec pin */
        unsigned char new:1;                    /* cnew complete */
@@ -559,7 +599,6 @@ struct snd_soc_dapm_widget {
 };
 
 struct snd_soc_dapm_update {
-       struct snd_soc_dapm_widget *widget;
        struct snd_kcontrol *kcontrol;
        int reg;
        int mask;
@@ -573,8 +612,6 @@ struct snd_soc_dapm_context {
        struct delayed_work delayed_work;
        unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
 
-       struct snd_soc_dapm_update *update;
-
        void (*seq_notifier)(struct snd_soc_dapm_context *,
                             enum snd_soc_dapm_type, int);
 
index 04598f1..047d657 100644 (file)
@@ -133,6 +133,6 @@ void snd_soc_dpcm_be_set_state(struct snd_soc_pcm_runtime *be, int stream,
 /* internal use only */
 int soc_dpcm_be_digital_mute(struct snd_soc_pcm_runtime *fe, int mute);
 int soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
-int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *);
+int soc_dpcm_runtime_update(struct snd_soc_card *);
 
 #endif
index 6eabee7..8e2ad52 100644 (file)
 /*
  * Convenience kcontrol builders
  */
-#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \
+#define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert, xautodisable) \
        ((unsigned long)&(struct soc_mixer_control) \
        {.reg = xreg, .rreg = xreg, .shift = shift_left, \
        .rshift = shift_right, .max = xmax, .platform_max = xmax, \
-       .invert = xinvert})
-#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
-       SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert)
+       .invert = xinvert, .autodisable = xautodisable})
+#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
+       SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
 #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
        ((unsigned long)&(struct soc_mixer_control) \
        {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
@@ -52,7 +52,7 @@
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .put = snd_soc_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 #define SOC_SINGLE_RANGE(xname, xreg, xshift, xmin, xmax, xinvert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw_range, .get = snd_soc_get_volsw_range, \
@@ -68,7 +68,7 @@
        .tlv.p = (tlv_array), \
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
        .put = snd_soc_put_volsw, \
-       .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
+       .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) }
 #define SOC_SINGLE_SX_TLV(xname, xreg, xshift, xmin, xmax, tlv_array) \
 {       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@@ -97,7 +97,7 @@
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
        .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
-                                         max, invert) }
+                                         max, invert, 0) }
 #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .info = snd_soc_info_volsw, \
        .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
        .put = snd_soc_put_volsw, \
        .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
-                                         max, invert) }
+                                         max, invert, 0) }
 #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
-       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
 #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\
         xhandler_get, xhandler_put) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = \
-               SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) }
+               SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert, 0) }
 #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
        .tlv.p = (tlv_array), \
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
-       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
+       .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, 0) }
 #define SOC_DOUBLE_EXT_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .info = snd_soc_info_volsw, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \
-                                         xmax, xinvert) }
+                                         xmax, xinvert, 0) }
 #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
         xhandler_get, xhandler_put, tlv_array) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
        .private_value = xdata }
 #define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
 {      .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
-       .info = snd_soc_info_enum_ext, \
+       .info = snd_soc_info_enum_double, \
        .get = xhandler_get, .put = xhandler_put, \
        .private_value = (unsigned long)&xenum }
 
@@ -468,6 +468,8 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
 
 int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
+int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+               struct platform_device *pdev);
 
 /*
  *Controls
@@ -475,6 +477,8 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
 struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template,
                                  void *data, const char *long_name,
                                  const char *prefix);
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+                                              const char *name);
 int snd_soc_add_codec_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_add_platform_controls(struct snd_soc_platform *platform,
@@ -485,8 +489,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
        const struct snd_kcontrol_new *controls, int num_controls);
 int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
-int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo);
 int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
@@ -497,8 +499,6 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
 int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_info *uinfo);
-int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo);
 #define snd_soc_info_bool_ext          snd_ctl_boolean_mono_info
 int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol);
@@ -1042,6 +1042,7 @@ struct snd_soc_card {
        /* Generic DAPM context for the card */
        struct snd_soc_dapm_context dapm;
        struct snd_soc_dapm_stats dapm_stats;
+       struct snd_soc_dapm_update *update;
 
 #ifdef CONFIG_DEBUG_FS
        struct dentry *debugfs_card_root;
@@ -1087,7 +1088,9 @@ struct snd_soc_pcm_runtime {
 /* mixer control */
 struct soc_mixer_control {
        int min, max, platform_max;
-       unsigned int reg, rreg, shift, rshift, invert;
+       unsigned int reg, rreg, shift, rshift;
+       unsigned int invert:1;
+       unsigned int autodisable:1;
 };
 
 struct soc_bytes {
index d500369..1db453e 100644 (file)
@@ -215,8 +215,8 @@ struct fw_cdev_event_request2 {
  * with the %FW_CDEV_ISO_INTERRUPT bit set, when explicitly requested with
  * %FW_CDEV_IOC_FLUSH_ISO, or when there have been so many completed packets
  * without the interrupt bit set that the kernel's internal buffer for @header
- * is about to overflow.  (In the last case, kernels with ABI version < 5 drop
- * header data up to the next interrupt packet.)
+ * is about to overflow.  (In the last case, ABI versions < 5 drop header data
+ * up to the next interrupt packet.)
  *
  * Isochronous transmit events (context type %FW_CDEV_ISO_CONTEXT_TRANSMIT):
  *
index caed0f3..8137dd8 100644 (file)
@@ -69,8 +69,8 @@
  *     starting a poll from a device which has a secure element enabled means
  *     we want to do SE based card emulation.
  * @NFC_CMD_DISABLE_SE: Disable the physical link to a specific secure element.
- * @NFC_CMD_FW_UPLOAD: Request to Load/flash firmware, or event to inform that
- *     some firmware was loaded
+ * @NFC_CMD_FW_DOWNLOAD: Request to Load/flash firmware, or event to inform
+ *     that some firmware was loaded
  */
 enum nfc_commands {
        NFC_CMD_UNSPEC,
@@ -94,7 +94,7 @@ enum nfc_commands {
        NFC_CMD_DISABLE_SE,
        NFC_CMD_LLC_SDREQ,
        NFC_EVENT_LLC_SDRES,
-       NFC_CMD_FW_UPLOAD,
+       NFC_CMD_FW_DOWNLOAD,
        NFC_EVENT_SE_ADDED,
        NFC_EVENT_SE_REMOVED,
 /* private: internal use only */
index dbd71b0..09d62b9 100644 (file)
@@ -73,9 +73,17 @@ struct tc_estimator {
 #define TC_H_ROOT      (0xFFFFFFFFU)
 #define TC_H_INGRESS    (0xFFFFFFF1U)
 
+/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */
+enum tc_link_layer {
+       TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */
+       TC_LINKLAYER_ETHERNET,
+       TC_LINKLAYER_ATM,
+};
+#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */
+
 struct tc_ratespec {
        unsigned char   cell_log;
-       unsigned char   __reserved;
+       __u8            linklayer; /* lower 4 bits */
        unsigned short  overhead;
        short           cell_align;
        unsigned short  mpu;
index af0a674..a1356d3 100644 (file)
@@ -253,7 +253,7 @@ enum
        LINUX_MIB_TCPFASTOPENLISTENOVERFLOW,    /* TCPFastOpenListenOverflow */
        LINUX_MIB_TCPFASTOPENCOOKIEREQD,        /* TCPFastOpenCookieReqd */
        LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */
-       LINUX_MIB_LOWLATENCYRXPACKETS,          /* LowLatencyRxPackets */
+       LINUX_MIB_BUSYPOLLRXPACKETS,            /* BusyPollRxPackets */
        __LINUX_MIB_MAX
 };
 
index 470839d..35ef118 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-obj-y     = fork.o exec_domain.o panic.o printk.o \
+obj-y     = fork.o exec_domain.o panic.o \
            cpu.o exit.o itimer.o time.o softirq.o resource.o \
            sysctl.o sysctl_binary.o capability.o ptrace.o timer.o user.o \
            signal.o sys.o kmod.o workqueue.o pid.o task_work.o \
@@ -24,6 +24,7 @@ endif
 
 obj-y += sched/
 obj-y += power/
+obj-y += printk/
 obj-y += cpu/
 
 obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
index 789ec46..781845a 100644 (file)
@@ -4335,8 +4335,10 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                }
 
                err = percpu_ref_init(&css->refcnt, css_release);
-               if (err)
+               if (err) {
+                       ss->css_free(cgrp);
                        goto err_free_all;
+               }
 
                init_cgroup_css(css, ss, cgrp);
 
index e565778..010a008 100644 (file)
@@ -1608,11 +1608,13 @@ static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
 {
        struct cpuset *cs = cgroup_cs(cgrp);
        cpuset_filetype_t type = cft->private;
-       int retval = -ENODEV;
+       int retval = 0;
 
        mutex_lock(&cpuset_mutex);
-       if (!is_cpuset_online(cs))
+       if (!is_cpuset_online(cs)) {
+               retval = -ENODEV;
                goto out_unlock;
+       }
 
        switch (type) {
        case FILE_CPU_EXCLUSIVE:
index 403d2bb..e23bb19 100644 (file)
@@ -1679,6 +1679,12 @@ SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
                 int __user *, parent_tidptr,
                 int __user *, child_tidptr,
                 int, tls_val)
+#elif defined(CONFIG_CLONE_BACKWARDS3)
+SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
+               int, stack_size,
+               int __user *, parent_tidptr,
+               int __user *, child_tidptr,
+               int, tls_val)
 #else
 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
                 int __user *, parent_tidptr,
index 8b2afc1..b462fa1 100644 (file)
@@ -33,7 +33,7 @@ static DEFINE_SPINLOCK(freezer_lock);
  */
 bool freezing_slow_path(struct task_struct *p)
 {
-       if (p->flags & PF_NOFREEZE)
+       if (p->flags & (PF_NOFREEZE | PF_SUSPEND_TASK))
                return false;
 
        if (pm_nosig_freezing || cgroup_freezing(p))
index ff05f4b..a52ee7b 100644 (file)
@@ -686,7 +686,7 @@ __ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
        might_sleep();
        ret =  __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE,
                                   0, &ctx->dep_map, _RET_IP_, ctx);
-       if (!ret && ctx->acquired > 0)
+       if (!ret && ctx->acquired > 1)
                return ww_mutex_deadlock_injection(lock, ctx);
 
        return ret;
@@ -702,7 +702,7 @@ __ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx)
        ret = __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE,
                                  0, &ctx->dep_map, _RET_IP_, ctx);
 
-       if (!ret && ctx->acquired > 0)
+       if (!ret && ctx->acquired > 1)
                return ww_mutex_deadlock_injection(lock, ctx);
 
        return ret;
index fc0df84..06ec886 100644 (file)
@@ -109,6 +109,8 @@ static int try_to_freeze_tasks(bool user_only)
 
 /**
  * freeze_processes - Signal user space processes to enter the refrigerator.
+ * The current thread will not be frozen.  The same process that calls
+ * freeze_processes must later call thaw_processes.
  *
  * On success, returns 0.  On failure, -errno and system is fully thawed.
  */
@@ -120,6 +122,9 @@ int freeze_processes(void)
        if (error)
                return error;
 
+       /* Make sure this task doesn't get frozen */
+       current->flags |= PF_SUSPEND_TASK;
+
        if (!pm_freezing)
                atomic_inc(&system_freezing_cnt);
 
@@ -168,6 +173,7 @@ int freeze_kernel_threads(void)
 void thaw_processes(void)
 {
        struct task_struct *g, *p;
+       struct task_struct *curr = current;
 
        if (pm_freezing)
                atomic_dec(&system_freezing_cnt);
@@ -182,10 +188,15 @@ void thaw_processes(void)
 
        read_lock(&tasklist_lock);
        do_each_thread(g, p) {
+               /* No other threads should have PF_SUSPEND_TASK set */
+               WARN_ON((p != curr) && (p->flags & PF_SUSPEND_TASK));
                __thaw_task(p);
        } while_each_thread(g, p);
        read_unlock(&tasklist_lock);
 
+       WARN_ON(!(curr->flags & PF_SUSPEND_TASK));
+       curr->flags &= ~PF_SUSPEND_TASK;
+
        usermodehelper_enable();
 
        schedule();
index 06fe285..a394297 100644 (file)
@@ -296,6 +296,17 @@ int pm_qos_request_active(struct pm_qos_request *req)
 }
 EXPORT_SYMBOL_GPL(pm_qos_request_active);
 
+static void __pm_qos_update_request(struct pm_qos_request *req,
+                          s32 new_value)
+{
+       trace_pm_qos_update_request(req->pm_qos_class, new_value);
+
+       if (new_value != req->node.prio)
+               pm_qos_update_target(
+                       pm_qos_array[req->pm_qos_class]->constraints,
+                       &req->node, PM_QOS_UPDATE_REQ, new_value);
+}
+
 /**
  * pm_qos_work_fn - the timeout handler of pm_qos_update_request_timeout
  * @work: work struct for the delayed work (timeout)
@@ -308,7 +319,7 @@ static void pm_qos_work_fn(struct work_struct *work)
                                                  struct pm_qos_request,
                                                  work);
 
-       pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
+       __pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE);
 }
 
 /**
@@ -364,12 +375,7 @@ void pm_qos_update_request(struct pm_qos_request *req,
        }
 
        cancel_delayed_work_sync(&req->work);
-
-       trace_pm_qos_update_request(req->pm_qos_class, new_value);
-       if (new_value != req->node.prio)
-               pm_qos_update_target(
-                       pm_qos_array[req->pm_qos_class]->constraints,
-                       &req->node, PM_QOS_UPDATE_REQ, new_value);
+       __pm_qos_update_request(req, new_value);
 }
 EXPORT_SYMBOL_GPL(pm_qos_update_request);
 
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
new file mode 100644 (file)
index 0000000..85405bd
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y  = printk.o
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE)     += braille.o
diff --git a/kernel/printk/braille.c b/kernel/printk/braille.c
new file mode 100644 (file)
index 0000000..276762f
--- /dev/null
@@ -0,0 +1,49 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/string.h>
+
+#include "console_cmdline.h"
+#include "braille.h"
+
+char *_braille_console_setup(char **str, char **brl_options)
+{
+       if (!memcmp(*str, "brl,", 4)) {
+               *brl_options = "";
+               *str += 4;
+       } else if (!memcmp(str, "brl=", 4)) {
+               *brl_options = *str + 4;
+               *str = strchr(*brl_options, ',');
+               if (!*str)
+                       pr_err("need port name after brl=\n");
+               else
+                       *((*str)++) = 0;
+       } else
+               return NULL;
+
+       return *str;
+}
+
+int
+_braille_register_console(struct console *console, struct console_cmdline *c)
+{
+       int rtn = 0;
+
+       if (c->brl_options) {
+               console->flags |= CON_BRL;
+               rtn = braille_register_console(console, c->index, c->options,
+                                              c->brl_options);
+       }
+
+       return rtn;
+}
+
+int
+_braille_unregister_console(struct console *console)
+{
+       if (console->flags & CON_BRL)
+               return braille_unregister_console(console);
+
+       return 0;
+}
diff --git a/kernel/printk/braille.h b/kernel/printk/braille.h
new file mode 100644 (file)
index 0000000..769d771
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef _PRINTK_BRAILLE_H
+#define _PRINTK_BRAILLE_H
+
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+
+static inline void
+braille_set_options(struct console_cmdline *c, char *brl_options)
+{
+       c->brl_options = brl_options;
+}
+
+char *
+_braille_console_setup(char **str, char **brl_options);
+
+int
+_braille_register_console(struct console *console, struct console_cmdline *c);
+
+int
+_braille_unregister_console(struct console *console);
+
+#else
+
+static inline void
+braille_set_options(struct console_cmdline *c, char *brl_options)
+{
+}
+
+static inline char *
+_braille_console_setup(char **str, char **brl_options)
+{
+       return NULL;
+}
+
+static inline int
+_braille_register_console(struct console *console, struct console_cmdline *c)
+{
+       return 0;
+}
+
+static inline int
+_braille_unregister_console(struct console *console)
+{
+       return 0;
+}
+
+#endif
+
+#endif
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
new file mode 100644 (file)
index 0000000..cbd69d8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _CONSOLE_CMDLINE_H
+#define _CONSOLE_CMDLINE_H
+
+struct console_cmdline
+{
+       char    name[8];                        /* Name of the driver       */
+       int     index;                          /* Minor dev. to use        */
+       char    *options;                       /* Options for the driver   */
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+       char    *brl_options;                   /* Options for braille driver */
+#endif
+};
+
+#endif
similarity index 95%
rename from kernel/printk.c
rename to kernel/printk/printk.c
index 69b0890..5b5a708 100644 (file)
@@ -51,6 +51,9 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/printk.h>
 
+#include "console_cmdline.h"
+#include "braille.h"
+
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL CONFIG_DEFAULT_MESSAGE_LOGLEVEL
 
@@ -105,19 +108,11 @@ static struct console *exclusive_console;
 /*
  *     Array of consoles built from command line options (console=)
  */
-struct console_cmdline
-{
-       char    name[8];                        /* Name of the driver       */
-       int     index;                          /* Minor dev. to use        */
-       char    *options;                       /* Options for the driver   */
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       char    *brl_options;                   /* Options for braille driver */
-#endif
-};
 
 #define MAX_CMDLINECONSOLES 8
 
 static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];
+
 static int selected_console = -1;
 static int preferred_console = -1;
 int console_set_on_cmdline;
@@ -178,7 +173,7 @@ static int console_may_schedule;
  *         67                           "g"
  *   0032     00 00 00                  padding to next message header
  *
- * The 'struct log' buffer header must never be directly exported to
+ * The 'struct printk_log' buffer header must never be directly exported to
  * userspace, it is a kernel-private implementation detail that might
  * need to be changed in the future, when the requirements change.
  *
@@ -200,7 +195,7 @@ enum log_flags {
        LOG_CONT        = 8,    /* text is a fragment of a continuation line */
 };
 
-struct log {
+struct printk_log {
        u64 ts_nsec;            /* timestamp in nanoseconds */
        u16 len;                /* length of entire record */
        u16 text_len;           /* length of text buffer */
@@ -248,7 +243,7 @@ static u32 clear_idx;
 #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
 #define LOG_ALIGN 4
 #else
-#define LOG_ALIGN __alignof__(struct log)
+#define LOG_ALIGN __alignof__(struct printk_log)
 #endif
 #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT)
 static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
@@ -259,35 +254,35 @@ static u32 log_buf_len = __LOG_BUF_LEN;
 static volatile unsigned int logbuf_cpu = UINT_MAX;
 
 /* human readable text of the record */
-static char *log_text(const struct log *msg)
+static char *log_text(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log);
+       return (char *)msg + sizeof(struct printk_log);
 }
 
 /* optional key/value pair dictionary attached to the record */
-static char *log_dict(const struct log *msg)
+static char *log_dict(const struct printk_log *msg)
 {
-       return (char *)msg + sizeof(struct log) + msg->text_len;
+       return (char *)msg + sizeof(struct printk_log) + msg->text_len;
 }
 
 /* get record by index; idx must point to valid msg */
-static struct log *log_from_idx(u32 idx)
+static struct printk_log *log_from_idx(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /*
         * A length == 0 record is the end of buffer marker. Wrap around and
         * read the message at the start of the buffer.
         */
        if (!msg->len)
-               return (struct log *)log_buf;
+               return (struct printk_log *)log_buf;
        return msg;
 }
 
 /* get next record; idx must point to valid msg */
 static u32 log_next(u32 idx)
 {
-       struct log *msg = (struct log *)(log_buf + idx);
+       struct printk_log *msg = (struct printk_log *)(log_buf + idx);
 
        /* length == 0 indicates the end of the buffer; wrap */
        /*
@@ -296,7 +291,7 @@ static u32 log_next(u32 idx)
         * return the one after that.
         */
        if (!msg->len) {
-               msg = (struct log *)log_buf;
+               msg = (struct printk_log *)log_buf;
                return msg->len;
        }
        return idx + msg->len;
@@ -308,11 +303,11 @@ static void log_store(int facility, int level,
                      const char *dict, u16 dict_len,
                      const char *text, u16 text_len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        u32 size, pad_len;
 
        /* number of '\0' padding bytes to next message */
-       size = sizeof(struct log) + text_len + dict_len;
+       size = sizeof(struct printk_log) + text_len + dict_len;
        pad_len = (-size) & (LOG_ALIGN - 1);
        size += pad_len;
 
@@ -324,7 +319,7 @@ static void log_store(int facility, int level,
                else
                        free = log_first_idx - log_next_idx;
 
-               if (free > size + sizeof(struct log))
+               if (free > size + sizeof(struct printk_log))
                        break;
 
                /* drop old messages until we have enough contiuous space */
@@ -332,18 +327,18 @@ static void log_store(int facility, int level,
                log_first_seq++;
        }
 
-       if (log_next_idx + size + sizeof(struct log) >= log_buf_len) {
+       if (log_next_idx + size + sizeof(struct printk_log) >= log_buf_len) {
                /*
                 * This message + an additional empty header does not fit
                 * at the end of the buffer. Add an empty header with len == 0
                 * to signify a wrap around.
                 */
-               memset(log_buf + log_next_idx, 0, sizeof(struct log));
+               memset(log_buf + log_next_idx, 0, sizeof(struct printk_log));
                log_next_idx = 0;
        }
 
        /* fill message */
-       msg = (struct log *)(log_buf + log_next_idx);
+       msg = (struct printk_log *)(log_buf + log_next_idx);
        memcpy(log_text(msg), text, text_len);
        msg->text_len = text_len;
        memcpy(log_dict(msg), dict, dict_len);
@@ -356,7 +351,7 @@ static void log_store(int facility, int level,
        else
                msg->ts_nsec = local_clock();
        memset(log_dict(msg) + dict_len, 0, pad_len);
-       msg->len = sizeof(struct log) + text_len + dict_len + pad_len;
+       msg->len = sizeof(struct printk_log) + text_len + dict_len + pad_len;
 
        /* insert message */
        log_next_idx += msg->len;
@@ -479,7 +474,7 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
                            size_t count, loff_t *ppos)
 {
        struct devkmsg_user *user = file->private_data;
-       struct log *msg;
+       struct printk_log *msg;
        u64 ts_usec;
        size_t i;
        char cont = '-';
@@ -724,14 +719,14 @@ void log_buf_kexec_setup(void)
        VMCOREINFO_SYMBOL(log_first_idx);
        VMCOREINFO_SYMBOL(log_next_idx);
        /*
-        * Export struct log size and field offsets. User space tools can
+        * Export struct printk_log size and field offsets. User space tools can
         * parse it and detect any changes to structure down the line.
         */
-       VMCOREINFO_STRUCT_SIZE(log);
-       VMCOREINFO_OFFSET(log, ts_nsec);
-       VMCOREINFO_OFFSET(log, len);
-       VMCOREINFO_OFFSET(log, text_len);
-       VMCOREINFO_OFFSET(log, dict_len);
+       VMCOREINFO_STRUCT_SIZE(printk_log);
+       VMCOREINFO_OFFSET(printk_log, ts_nsec);
+       VMCOREINFO_OFFSET(printk_log, len);
+       VMCOREINFO_OFFSET(printk_log, text_len);
+       VMCOREINFO_OFFSET(printk_log, dict_len);
 }
 #endif
 
@@ -884,7 +879,7 @@ static size_t print_time(u64 ts, char *buf)
                       (unsigned long)ts, rem_nsec / 1000);
 }
 
-static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
+static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf)
 {
        size_t len = 0;
        unsigned int prefix = (msg->facility << 3) | msg->level;
@@ -907,7 +902,7 @@ static size_t print_prefix(const struct log *msg, bool syslog, char *buf)
        return len;
 }
 
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size)
 {
        const char *text = log_text(msg);
@@ -969,7 +964,7 @@ static size_t msg_print_text(const struct log *msg, enum log_flags prev,
 static int syslog_print(char __user *buf, int size)
 {
        char *text;
-       struct log *msg;
+       struct printk_log *msg;
        int len = 0;
 
        text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL);
@@ -1060,7 +1055,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len += msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1073,7 +1068,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                idx = clear_idx;
                prev = 0;
                while (len > size && seq < log_next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
 
                        len -= msg_print_text(msg, prev, true, NULL, 0);
                        prev = msg->flags;
@@ -1087,7 +1082,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                len = 0;
                prev = 0;
                while (len >= 0 && seq < next_seq) {
-                       struct log *msg = log_from_idx(idx);
+                       struct printk_log *msg = log_from_idx(idx);
                        int textlen;
 
                        textlen = msg_print_text(msg, prev, true, text,
@@ -1233,7 +1228,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
 
                        error = 0;
                        while (seq < log_next_seq) {
-                               struct log *msg = log_from_idx(idx);
+                               struct printk_log *msg = log_from_idx(idx);
 
                                error += msg_print_text(msg, prev, true, NULL, 0);
                                idx = log_next(idx);
@@ -1719,10 +1714,10 @@ static struct cont {
        u8 level;
        bool flushed:1;
 } cont;
-static struct log *log_from_idx(u32 idx) { return NULL; }
+static struct printk_log *log_from_idx(u32 idx) { return NULL; }
 static u32 log_next(u32 idx) { return 0; }
 static void call_console_drivers(int level, const char *text, size_t len) {}
-static size_t msg_print_text(const struct log *msg, enum log_flags prev,
+static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
                             bool syslog, char *buf, size_t size) { return 0; }
 static size_t cont_print_text(char *text, size_t size) { return 0; }
 
@@ -1761,23 +1756,23 @@ static int __add_preferred_console(char *name, int idx, char *options,
         *      See if this tty is not yet registered, and
         *      if we have a slot free.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               if (!brl_options)
-                                       selected_console = i;
-                               return 0;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       if (!brl_options)
+                               selected_console = i;
+                       return 0;
                }
+       }
        if (i == MAX_CMDLINECONSOLES)
                return -E2BIG;
        if (!brl_options)
                selected_console = i;
-       c = &console_cmdline[i];
        strlcpy(c->name, name, sizeof(c->name));
        c->options = options;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       c->brl_options = brl_options;
-#endif
+       braille_set_options(c, brl_options);
+
        c->index = idx;
        return 0;
 }
@@ -1790,20 +1785,8 @@ static int __init console_setup(char *str)
        char *s, *options, *brl_options = NULL;
        int idx;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (!memcmp(str, "brl,", 4)) {
-               brl_options = "";
-               str += 4;
-       } else if (!memcmp(str, "brl=", 4)) {
-               brl_options = str + 4;
-               str = strchr(brl_options, ',');
-               if (!str) {
-                       printk(KERN_ERR "need port name after brl=\n");
-                       return 1;
-               }
-               *(str++) = 0;
-       }
-#endif
+       if (_braille_console_setup(&str, &brl_options))
+               return 1;
 
        /*
         * Decode str into name, index, options.
@@ -1858,15 +1841,15 @@ int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, cha
        struct console_cmdline *c;
        int i;
 
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
-               if (strcmp(console_cmdline[i].name, name) == 0 &&
-                         console_cmdline[i].index == idx) {
-                               c = &console_cmdline[i];
-                               strlcpy(c->name, name_new, sizeof(c->name));
-                               c->name[sizeof(c->name) - 1] = 0;
-                               c->options = options;
-                               c->index = idx_new;
-                               return i;
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++)
+               if (strcmp(c->name, name) == 0 && c->index == idx) {
+                       strlcpy(c->name, name_new, sizeof(c->name));
+                       c->name[sizeof(c->name) - 1] = 0;
+                       c->options = options;
+                       c->index = idx_new;
+                       return i;
                }
        /* not found */
        return -1;
@@ -2046,7 +2029,7 @@ void console_unlock(void)
        console_cont_flush(text, sizeof(text));
 again:
        for (;;) {
-               struct log *msg;
+               struct printk_log *msg;
                size_t len;
                int level;
 
@@ -2241,6 +2224,7 @@ void register_console(struct console *newcon)
        int i;
        unsigned long flags;
        struct console *bcon = NULL;
+       struct console_cmdline *c;
 
        /*
         * before we register a new CON_BOOT console, make sure we don't
@@ -2288,30 +2272,25 @@ void register_console(struct console *newcon)
         *      See if this console matches one we selected on
         *      the command line.
         */
-       for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0];
-                       i++) {
-               if (strcmp(console_cmdline[i].name, newcon->name) != 0)
+       for (i = 0, c = console_cmdline;
+            i < MAX_CMDLINECONSOLES && c->name[0];
+            i++, c++) {
+               if (strcmp(c->name, newcon->name) != 0)
                        continue;
                if (newcon->index >= 0 &&
-                   newcon->index != console_cmdline[i].index)
+                   newcon->index != c->index)
                        continue;
                if (newcon->index < 0)
-                       newcon->index = console_cmdline[i].index;
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-               if (console_cmdline[i].brl_options) {
-                       newcon->flags |= CON_BRL;
-                       braille_register_console(newcon,
-                                       console_cmdline[i].index,
-                                       console_cmdline[i].options,
-                                       console_cmdline[i].brl_options);
+                       newcon->index = c->index;
+
+               if (_braille_register_console(newcon, c))
                        return;
-               }
-#endif
+
                if (newcon->setup &&
                    newcon->setup(newcon, console_cmdline[i].options) != 0)
                        break;
                newcon->flags |= CON_ENABLED;
-               newcon->index = console_cmdline[i].index;
+               newcon->index = c->index;
                if (i == selected_console) {
                        newcon->flags |= CON_CONSDEV;
                        preferred_console = selected_console;
@@ -2394,13 +2373,13 @@ EXPORT_SYMBOL(register_console);
 int unregister_console(struct console *console)
 {
         struct console *a, *b;
-       int res = 1;
+       int res;
 
-#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
-       if (console->flags & CON_BRL)
-               return braille_unregister_console(console);
-#endif
+       res = _braille_unregister_console(console);
+       if (res)
+               return res;
 
+       res = 1;
        console_lock();
        if (console_drivers == console) {
                console_drivers=console->next;
@@ -2666,7 +2645,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
 bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
                               char *line, size_t size, size_t *len)
 {
-       struct log *msg;
+       struct printk_log *msg;
        size_t l = 0;
        bool ret = false;
 
@@ -2778,7 +2757,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2791,7 +2770,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        idx = dumper->cur_idx;
        prev = 0;
        while (l > size && seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l -= msg_print_text(msg, prev, true, NULL, 0);
                idx = log_next(idx);
@@ -2806,7 +2785,7 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
        l = 0;
        prev = 0;
        while (seq < dumper->next_seq) {
-               struct log *msg = log_from_idx(idx);
+               struct printk_log *msg = log_from_idx(idx);
 
                l += msg_print_text(msg, prev, syslog, buf + l, size - l);
                idx = log_next(idx);
index 4041f57..a146ee3 100644 (file)
@@ -469,7 +469,6 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
        /* Architecture-specific hardware disable .. */
        ptrace_disable(child);
        clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
-       flush_ptrace_hw_breakpoint(child);
 
        write_lock_irq(&tasklist_lock);
        /*
index b7c32cb..05c39f0 100644 (file)
@@ -933,6 +933,8 @@ static int effective_prio(struct task_struct *p)
 /**
  * task_curr - is this task currently executing on a CPU?
  * @p: the task in question.
+ *
+ * Return: 1 if the task is currently executing. 0 otherwise.
  */
 inline int task_curr(const struct task_struct *p)
 {
@@ -1482,7 +1484,7 @@ static void ttwu_queue(struct task_struct *p, int cpu)
  * the simpler "current->state = TASK_RUNNING" to mark yourself
  * runnable without the overhead of this.
  *
- * Returns %true if @p was woken up, %false if it was already running
+ * Return: %true if @p was woken up, %false if it was already running.
  * or @state didn't match @p's state.
  */
 static int
@@ -1491,7 +1493,13 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
        unsigned long flags;
        int cpu, success = 0;
 
-       smp_wmb();
+       /*
+        * If we are going to wake up a thread waiting for CONDITION we
+        * need to ensure that CONDITION=1 done by the caller can not be
+        * reordered with p->state check below. This pairs with mb() in
+        * set_current_state() the waiting thread does.
+        */
+       smp_mb__before_spinlock();
        raw_spin_lock_irqsave(&p->pi_lock, flags);
        if (!(p->state & state))
                goto out;
@@ -1577,8 +1585,9 @@ out:
  * @p: The process to be woken up.
  *
  * Attempt to wake up the nominated process and move it to the set of runnable
- * processes.  Returns 1 if the process was woken up, 0 if it was already
- * running.
+ * processes.
+ *
+ * Return: 1 if the process was woken up, 0 if it was already running.
  *
  * It may be assumed that this function implies a write memory barrier before
  * changing the task state if and only if any tasks are woken up.
@@ -2191,6 +2200,8 @@ void scheduler_tick(void)
  * This makes sure that uptime, CFS vruntime, load
  * balancing, etc... continue to move forward, even
  * with a very low granularity.
+ *
+ * Return: Maximum deferment in nanoseconds.
  */
 u64 scheduler_tick_max_deferment(void)
 {
@@ -2394,6 +2405,12 @@ need_resched:
        if (sched_feat(HRTICK))
                hrtick_clear(rq);
 
+       /*
+        * Make sure that signal_pending_state()->signal_pending() below
+        * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
+        * done by the caller to avoid the race with signal_wake_up().
+        */
+       smp_mb__before_spinlock();
        raw_spin_lock_irq(&rq->lock);
 
        switch_count = &prev->nivcsw;
@@ -2796,8 +2813,8 @@ EXPORT_SYMBOL(wait_for_completion);
  * specified timeout to expire. The timeout is in jiffies. It is not
  * interruptible.
  *
- * The return value is 0 if timed out, and positive (at least 1, or number of
- * jiffies left till timeout) if completed.
+ * Return: 0 if timed out, and positive (at least 1, or number of jiffies left
+ * till timeout) if completed.
  */
 unsigned long __sched
 wait_for_completion_timeout(struct completion *x, unsigned long timeout)
@@ -2829,8 +2846,8 @@ EXPORT_SYMBOL(wait_for_completion_io);
  * specified timeout to expire. The timeout is in jiffies. It is not
  * interruptible. The caller is accounted as waiting for IO.
  *
- * The return value is 0 if timed out, and positive (at least 1, or number of
- * jiffies left till timeout) if completed.
+ * Return: 0 if timed out, and positive (at least 1, or number of jiffies left
+ * till timeout) if completed.
  */
 unsigned long __sched
 wait_for_completion_io_timeout(struct completion *x, unsigned long timeout)
@@ -2846,7 +2863,7 @@ EXPORT_SYMBOL(wait_for_completion_io_timeout);
  * This waits for completion of a specific task to be signaled. It is
  * interruptible.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if completed.
  */
 int __sched wait_for_completion_interruptible(struct completion *x)
 {
@@ -2865,8 +2882,8 @@ EXPORT_SYMBOL(wait_for_completion_interruptible);
  * This waits for either a completion of a specific task to be signaled or for a
  * specified timeout to expire. It is interruptible. The timeout is in jiffies.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if timed out,
- * positive (at least 1, or number of jiffies left till timeout) if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1,
+ * or number of jiffies left till timeout) if completed.
  */
 long __sched
 wait_for_completion_interruptible_timeout(struct completion *x,
@@ -2883,7 +2900,7 @@ EXPORT_SYMBOL(wait_for_completion_interruptible_timeout);
  * This waits to be signaled for completion of a specific task. It can be
  * interrupted by a kill signal.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if completed.
  */
 int __sched wait_for_completion_killable(struct completion *x)
 {
@@ -2903,8 +2920,8 @@ EXPORT_SYMBOL(wait_for_completion_killable);
  * signaled or for a specified timeout to expire. It can be
  * interrupted by a kill signal. The timeout is in jiffies.
  *
- * The return value is -ERESTARTSYS if interrupted, 0 if timed out,
- * positive (at least 1, or number of jiffies left till timeout) if completed.
+ * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1,
+ * or number of jiffies left till timeout) if completed.
  */
 long __sched
 wait_for_completion_killable_timeout(struct completion *x,
@@ -2918,7 +2935,7 @@ EXPORT_SYMBOL(wait_for_completion_killable_timeout);
  *     try_wait_for_completion - try to decrement a completion without blocking
  *     @x:     completion structure
  *
- *     Returns: 0 if a decrement cannot be done without blocking
+ *     Return: 0 if a decrement cannot be done without blocking
  *              1 if a decrement succeeded.
  *
  *     If a completion is being used as a counting completion,
@@ -2945,7 +2962,7 @@ EXPORT_SYMBOL(try_wait_for_completion);
  *     completion_done - Test to see if a completion has any waiters
  *     @x:     completion structure
  *
- *     Returns: 0 if there are waiters (wait_for_completion() in progress)
+ *     Return: 0 if there are waiters (wait_for_completion() in progress)
  *              1 if there are no waiters.
  *
  */
@@ -3182,7 +3199,7 @@ SYSCALL_DEFINE1(nice, int, increment)
  * task_prio - return the priority value of a given task.
  * @p: the task in question.
  *
- * This is the priority value as seen by users in /proc.
+ * Return: The priority value as seen by users in /proc.
  * RT tasks are offset by -200. Normal tasks are centered
  * around 0, value goes from -16 to +15.
  */
@@ -3194,6 +3211,8 @@ int task_prio(const struct task_struct *p)
 /**
  * task_nice - return the nice value of a given task.
  * @p: the task in question.
+ *
+ * Return: The nice value [ -20 ... 0 ... 19 ].
  */
 int task_nice(const struct task_struct *p)
 {
@@ -3204,6 +3223,8 @@ EXPORT_SYMBOL(task_nice);
 /**
  * idle_cpu - is a given cpu idle currently?
  * @cpu: the processor in question.
+ *
+ * Return: 1 if the CPU is currently idle. 0 otherwise.
  */
 int idle_cpu(int cpu)
 {
@@ -3226,6 +3247,8 @@ int idle_cpu(int cpu)
 /**
  * idle_task - return the idle task for a given cpu.
  * @cpu: the processor in question.
+ *
+ * Return: The idle task for the cpu @cpu.
  */
 struct task_struct *idle_task(int cpu)
 {
@@ -3235,6 +3258,8 @@ struct task_struct *idle_task(int cpu)
 /**
  * find_process_by_pid - find a process with a matching PID value.
  * @pid: the pid in question.
+ *
+ * The task of @pid, if found. %NULL otherwise.
  */
 static struct task_struct *find_process_by_pid(pid_t pid)
 {
@@ -3432,6 +3457,8 @@ recheck:
  * @policy: new policy.
  * @param: structure containing the new RT priority.
  *
+ * Return: 0 on success. An error code otherwise.
+ *
  * NOTE that the task may be already dead.
  */
 int sched_setscheduler(struct task_struct *p, int policy,
@@ -3451,6 +3478,8 @@ EXPORT_SYMBOL_GPL(sched_setscheduler);
  * current context has permission.  For example, this is needed in
  * stop_machine(): we create temporary high priority worker threads,
  * but our caller might not have that capability.
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 int sched_setscheduler_nocheck(struct task_struct *p, int policy,
                               const struct sched_param *param)
@@ -3485,6 +3514,8 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
  * @pid: the pid in question.
  * @policy: new policy.
  * @param: structure containing the new RT priority.
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy,
                struct sched_param __user *, param)
@@ -3500,6 +3531,8 @@ SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy,
  * sys_sched_setparam - set/change the RT priority of a thread
  * @pid: the pid in question.
  * @param: structure containing the new RT priority.
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
 {
@@ -3509,6 +3542,9 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)
 /**
  * sys_sched_getscheduler - get the policy (scheduling class) of a thread
  * @pid: the pid in question.
+ *
+ * Return: On success, the policy of the thread. Otherwise, a negative error
+ * code.
  */
 SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
 {
@@ -3535,6 +3571,9 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)
  * sys_sched_getparam - get the RT priority of a thread
  * @pid: the pid in question.
  * @param: structure containing the RT priority.
+ *
+ * Return: On success, 0 and the RT priority is in @param. Otherwise, an error
+ * code.
  */
 SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)
 {
@@ -3659,6 +3698,8 @@ static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len,
  * @pid: pid of the process
  * @len: length in bytes of the bitmask pointed to by user_mask_ptr
  * @user_mask_ptr: user-space pointer to the new cpu mask
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len,
                unsigned long __user *, user_mask_ptr)
@@ -3710,6 +3751,8 @@ out_unlock:
  * @pid: pid of the process
  * @len: length in bytes of the bitmask pointed to by user_mask_ptr
  * @user_mask_ptr: user-space pointer to hold the current cpu mask
+ *
+ * Return: 0 on success. An error code otherwise.
  */
 SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
                unsigned long __user *, user_mask_ptr)
@@ -3744,6 +3787,8 @@ SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len,
  *
  * This function yields the current CPU to other tasks. If there are no
  * other threads running on this CPU then this function will return.
+ *
+ * Return: 0.
  */
 SYSCALL_DEFINE0(sched_yield)
 {
@@ -3869,7 +3914,7 @@ EXPORT_SYMBOL(yield);
  * It's the caller's job to ensure that the target task struct
  * can't go away on us before we can do any checks.
  *
- * Returns:
+ * Return:
  *     true (>0) if we indeed boosted the target task.
  *     false (0) if we failed to boost the target.
  *     -ESRCH if there's no task to yield to.
@@ -3972,8 +4017,9 @@ long __sched io_schedule_timeout(long timeout)
  * sys_sched_get_priority_max - return maximum RT priority.
  * @policy: scheduling class.
  *
- * this syscall returns the maximum rt_priority that can be used
- * by a given scheduling class.
+ * Return: On success, this syscall returns the maximum
+ * rt_priority that can be used by a given scheduling class.
+ * On failure, a negative error code is returned.
  */
 SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
 {
@@ -3997,8 +4043,9 @@ SYSCALL_DEFINE1(sched_get_priority_max, int, policy)
  * sys_sched_get_priority_min - return minimum RT priority.
  * @policy: scheduling class.
  *
- * this syscall returns the minimum rt_priority that can be used
- * by a given scheduling class.
+ * Return: On success, this syscall returns the minimum
+ * rt_priority that can be used by a given scheduling class.
+ * On failure, a negative error code is returned.
  */
 SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
 {
@@ -4024,6 +4071,9 @@ SYSCALL_DEFINE1(sched_get_priority_min, int, policy)
  *
  * this syscall writes the default timeslice value of a given process
  * into the user-space timespec buffer. A value of '0' means infinity.
+ *
+ * Return: On success, 0 and the timeslice is in @interval. Otherwise,
+ * an error code.
  */
 SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
                struct timespec __user *, interval)
@@ -6632,6 +6682,8 @@ void normalize_rt_tasks(void)
  * @cpu: the processor in question.
  *
  * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED!
+ *
+ * Return: The current task for @cpu.
  */
 struct task_struct *curr_task(int cpu)
 {
index 1095e87..8b836b3 100644 (file)
@@ -62,7 +62,7 @@ static int convert_prio(int prio)
  * any discrepancies created by racing against the uncertainty of the current
  * priority configuration.
  *
- * Returns: (int)bool - CPUs were found
+ * Return: (int)bool - CPUs were found
  */
 int cpupri_find(struct cpupri *cp, struct task_struct *p,
                struct cpumask *lowest_mask)
@@ -203,7 +203,7 @@ void cpupri_set(struct cpupri *cp, int cpu, int newpri)
  * cpupri_init - initialize the cpupri structure
  * @cp: The cpupri context
  *
- * Returns: -ENOMEM if memory fails.
+ * Return: -ENOMEM on memory allocation failure.
  */
 int cpupri_init(struct cpupri *cp)
 {
index bb456f4..68f1609 100644 (file)
@@ -851,7 +851,7 @@ void task_numa_fault(int node, int pages, bool migrated)
 {
        struct task_struct *p = current;
 
-       if (!sched_feat_numa(NUMA))
+       if (!numabalancing_enabled)
                return;
 
        /* FIXME: Allocate task-specific structure for placement policy here */
@@ -2032,6 +2032,7 @@ entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
         */
        update_entity_load_avg(curr, 1);
        update_cfs_rq_blocked_load(cfs_rq, 1);
+       update_cfs_shares(cfs_rq);
 
 #ifdef CONFIG_SCHED_HRTICK
        /*
@@ -4280,6 +4281,8 @@ struct sg_lb_stats {
  * get_sd_load_idx - Obtain the load index for a given sched domain.
  * @sd: The sched_domain whose load_idx is to be obtained.
  * @idle: The Idle status of the CPU for whose sd load_icx is obtained.
+ *
+ * Return: The load index.
  */
 static inline int get_sd_load_idx(struct sched_domain *sd,
                                        enum cpu_idle_type idle)
@@ -4574,6 +4577,9 @@ static inline void update_sg_lb_stats(struct lb_env *env,
  *
  * Determine if @sg is a busier group than the previously selected
  * busiest group.
+ *
+ * Return: %true if @sg is a busier group than the previously selected
+ * busiest group. %false otherwise.
  */
 static bool update_sd_pick_busiest(struct lb_env *env,
                                   struct sd_lb_stats *sds,
@@ -4691,7 +4697,7 @@ static inline void update_sd_lb_stats(struct lb_env *env,
  * assuming lower CPU number will be equivalent to lower a SMT thread
  * number.
  *
- * Returns 1 when packing is required and a task should be moved to
+ * Return: 1 when packing is required and a task should be moved to
  * this CPU.  The amount of the imbalance is returned in *imbalance.
  *
  * @env: The load balancing environment.
@@ -4869,7 +4875,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
  * @balance: Pointer to a variable indicating if this_cpu
  *     is the appropriate cpu to perform load balancing at this_level.
  *
- * Returns:    - the busiest group if imbalance exists.
+ * Return:     - The busiest group if imbalance exists.
  *             - If no imbalance and user has opted for power-savings balance,
  *                return the least loaded group whose CPUs can be
  *                put to idle by rebalancing its tasks onto our group.
@@ -5786,7 +5792,7 @@ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
                entity_tick(cfs_rq, se, queued);
        }
 
-       if (sched_feat_numa(NUMA))
+       if (numabalancing_enabled)
                task_tick_numa(rq, curr);
 
        update_rq_runnable_avg(rq, 1);
index ac09d98..07f6fc4 100644 (file)
@@ -2346,7 +2346,11 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
                                            int write, void *data)
 {
        if (write) {
-               *valp = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
+               unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp);
+
+               if (jif > INT_MAX)
+                       return 1;
+               *valp = (int)jif;
        } else {
                int val = *valp;
                unsigned long lval;
index e80183f..e77edc9 100644 (file)
@@ -827,13 +827,10 @@ void tick_nohz_irq_exit(void)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
 
-       if (ts->inidle) {
-               /* Cancel the timer because CPU already waken up from the C-states*/
-               menu_hrtimer_cancel();
+       if (ts->inidle)
                __tick_nohz_idle_enter(ts);
-       } else {
+       else
                tick_nohz_full_stop_tick(ts);
-       }
 }
 
 /**
@@ -931,8 +928,6 @@ void tick_nohz_idle_exit(void)
 
        ts->inidle = 0;
 
-       /* Cancel the timer because CPU already waken up from the C-states*/
-       menu_hrtimer_cancel();
        if (ts->idle_active || ts->tick_stopped)
                now = ktime_get();
 
index 8ce9eef..a6d098c 100644 (file)
@@ -2169,12 +2169,57 @@ static cycle_t          ftrace_update_time;
 static unsigned long   ftrace_update_cnt;
 unsigned long          ftrace_update_tot_cnt;
 
-static int ops_traces_mod(struct ftrace_ops *ops)
+static inline int ops_traces_mod(struct ftrace_ops *ops)
 {
-       struct ftrace_hash *hash;
+       /*
+        * Filter_hash being empty will default to trace module.
+        * But notrace hash requires a test of individual module functions.
+        */
+       return ftrace_hash_empty(ops->filter_hash) &&
+               ftrace_hash_empty(ops->notrace_hash);
+}
+
+/*
+ * Check if the current ops references the record.
+ *
+ * If the ops traces all functions, then it was already accounted for.
+ * If the ops does not trace the current record function, skip it.
+ * If the ops ignores the function via notrace filter, skip it.
+ */
+static inline bool
+ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec)
+{
+       /* If ops isn't enabled, ignore it */
+       if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+               return 0;
+
+       /* If ops traces all mods, we already accounted for it */
+       if (ops_traces_mod(ops))
+               return 0;
+
+       /* The function must be in the filter */
+       if (!ftrace_hash_empty(ops->filter_hash) &&
+           !ftrace_lookup_ip(ops->filter_hash, rec->ip))
+               return 0;
+
+       /* If in notrace hash, we ignore it too */
+       if (ftrace_lookup_ip(ops->notrace_hash, rec->ip))
+               return 0;
+
+       return 1;
+}
+
+static int referenced_filters(struct dyn_ftrace *rec)
+{
+       struct ftrace_ops *ops;
+       int cnt = 0;
 
-       hash = ops->filter_hash;
-       return ftrace_hash_empty(hash);
+       for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) {
+               if (ops_references_rec(ops, rec))
+                   cnt++;
+       }
+
+       return cnt;
 }
 
 static int ftrace_update_code(struct module *mod)
@@ -2183,6 +2228,7 @@ static int ftrace_update_code(struct module *mod)
        struct dyn_ftrace *p;
        cycle_t start, stop;
        unsigned long ref = 0;
+       bool test = false;
        int i;
 
        /*
@@ -2196,9 +2242,12 @@ static int ftrace_update_code(struct module *mod)
 
                for (ops = ftrace_ops_list;
                     ops != &ftrace_list_end; ops = ops->next) {
-                       if (ops->flags & FTRACE_OPS_FL_ENABLED &&
-                           ops_traces_mod(ops))
-                               ref++;
+                       if (ops->flags & FTRACE_OPS_FL_ENABLED) {
+                               if (ops_traces_mod(ops))
+                                       ref++;
+                               else
+                                       test = true;
+                       }
                }
        }
 
@@ -2208,12 +2257,16 @@ static int ftrace_update_code(struct module *mod)
        for (pg = ftrace_new_pgs; pg; pg = pg->next) {
 
                for (i = 0; i < pg->index; i++) {
+                       int cnt = ref;
+
                        /* If something went wrong, bail without enabling anything */
                        if (unlikely(ftrace_disabled))
                                return -1;
 
                        p = &pg->records[i];
-                       p->flags = ref;
+                       if (test)
+                               cnt += referenced_filters(p);
+                       p->flags = cnt;
 
                        /*
                         * Do the initial record conversion from mcount jump
@@ -2233,7 +2286,7 @@ static int ftrace_update_code(struct module *mod)
                         * conversion puts the module to the correct state, thus
                         * passing the ftrace_make_call check.
                         */
-                       if (ftrace_start_up && ref) {
+                       if (ftrace_start_up && cnt) {
                                int failed = __ftrace_replace_code(p, 1);
                                if (failed)
                                        ftrace_bug(failed, p->ip);
@@ -3384,6 +3437,12 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
        return add_hash_entry(hash, ip);
 }
 
+static void ftrace_ops_update_code(struct ftrace_ops *ops)
+{
+       if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
+               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+}
+
 static int
 ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
                unsigned long ip, int remove, int reset, int enable)
@@ -3426,9 +3485,8 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 
        mutex_lock(&ftrace_lock);
        ret = ftrace_hash_move(ops, enable, orig_hash, hash);
-       if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED
-           && ftrace_enabled)
-               ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+       if (!ret)
+               ftrace_ops_update_code(ops);
 
        mutex_unlock(&ftrace_lock);
 
@@ -3655,9 +3713,8 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
                mutex_lock(&ftrace_lock);
                ret = ftrace_hash_move(iter->ops, filter_hash,
                                       orig_hash, iter->hash);
-               if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED)
-                   && ftrace_enabled)
-                       ftrace_run_update_code(FTRACE_UPDATE_CALLS);
+               if (!ret)
+                       ftrace_ops_update_code(iter->ops);
 
                mutex_unlock(&ftrace_lock);
        }
index 882ec1d..496f94d 100644 (file)
@@ -243,20 +243,25 @@ int filter_current_check_discard(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(filter_current_check_discard);
 
-cycle_t ftrace_now(int cpu)
+cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu)
 {
        u64 ts;
 
        /* Early boot up does not have a buffer yet */
-       if (!global_trace.trace_buffer.buffer)
+       if (!buf->buffer)
                return trace_clock_local();
 
-       ts = ring_buffer_time_stamp(global_trace.trace_buffer.buffer, cpu);
-       ring_buffer_normalize_time_stamp(global_trace.trace_buffer.buffer, cpu, &ts);
+       ts = ring_buffer_time_stamp(buf->buffer, cpu);
+       ring_buffer_normalize_time_stamp(buf->buffer, cpu, &ts);
 
        return ts;
 }
 
+cycle_t ftrace_now(int cpu)
+{
+       return buffer_ftrace_now(&global_trace.trace_buffer, cpu);
+}
+
 /**
  * tracing_is_enabled - Show if global_trace has been disabled
  *
@@ -1211,7 +1216,7 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
        /* Make sure all commits have finished */
        synchronize_sched();
 
-       buf->time_start = ftrace_now(buf->cpu);
+       buf->time_start = buffer_ftrace_now(buf, buf->cpu);
 
        for_each_online_cpu(cpu)
                ring_buffer_reset_cpu(buffer, cpu);
@@ -1219,11 +1224,6 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
        ring_buffer_record_enable(buffer);
 }
 
-void tracing_reset_current(int cpu)
-{
-       tracing_reset(&global_trace.trace_buffer, cpu);
-}
-
 /* Must have trace_types_lock held */
 void tracing_reset_all_online_cpus(void)
 {
@@ -4151,6 +4151,7 @@ waitagain:
        memset(&iter->seq, 0,
               sizeof(struct trace_iterator) -
               offsetof(struct trace_iterator, seq));
+       cpumask_clear(iter->started);
        iter->pos = -1;
 
        trace_event_read_lock();
@@ -4468,7 +4469,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
 
        /* disable tracing ? */
        if (trace_flags & TRACE_ITER_STOP_ON_FREE)
-               tracing_off();
+               tracer_tracing_off(tr);
        /* resize the ring buffer to 0 */
        tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
 
@@ -4633,12 +4634,12 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
         * New clock may not be consistent with the previous clock.
         * Reset the buffer so that it doesn't have incomparable timestamps.
         */
-       tracing_reset_online_cpus(&global_trace.trace_buffer);
+       tracing_reset_online_cpus(&tr->trace_buffer);
 
 #ifdef CONFIG_TRACER_MAX_TRACE
        if (tr->flags & TRACE_ARRAY_FL_GLOBAL && tr->max_buffer.buffer)
                ring_buffer_set_clock(tr->max_buffer.buffer, trace_clocks[i].func);
-       tracing_reset_online_cpus(&global_trace.max_buffer);
+       tracing_reset_online_cpus(&tr->max_buffer);
 #endif
 
        mutex_unlock(&trace_types_lock);
index 898f868..29a7ebc 100644 (file)
@@ -409,33 +409,42 @@ static void put_system(struct ftrace_subsystem_dir *dir)
        mutex_unlock(&event_mutex);
 }
 
-/*
- * Open and update trace_array ref count.
- * Must have the current trace_array passed to it.
- */
-static int tracing_open_generic_file(struct inode *inode, struct file *filp)
+static void remove_subsystem(struct ftrace_subsystem_dir *dir)
 {
-       struct ftrace_event_file *file = inode->i_private;
-       struct trace_array *tr = file->tr;
-       int ret;
+       if (!dir)
+               return;
 
-       if (trace_array_get(tr) < 0)
-               return -ENODEV;
+       if (!--dir->nr_events) {
+               debugfs_remove_recursive(dir->entry);
+               list_del(&dir->list);
+               __put_system_dir(dir);
+       }
+}
 
-       ret = tracing_open_generic(inode, filp);
-       if (ret < 0)
-               trace_array_put(tr);
-       return ret;
+static void *event_file_data(struct file *filp)
+{
+       return ACCESS_ONCE(file_inode(filp)->i_private);
 }
 
-static int tracing_release_generic_file(struct inode *inode, struct file *filp)
+static void remove_event_file_dir(struct ftrace_event_file *file)
 {
-       struct ftrace_event_file *file = inode->i_private;
-       struct trace_array *tr = file->tr;
+       struct dentry *dir = file->dir;
+       struct dentry *child;
 
-       trace_array_put(tr);
+       if (dir) {
+               spin_lock(&dir->d_lock);        /* probably unneeded */
+               list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+                       if (child->d_inode)     /* probably unneeded */
+                               child->d_inode->i_private = NULL;
+               }
+               spin_unlock(&dir->d_lock);
 
-       return 0;
+               debugfs_remove_recursive(dir);
+       }
+
+       list_del(&file->list);
+       remove_subsystem(file->system);
+       kmem_cache_free(file_cachep, file);
 }
 
 /*
@@ -679,15 +688,25 @@ static ssize_t
 event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
-       struct ftrace_event_file *file = filp->private_data;
+       struct ftrace_event_file *file;
+       unsigned long flags;
        char buf[4] = "0";
 
-       if (file->flags & FTRACE_EVENT_FL_ENABLED &&
-           !(file->flags & FTRACE_EVENT_FL_SOFT_DISABLED))
+       mutex_lock(&event_mutex);
+       file = event_file_data(filp);
+       if (likely(file))
+               flags = file->flags;
+       mutex_unlock(&event_mutex);
+
+       if (!file)
+               return -ENODEV;
+
+       if (flags & FTRACE_EVENT_FL_ENABLED &&
+           !(flags & FTRACE_EVENT_FL_SOFT_DISABLED))
                strcpy(buf, "1");
 
-       if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
-           file->flags & FTRACE_EVENT_FL_SOFT_MODE)
+       if (flags & FTRACE_EVENT_FL_SOFT_DISABLED ||
+           flags & FTRACE_EVENT_FL_SOFT_MODE)
                strcat(buf, "*");
 
        strcat(buf, "\n");
@@ -699,13 +718,10 @@ static ssize_t
 event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
-       struct ftrace_event_file *file = filp->private_data;
+       struct ftrace_event_file *file;
        unsigned long val;
        int ret;
 
-       if (!file)
-               return -EINVAL;
-
        ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
        if (ret)
                return ret;
@@ -717,8 +733,11 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
        switch (val) {
        case 0:
        case 1:
+               ret = -ENODEV;
                mutex_lock(&event_mutex);
-               ret = ftrace_event_enable_disable(file, val);
+               file = event_file_data(filp);
+               if (likely(file))
+                       ret = ftrace_event_enable_disable(file, val);
                mutex_unlock(&event_mutex);
                break;
 
@@ -825,7 +844,7 @@ enum {
 
 static void *f_next(struct seq_file *m, void *v, loff_t *pos)
 {
-       struct ftrace_event_call *call = m->private;
+       struct ftrace_event_call *call = event_file_data(m->private);
        struct list_head *common_head = &ftrace_common_fields;
        struct list_head *head = trace_get_fields(call);
        struct list_head *node = v;
@@ -857,7 +876,7 @@ static void *f_next(struct seq_file *m, void *v, loff_t *pos)
 
 static int f_show(struct seq_file *m, void *v)
 {
-       struct ftrace_event_call *call = m->private;
+       struct ftrace_event_call *call = event_file_data(m->private);
        struct ftrace_event_field *field;
        const char *array_descriptor;
 
@@ -910,6 +929,11 @@ static void *f_start(struct seq_file *m, loff_t *pos)
        void *p = (void *)FORMAT_HEADER;
        loff_t l = 0;
 
+       /* ->stop() is called even if ->start() fails */
+       mutex_lock(&event_mutex);
+       if (!event_file_data(m->private))
+               return ERR_PTR(-ENODEV);
+
        while (l < *pos && p)
                p = f_next(m, p, &l);
 
@@ -918,6 +942,7 @@ static void *f_start(struct seq_file *m, loff_t *pos)
 
 static void f_stop(struct seq_file *m, void *p)
 {
+       mutex_unlock(&event_mutex);
 }
 
 static const struct seq_operations trace_format_seq_ops = {
@@ -929,7 +954,6 @@ static const struct seq_operations trace_format_seq_ops = {
 
 static int trace_format_open(struct inode *inode, struct file *file)
 {
-       struct ftrace_event_call *call = inode->i_private;
        struct seq_file *m;
        int ret;
 
@@ -938,7 +962,7 @@ static int trace_format_open(struct inode *inode, struct file *file)
                return ret;
 
        m = file->private_data;
-       m->private = call;
+       m->private = file;
 
        return 0;
 }
@@ -946,14 +970,18 @@ static int trace_format_open(struct inode *inode, struct file *file)
 static ssize_t
 event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       int id = (long)event_file_data(filp);
        char buf[32];
        int len;
 
        if (*ppos)
                return 0;
 
-       len = sprintf(buf, "%d\n", call->event.type);
+       if (unlikely(!id))
+               return -ENODEV;
+
+       len = sprintf(buf, "%d\n", id);
+
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
 }
 
@@ -961,21 +989,28 @@ static ssize_t
 event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
                  loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       struct ftrace_event_call *call;
        struct trace_seq *s;
-       int r;
+       int r = -ENODEV;
 
        if (*ppos)
                return 0;
 
        s = kmalloc(sizeof(*s), GFP_KERNEL);
+
        if (!s)
                return -ENOMEM;
 
        trace_seq_init(s);
 
-       print_event_filter(call, s);
-       r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+       mutex_lock(&event_mutex);
+       call = event_file_data(filp);
+       if (call)
+               print_event_filter(call, s);
+       mutex_unlock(&event_mutex);
+
+       if (call)
+               r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
 
        kfree(s);
 
@@ -986,9 +1021,9 @@ static ssize_t
 event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
-       struct ftrace_event_call *call = filp->private_data;
+       struct ftrace_event_call *call;
        char *buf;
-       int err;
+       int err = -ENODEV;
 
        if (cnt >= PAGE_SIZE)
                return -EINVAL;
@@ -1003,7 +1038,12 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
        }
        buf[cnt] = '\0';
 
-       err = apply_event_filter(call, buf);
+       mutex_lock(&event_mutex);
+       call = event_file_data(filp);
+       if (call)
+               err = apply_event_filter(call, buf);
+       mutex_unlock(&event_mutex);
+
        free_page((unsigned long) buf);
        if (err < 0)
                return err;
@@ -1225,10 +1265,9 @@ static const struct file_operations ftrace_set_event_fops = {
 };
 
 static const struct file_operations ftrace_enable_fops = {
-       .open = tracing_open_generic_file,
+       .open = tracing_open_generic,
        .read = event_enable_read,
        .write = event_enable_write,
-       .release = tracing_release_generic_file,
        .llseek = default_llseek,
 };
 
@@ -1240,7 +1279,6 @@ static const struct file_operations ftrace_event_format_fops = {
 };
 
 static const struct file_operations ftrace_event_id_fops = {
-       .open = tracing_open_generic,
        .read = event_id_read,
        .llseek = default_llseek,
 };
@@ -1488,8 +1526,8 @@ event_create_dir(struct dentry *parent,
 
 #ifdef CONFIG_PERF_EVENTS
        if (call->event.type && call->class->reg)
-               trace_create_file("id", 0444, file->dir, call,
-                                 id);
+               trace_create_file("id", 0444, file->dir,
+                                 (void *)(long)call->event.type, id);
 #endif
 
        /*
@@ -1514,33 +1552,16 @@ event_create_dir(struct dentry *parent,
        return 0;
 }
 
-static void remove_subsystem(struct ftrace_subsystem_dir *dir)
-{
-       if (!dir)
-               return;
-
-       if (!--dir->nr_events) {
-               debugfs_remove_recursive(dir->entry);
-               list_del(&dir->list);
-               __put_system_dir(dir);
-       }
-}
-
 static void remove_event_from_tracers(struct ftrace_event_call *call)
 {
        struct ftrace_event_file *file;
        struct trace_array *tr;
 
        do_for_each_event_file_safe(tr, file) {
-
                if (file->event_call != call)
                        continue;
 
-               list_del(&file->list);
-               debugfs_remove_recursive(file->dir);
-               remove_subsystem(file->system);
-               kmem_cache_free(file_cachep, file);
-
+               remove_event_file_dir(file);
                /*
                 * The do_for_each_event_file_safe() is
                 * a double loop. After finding the call for this
@@ -1692,16 +1713,53 @@ static void __trace_remove_event_call(struct ftrace_event_call *call)
        destroy_preds(call);
 }
 
+static int probe_remove_event_call(struct ftrace_event_call *call)
+{
+       struct trace_array *tr;
+       struct ftrace_event_file *file;
+
+#ifdef CONFIG_PERF_EVENTS
+       if (call->perf_refcount)
+               return -EBUSY;
+#endif
+       do_for_each_event_file(tr, file) {
+               if (file->event_call != call)
+                       continue;
+               /*
+                * We can't rely on ftrace_event_enable_disable(enable => 0)
+                * we are going to do, FTRACE_EVENT_FL_SOFT_MODE can suppress
+                * TRACE_REG_UNREGISTER.
+                */
+               if (file->flags & FTRACE_EVENT_FL_ENABLED)
+                       return -EBUSY;
+               /*
+                * The do_for_each_event_file_safe() is
+                * a double loop. After finding the call for this
+                * trace_array, we use break to jump to the next
+                * trace_array.
+                */
+               break;
+       } while_for_each_event_file();
+
+       __trace_remove_event_call(call);
+
+       return 0;
+}
+
 /* Remove an event_call */
-void trace_remove_event_call(struct ftrace_event_call *call)
+int trace_remove_event_call(struct ftrace_event_call *call)
 {
+       int ret;
+
        mutex_lock(&trace_types_lock);
        mutex_lock(&event_mutex);
        down_write(&trace_event_sem);
-       __trace_remove_event_call(call);
+       ret = probe_remove_event_call(call);
        up_write(&trace_event_sem);
        mutex_unlock(&event_mutex);
        mutex_unlock(&trace_types_lock);
+
+       return ret;
 }
 
 #define for_each_event(event, start, end)                      \
@@ -2270,12 +2328,8 @@ __trace_remove_event_dirs(struct trace_array *tr)
 {
        struct ftrace_event_file *file, *next;
 
-       list_for_each_entry_safe(file, next, &tr->events, list) {
-               list_del(&file->list);
-               debugfs_remove_recursive(file->dir);
-               remove_subsystem(file->system);
-               kmem_cache_free(file_cachep, file);
-       }
+       list_for_each_entry_safe(file, next, &tr->events, list)
+               remove_event_file_dir(file);
 }
 
 static void
index 0c7b75a..97daa8c 100644 (file)
@@ -637,17 +637,15 @@ static void append_filter_err(struct filter_parse_state *ps,
        free_page((unsigned long) buf);
 }
 
+/* caller must hold event_mutex */
 void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s)
 {
-       struct event_filter *filter;
+       struct event_filter *filter = call->filter;
 
-       mutex_lock(&event_mutex);
-       filter = call->filter;
        if (filter && filter->filter_string)
                trace_seq_printf(s, "%s\n", filter->filter_string);
        else
                trace_seq_puts(s, "none\n");
-       mutex_unlock(&event_mutex);
 }
 
 void print_subsystem_event_filter(struct event_subsystem *system,
@@ -1841,23 +1839,22 @@ static int create_system_filter(struct event_subsystem *system,
        return err;
 }
 
+/* caller must hold event_mutex */
 int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
 {
        struct event_filter *filter;
-       int err = 0;
-
-       mutex_lock(&event_mutex);
+       int err;
 
        if (!strcmp(strstrip(filter_string), "0")) {
                filter_disable(call);
                filter = call->filter;
                if (!filter)
-                       goto out_unlock;
+                       return 0;
                RCU_INIT_POINTER(call->filter, NULL);
                /* Make sure the filter is not being used */
                synchronize_sched();
                __free_filter(filter);
-               goto out_unlock;
+               return 0;
        }
 
        err = create_filter(call, filter_string, true, &filter);
@@ -1884,8 +1881,6 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
                        __free_filter(tmp);
                }
        }
-out_unlock:
-       mutex_unlock(&event_mutex);
 
        return err;
 }
index 3811487..243f683 100644 (file)
@@ -95,7 +95,7 @@ static __kprobes bool trace_probe_is_on_module(struct trace_probe *tp)
 }
 
 static int register_probe_event(struct trace_probe *tp);
-static void unregister_probe_event(struct trace_probe *tp);
+static int unregister_probe_event(struct trace_probe *tp);
 
 static DEFINE_MUTEX(probe_lock);
 static LIST_HEAD(probe_list);
@@ -351,9 +351,12 @@ static int unregister_trace_probe(struct trace_probe *tp)
        if (trace_probe_is_enabled(tp))
                return -EBUSY;
 
+       /* Will fail if probe is being used by ftrace or perf */
+       if (unregister_probe_event(tp))
+               return -EBUSY;
+
        __unregister_trace_probe(tp);
        list_del(&tp->list);
-       unregister_probe_event(tp);
 
        return 0;
 }
@@ -632,7 +635,9 @@ static int release_all_trace_probes(void)
        /* TODO: Use batch unregistration */
        while (!list_empty(&probe_list)) {
                tp = list_entry(probe_list.next, struct trace_probe, list);
-               unregister_trace_probe(tp);
+               ret = unregister_trace_probe(tp);
+               if (ret)
+                       goto end;
                free_trace_probe(tp);
        }
 
@@ -1247,11 +1252,15 @@ static int register_probe_event(struct trace_probe *tp)
        return ret;
 }
 
-static void unregister_probe_event(struct trace_probe *tp)
+static int unregister_probe_event(struct trace_probe *tp)
 {
+       int ret;
+
        /* tp->event is unregistered in trace_remove_event_call() */
-       trace_remove_event_call(&tp->call);
-       kfree(tp->call.print_fmt);
+       ret = trace_remove_event_call(&tp->call);
+       if (!ret)
+               kfree(tp->call.print_fmt);
+       return ret;
 }
 
 /* Make a debugfs interface for controlling probe points */
index a23d2d7..272261b 100644 (file)
@@ -70,7 +70,7 @@ struct trace_uprobe {
        (sizeof(struct probe_arg) * (n)))
 
 static int register_uprobe_event(struct trace_uprobe *tu);
-static void unregister_uprobe_event(struct trace_uprobe *tu);
+static int unregister_uprobe_event(struct trace_uprobe *tu);
 
 static DEFINE_MUTEX(uprobe_lock);
 static LIST_HEAD(uprobe_list);
@@ -164,11 +164,17 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
 }
 
 /* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */
-static void unregister_trace_uprobe(struct trace_uprobe *tu)
+static int unregister_trace_uprobe(struct trace_uprobe *tu)
 {
+       int ret;
+
+       ret = unregister_uprobe_event(tu);
+       if (ret)
+               return ret;
+
        list_del(&tu->list);
-       unregister_uprobe_event(tu);
        free_trace_uprobe(tu);
+       return 0;
 }
 
 /* Register a trace_uprobe and probe_event */
@@ -181,9 +187,12 @@ static int register_trace_uprobe(struct trace_uprobe *tu)
 
        /* register as an event */
        old_tp = find_probe_event(tu->call.name, tu->call.class->system);
-       if (old_tp)
+       if (old_tp) {
                /* delete old event */
-               unregister_trace_uprobe(old_tp);
+               ret = unregister_trace_uprobe(old_tp);
+               if (ret)
+                       goto end;
+       }
 
        ret = register_uprobe_event(tu);
        if (ret) {
@@ -256,6 +265,8 @@ static int create_trace_uprobe(int argc, char **argv)
                group = UPROBE_EVENT_SYSTEM;
 
        if (is_delete) {
+               int ret;
+
                if (!event) {
                        pr_info("Delete command needs an event name.\n");
                        return -EINVAL;
@@ -269,9 +280,9 @@ static int create_trace_uprobe(int argc, char **argv)
                        return -ENOENT;
                }
                /* delete an event */
-               unregister_trace_uprobe(tu);
+               ret = unregister_trace_uprobe(tu);
                mutex_unlock(&uprobe_lock);
-               return 0;
+               return ret;
        }
 
        if (argc < 2) {
@@ -408,16 +419,20 @@ fail_address_parse:
        return ret;
 }
 
-static void cleanup_all_probes(void)
+static int cleanup_all_probes(void)
 {
        struct trace_uprobe *tu;
+       int ret = 0;
 
        mutex_lock(&uprobe_lock);
        while (!list_empty(&uprobe_list)) {
                tu = list_entry(uprobe_list.next, struct trace_uprobe, list);
-               unregister_trace_uprobe(tu);
+               ret = unregister_trace_uprobe(tu);
+               if (ret)
+                       break;
        }
        mutex_unlock(&uprobe_lock);
+       return ret;
 }
 
 /* Probes listing interfaces */
@@ -462,8 +477,13 @@ static const struct seq_operations probes_seq_op = {
 
 static int probes_open(struct inode *inode, struct file *file)
 {
-       if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC))
-               cleanup_all_probes();
+       int ret;
+
+       if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
+               ret = cleanup_all_probes();
+               if (ret)
+                       return ret;
+       }
 
        return seq_open(file, &probes_seq_op);
 }
@@ -968,12 +988,17 @@ static int register_uprobe_event(struct trace_uprobe *tu)
        return ret;
 }
 
-static void unregister_uprobe_event(struct trace_uprobe *tu)
+static int unregister_uprobe_event(struct trace_uprobe *tu)
 {
+       int ret;
+
        /* tu->event is unregistered in trace_remove_event_call() */
-       trace_remove_event_call(&tu->call);
+       ret = trace_remove_event_call(&tu->call);
+       if (ret)
+               return ret;
        kfree(tu->call.print_fmt);
        tu->call.print_fmt = NULL;
+       return 0;
 }
 
 /* Make a trace interface for controling probe points */
index d8c30db..9064b91 100644 (file)
@@ -62,6 +62,9 @@ int create_user_ns(struct cred *new)
        kgid_t group = new->egid;
        int ret;
 
+       if (parent_ns->level > 32)
+               return -EUSERS;
+
        /*
         * Verify that we can not violate the policy of which files
         * may be accessed that is specified by the root directory,
@@ -92,6 +95,7 @@ int create_user_ns(struct cred *new)
        atomic_set(&ns->count, 1);
        /* Leave the new->user_ns reference with the new user namespace. */
        ns->parent = parent_ns;
+       ns->level = parent_ns->level + 1;
        ns->owner = owner;
        ns->group = group;
 
@@ -105,16 +109,21 @@ int create_user_ns(struct cred *new)
 int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
 {
        struct cred *cred;
+       int err = -ENOMEM;
 
        if (!(unshare_flags & CLONE_NEWUSER))
                return 0;
 
        cred = prepare_creds();
-       if (!cred)
-               return -ENOMEM;
+       if (cred) {
+               err = create_user_ns(cred);
+               if (err)
+                       put_cred(cred);
+               else
+                       *new_cred = cred;
+       }
 
-       *new_cred = cred;
-       return create_user_ns(cred);
+       return err;
 }
 
 void free_user_ns(struct user_namespace *ns)
index 0b72e81..7f5d4be 100644 (file)
@@ -2817,6 +2817,19 @@ already_gone:
        return false;
 }
 
+static bool __flush_work(struct work_struct *work)
+{
+       struct wq_barrier barr;
+
+       if (start_flush_work(work, &barr)) {
+               wait_for_completion(&barr.done);
+               destroy_work_on_stack(&barr.work);
+               return true;
+       } else {
+               return false;
+       }
+}
+
 /**
  * flush_work - wait for a work to finish executing the last queueing instance
  * @work: the work to flush
@@ -2830,18 +2843,10 @@ already_gone:
  */
 bool flush_work(struct work_struct *work)
 {
-       struct wq_barrier barr;
-
        lock_map_acquire(&work->lockdep_map);
        lock_map_release(&work->lockdep_map);
 
-       if (start_flush_work(work, &barr)) {
-               wait_for_completion(&barr.done);
-               destroy_work_on_stack(&barr.work);
-               return true;
-       } else {
-               return false;
-       }
+       return __flush_work(work);
 }
 EXPORT_SYMBOL_GPL(flush_work);
 
@@ -3411,6 +3416,12 @@ static void copy_workqueue_attrs(struct workqueue_attrs *to,
 {
        to->nice = from->nice;
        cpumask_copy(to->cpumask, from->cpumask);
+       /*
+        * Unlike hash and equality test, this function doesn't ignore
+        * ->no_numa as it is used for both pool and wq attrs.  Instead,
+        * get_unbound_pool() explicitly clears ->no_numa after copying.
+        */
+       to->no_numa = from->no_numa;
 }
 
 /* hash value of the content of @attr */
@@ -3578,6 +3589,12 @@ static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs)
        lockdep_set_subclass(&pool->lock, 1);   /* see put_pwq() */
        copy_workqueue_attrs(pool->attrs, attrs);
 
+       /*
+        * no_numa isn't a worker_pool attribute, always clear it.  See
+        * 'struct workqueue_attrs' comments for detail.
+        */
+       pool->attrs->no_numa = false;
+
        /* if cpumask is contained inside a NUMA node, we belong to that node */
        if (wq_numa_enabled) {
                for_each_node(node) {
@@ -4756,7 +4773,14 @@ long work_on_cpu(int cpu, long (*fn)(void *), void *arg)
 
        INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
        schedule_work_on(cpu, &wfc.work);
-       flush_work(&wfc.work);
+
+       /*
+        * The work item is on-stack and can't lead to deadlock through
+        * flushing.  Use __flush_work() to avoid spurious lockdep warnings
+        * when work_on_cpu()s are nested.
+        */
+       __flush_work(&wfc.work);
+
        return wfc.ret;
 }
 EXPORT_SYMBOL_GPL(work_on_cpu);
index 87da359..5bff081 100644 (file)
@@ -57,17 +57,22 @@ static int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long addr, unsigned long pgoff, pgprot_t prot)
 {
        int err = -ENOMEM;
-       pte_t *pte;
+       pte_t *pte, ptfile;
        spinlock_t *ptl;
 
        pte = get_locked_pte(mm, addr, &ptl);
        if (!pte)
                goto out;
 
-       if (!pte_none(*pte))
+       ptfile = pgoff_to_pte(pgoff);
+
+       if (!pte_none(*pte)) {
+               if (pte_present(*pte) && pte_soft_dirty(*pte))
+                       pte_file_mksoft_dirty(ptfile);
                zap_pte(mm, vma, addr, pte);
+       }
 
-       set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
+       set_pte_at(mm, addr, pte, ptfile);
        /*
         * We don't need to run update_mmu_cache() here because the "file pte"
         * being installed by install_file_pte() is not a real pte - it's a
index 243e710..a92012a 100644 (file)
@@ -1620,7 +1620,9 @@ static void __split_huge_page_refcount(struct page *page,
                                     ((1L << PG_referenced) |
                                      (1L << PG_swapbacked) |
                                      (1L << PG_mlocked) |
-                                     (1L << PG_uptodate)));
+                                     (1L << PG_uptodate) |
+                                     (1L << PG_active) |
+                                     (1L << PG_unevictable)));
                page_tail->flags |= (1L << PG_dirty);
 
                /* clear PageTail before overwriting first_page */
index 83aff0a..b60f330 100644 (file)
@@ -2490,7 +2490,7 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
 
        mm = vma->vm_mm;
 
-       tlb_gather_mmu(&tlb, mm, 0);
+       tlb_gather_mmu(&tlb, mm, start, end);
        __unmap_hugepage_range(&tlb, vma, start, end, ref_page);
        tlb_finish_mmu(&tlb, start, end);
 }
index 00a7a66..c5792a5 100644 (file)
@@ -3195,11 +3195,11 @@ int memcg_register_cache(struct mem_cgroup *memcg, struct kmem_cache *s,
        if (!s->memcg_params)
                return -ENOMEM;
 
-       INIT_WORK(&s->memcg_params->destroy,
-                       kmem_cache_destroy_work_func);
        if (memcg) {
                s->memcg_params->memcg = memcg;
                s->memcg_params->root_cache = root_cache;
+               INIT_WORK(&s->memcg_params->destroy,
+                               kmem_cache_destroy_work_func);
        } else
                s->memcg_params->is_root_cache = true;
 
@@ -6335,6 +6335,7 @@ static void mem_cgroup_css_offline(struct cgroup *cont)
        mem_cgroup_invalidate_reclaim_iterators(memcg);
        mem_cgroup_reparent_charges(memcg);
        mem_cgroup_destroy_all_caches(memcg);
+       vmpressure_cleanup(&memcg->vmpressure);
 }
 
 static void mem_cgroup_css_free(struct cgroup *cont)
index 1ce2e2a..af84bc0 100644 (file)
@@ -209,14 +209,15 @@ static int tlb_next_batch(struct mmu_gather *tlb)
  *     tear-down from @mm. The @fullmm argument is used when @mm is without
  *     users and we're going to destroy the full address space (exit/execve).
  */
-void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)
+void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end)
 {
        tlb->mm = mm;
 
-       tlb->fullmm     = fullmm;
+       /* Is it from 0 to ~0? */
+       tlb->fullmm     = !(start | (end+1));
        tlb->need_flush_all = 0;
-       tlb->start      = -1UL;
-       tlb->end        = 0;
+       tlb->start      = start;
+       tlb->end        = end;
        tlb->need_flush = 0;
        tlb->local.next = NULL;
        tlb->local.nr   = 0;
@@ -256,8 +257,6 @@ void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long e
 {
        struct mmu_gather_batch *batch, *next;
 
-       tlb->start = start;
-       tlb->end   = end;
        tlb_flush_mmu(tlb);
 
        /* keep the page table cache within bounds */
@@ -1099,7 +1098,6 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
        spinlock_t *ptl;
        pte_t *start_pte;
        pte_t *pte;
-       unsigned long range_start = addr;
 
 again:
        init_rss_vec(rss);
@@ -1141,9 +1139,12 @@ again:
                                continue;
                        if (unlikely(details) && details->nonlinear_vma
                            && linear_page_index(details->nonlinear_vma,
-                                               addr) != page->index)
-                               set_pte_at(mm, addr, pte,
-                                          pgoff_to_pte(page->index));
+                                               addr) != page->index) {
+                               pte_t ptfile = pgoff_to_pte(page->index);
+                               if (pte_soft_dirty(ptent))
+                                       pte_file_mksoft_dirty(ptfile);
+                               set_pte_at(mm, addr, pte, ptfile);
+                       }
                        if (PageAnon(page))
                                rss[MM_ANONPAGES]--;
                        else {
@@ -1202,17 +1203,25 @@ again:
         * and page-free while holding it.
         */
        if (force_flush) {
+               unsigned long old_end;
+
                force_flush = 0;
 
-#ifdef HAVE_GENERIC_MMU_GATHER
-               tlb->start = range_start;
+               /*
+                * Flush the TLB just for the previous segment,
+                * then update the range to be the remaining
+                * TLB range.
+                */
+               old_end = tlb->end;
                tlb->end = addr;
-#endif
+
                tlb_flush_mmu(tlb);
-               if (addr != end) {
-                       range_start = addr;
+
+               tlb->start = addr;
+               tlb->end = old_end;
+
+               if (addr != end)
                        goto again;
-               }
        }
 
        return addr;
@@ -1397,7 +1406,7 @@ void zap_page_range(struct vm_area_struct *vma, unsigned long start,
        unsigned long end = start + size;
 
        lru_add_drain();
-       tlb_gather_mmu(&tlb, mm, 0);
+       tlb_gather_mmu(&tlb, mm, start, end);
        update_hiwater_rss(mm);
        mmu_notifier_invalidate_range_start(mm, start, end);
        for ( ; vma && vma->vm_start < end; vma = vma->vm_next)
@@ -1423,7 +1432,7 @@ static void zap_page_range_single(struct vm_area_struct *vma, unsigned long addr
        unsigned long end = address + size;
 
        lru_add_drain();
-       tlb_gather_mmu(&tlb, mm, 0);
+       tlb_gather_mmu(&tlb, mm, address, end);
        update_hiwater_rss(mm);
        mmu_notifier_invalidate_range_start(mm, address, end);
        unmap_single_vma(&tlb, vma, address, end, details);
@@ -3115,6 +3124,8 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,
                exclusive = 1;
        }
        flush_icache_page(vma, page);
+       if (pte_swp_soft_dirty(orig_pte))
+               pte = pte_mksoft_dirty(pte);
        set_pte_at(mm, address, page_table, pte);
        if (page == swapcache)
                do_page_add_anon_rmap(page, vma, address, exclusive);
@@ -3408,6 +3419,8 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                entry = mk_pte(page, vma->vm_page_prot);
                if (flags & FAULT_FLAG_WRITE)
                        entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+               else if (pte_file(orig_pte) && pte_file_soft_dirty(orig_pte))
+                       pte_mksoft_dirty(entry);
                if (anon) {
                        inc_mm_counter_fast(mm, MM_ANONPAGES);
                        page_add_new_anon_rmap(page, vma, address);
index 7431001..4baf12e 100644 (file)
@@ -732,7 +732,10 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                if (prev) {
                        vma = prev;
                        next = vma->vm_next;
-                       continue;
+                       if (mpol_equal(vma_policy(vma), new_pol))
+                               continue;
+                       /* vma_merge() joined vma && vma->next, case 8 */
+                       goto replace;
                }
                if (vma->vm_start != vmstart) {
                        err = split_vma(vma->vm_mm, vma, vmstart, 1);
@@ -744,6 +747,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                        if (err)
                                goto out;
                }
+ replace:
                err = vma_replace_policy(vma, new_pol);
                if (err)
                        goto out;
index fbad7b0..f9c97d1 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -865,7 +865,7 @@ again:                      remove_next = 1 + (end > next->vm_end);
                if (next->anon_vma)
                        anon_vma_merge(vma, next);
                mm->map_count--;
-               vma_set_policy(vma, vma_policy(next));
+               mpol_put(vma_policy(next));
                kmem_cache_free(vm_area_cachep, next);
                /*
                 * In mprotect's case 6 (see comments on vma_merge),
@@ -2336,7 +2336,7 @@ static void unmap_region(struct mm_struct *mm,
        struct mmu_gather tlb;
 
        lru_add_drain();
-       tlb_gather_mmu(&tlb, mm, 0);
+       tlb_gather_mmu(&tlb, mm, start, end);
        update_hiwater_rss(mm);
        unmap_vmas(&tlb, vma, start, end);
        free_pgtables(&tlb, vma, prev ? prev->vm_end : FIRST_USER_ADDRESS,
@@ -2709,7 +2709,7 @@ void exit_mmap(struct mm_struct *mm)
 
        lru_add_drain();
        flush_cache_mm(mm);
-       tlb_gather_mmu(&tlb, mm, 1);
+       tlb_gather_mmu(&tlb, mm, 0, -1);
        /* update_hiwater_rss(mm) here? but nobody should be looking */
        /* Use -1 here to ensure all VMAs in the mm are unmapped */
        unmap_vmas(&tlb, vma, 0, -1);
index cd356df..b2e29ac 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1236,6 +1236,7 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                           swp_entry_to_pte(make_hwpoison_entry(page)));
        } else if (PageAnon(page)) {
                swp_entry_t entry = { .val = page_private(page) };
+               pte_t swp_pte;
 
                if (PageSwapCache(page)) {
                        /*
@@ -1264,7 +1265,10 @@ int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
                        BUG_ON(TTU_ACTION(flags) != TTU_MIGRATION);
                        entry = make_migration_entry(page, pte_write(pteval));
                }
-               set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
+               swp_pte = swp_entry_to_pte(entry);
+               if (pte_soft_dirty(pteval))
+                       swp_pte = pte_swp_mksoft_dirty(swp_pte);
+               set_pte_at(mm, address, pte, swp_pte);
                BUG_ON(pte_file(*pte));
        } else if (IS_ENABLED(CONFIG_MIGRATION) &&
                   (TTU_ACTION(flags) == TTU_MIGRATION)) {
@@ -1401,8 +1405,12 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
                pteval = ptep_clear_flush(vma, address, pte);
 
                /* If nonlinear, store the file page offset in the pte. */
-               if (page->index != linear_page_index(vma, address))
-                       set_pte_at(mm, address, pte, pgoff_to_pte(page->index));
+               if (page->index != linear_page_index(vma, address)) {
+                       pte_t ptfile = pgoff_to_pte(page->index);
+                       if (pte_soft_dirty(pteval))
+                               pte_file_mksoft_dirty(ptfile);
+                       set_pte_at(mm, address, pte, ptfile);
+               }
 
                /* Move the dirty bit to the physical page now the pte is gone. */
                if (pte_dirty(pteval))
index a87990c..8335dbd 100644 (file)
@@ -1798,7 +1798,8 @@ static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence)
                }
        }
 
-       offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
+       if (offset >= 0)
+               offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE);
        mutex_unlock(&inode->i_mutex);
        return offset;
 }
index 2b02d66..e3ba1f2 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1968,9 +1968,6 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
        int pages;
        int pobjects;
 
-       if (!s->cpu_partial)
-               return;
-
        do {
                pages = 0;
                pobjects = 0;
index 4a1d0d2..62b78a6 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -512,12 +512,7 @@ EXPORT_SYMBOL(__lru_cache_add);
  */
 void lru_cache_add(struct page *page)
 {
-       if (PageActive(page)) {
-               VM_BUG_ON(PageUnevictable(page));
-       } else if (PageUnevictable(page)) {
-               VM_BUG_ON(PageActive(page));
-       }
-
+       VM_BUG_ON(PageActive(page) && PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
        __lru_cache_add(page);
 }
@@ -539,6 +534,7 @@ void add_page_to_unevictable_list(struct page *page)
 
        spin_lock_irq(&zone->lru_lock);
        lruvec = mem_cgroup_page_lruvec(page, zone);
+       ClearPageActive(page);
        SetPageUnevictable(page);
        SetPageLRU(page);
        add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
@@ -774,8 +770,6 @@ EXPORT_SYMBOL(__pagevec_release);
 void lru_add_page_tail(struct page *page, struct page *page_tail,
                       struct lruvec *lruvec, struct list_head *list)
 {
-       int uninitialized_var(active);
-       enum lru_list lru;
        const int file = 0;
 
        VM_BUG_ON(!PageHead(page));
@@ -787,20 +781,6 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
        if (!list)
                SetPageLRU(page_tail);
 
-       if (page_evictable(page_tail)) {
-               if (PageActive(page)) {
-                       SetPageActive(page_tail);
-                       active = 1;
-                       lru = LRU_ACTIVE_ANON;
-               } else {
-                       active = 0;
-                       lru = LRU_INACTIVE_ANON;
-               }
-       } else {
-               SetPageUnevictable(page_tail);
-               lru = LRU_UNEVICTABLE;
-       }
-
        if (likely(PageLRU(page)))
                list_add_tail(&page_tail->lru, &page->lru);
        else if (list) {
@@ -816,13 +796,13 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
                 * Use the standard add function to put page_tail on the list,
                 * but then correct its position so they all end up in order.
                 */
-               add_page_to_lru_list(page_tail, lruvec, lru);
+               add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail));
                list_head = page_tail->lru.prev;
                list_move_tail(&page_tail->lru, list_head);
        }
 
        if (!PageUnevictable(page))
-               update_page_reclaim_stat(lruvec, file, active);
+               update_page_reclaim_stat(lruvec, file, PageActive(page_tail));
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
@@ -833,7 +813,6 @@ static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
        int active = PageActive(page);
        enum lru_list lru = page_lru(page);
 
-       VM_BUG_ON(PageUnevictable(page));
        VM_BUG_ON(PageLRU(page));
 
        SetPageLRU(page);
index 36af6ee..6cf2e60 100644 (file)
@@ -866,6 +866,21 @@ unsigned int count_swap_pages(int type, int free)
 }
 #endif /* CONFIG_HIBERNATION */
 
+static inline int maybe_same_pte(pte_t pte, pte_t swp_pte)
+{
+#ifdef CONFIG_MEM_SOFT_DIRTY
+       /*
+        * When pte keeps soft dirty bit the pte generated
+        * from swap entry does not has it, still it's same
+        * pte from logical point of view.
+        */
+       pte_t swp_pte_dirty = pte_swp_mksoft_dirty(swp_pte);
+       return pte_same(pte, swp_pte) || pte_same(pte, swp_pte_dirty);
+#else
+       return pte_same(pte, swp_pte);
+#endif
+}
+
 /*
  * No need to decide whether this PTE shares the swap entry with others,
  * just let do_wp_page work it out if a write is requested later - to
@@ -892,7 +907,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        }
 
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
-       if (unlikely(!pte_same(*pte, swp_entry_to_pte(entry)))) {
+       if (unlikely(!maybe_same_pte(*pte, swp_entry_to_pte(entry)))) {
                mem_cgroup_cancel_charge_swapin(memcg);
                ret = 0;
                goto out;
@@ -947,7 +962,7 @@ static int unuse_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                 * swapoff spends a _lot_ of time in this loop!
                 * Test inline before going to call unuse_pte.
                 */
-               if (unlikely(pte_same(*pte, swp_pte))) {
+               if (unlikely(maybe_same_pte(*pte, swp_pte))) {
                        pte_unmap(pte);
                        ret = unuse_pte(vma, pmd, addr, entry, page);
                        if (ret)
index 736a601..0c1e37d 100644 (file)
@@ -180,12 +180,12 @@ static void vmpressure_work_fn(struct work_struct *work)
        if (!vmpr->scanned)
                return;
 
-       mutex_lock(&vmpr->sr_lock);
+       spin_lock(&vmpr->sr_lock);
        scanned = vmpr->scanned;
        reclaimed = vmpr->reclaimed;
        vmpr->scanned = 0;
        vmpr->reclaimed = 0;
-       mutex_unlock(&vmpr->sr_lock);
+       spin_unlock(&vmpr->sr_lock);
 
        do {
                if (vmpressure_event(vmpr, scanned, reclaimed))
@@ -240,13 +240,13 @@ void vmpressure(gfp_t gfp, struct mem_cgroup *memcg,
        if (!scanned)
                return;
 
-       mutex_lock(&vmpr->sr_lock);
+       spin_lock(&vmpr->sr_lock);
        vmpr->scanned += scanned;
        vmpr->reclaimed += reclaimed;
        scanned = vmpr->scanned;
-       mutex_unlock(&vmpr->sr_lock);
+       spin_unlock(&vmpr->sr_lock);
 
-       if (scanned < vmpressure_win || work_pending(&vmpr->work))
+       if (scanned < vmpressure_win)
                return;
        schedule_work(&vmpr->work);
 }
@@ -367,8 +367,24 @@ void vmpressure_unregister_event(struct cgroup *cg, struct cftype *cft,
  */
 void vmpressure_init(struct vmpressure *vmpr)
 {
-       mutex_init(&vmpr->sr_lock);
+       spin_lock_init(&vmpr->sr_lock);
        mutex_init(&vmpr->events_lock);
        INIT_LIST_HEAD(&vmpr->events);
        INIT_WORK(&vmpr->work, vmpressure_work_fn);
 }
+
+/**
+ * vmpressure_cleanup() - shuts down vmpressure control structure
+ * @vmpr:      Structure to be cleaned up
+ *
+ * This function should be called before the structure in which it is
+ * embedded is cleaned up.
+ */
+void vmpressure_cleanup(struct vmpressure *vmpr)
+{
+       /*
+        * Make sure there is no pending work before eventfd infrastructure
+        * goes away.
+        */
+       flush_work(&vmpr->work);
+}
index 9bb4710..ad1e781 100644 (file)
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -257,7 +257,7 @@ int zbud_alloc(struct zbud_pool *pool, int size, gfp_t gfp,
 
        if (size <= 0 || gfp & __GFP_HIGHMEM)
                return -EINVAL;
-       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED)
+       if (size > PAGE_SIZE - ZHDR_SIZE_ALIGNED - CHUNK_SIZE)
                return -ENOSPC;
        chunks = size_to_chunks(size);
        spin_lock(&pool->lock);
index 4a78c4d..6ee48aa 100644 (file)
@@ -91,7 +91,12 @@ EXPORT_SYMBOL(__vlan_find_dev_deep);
 
 struct net_device *vlan_dev_real_dev(const struct net_device *dev)
 {
-       return vlan_dev_priv(dev)->real_dev;
+       struct net_device *ret = vlan_dev_priv(dev)->real_dev;
+
+       while (is_vlan_dev(ret))
+               ret = vlan_dev_priv(ret)->real_dev;
+
+       return ret;
 }
 EXPORT_SYMBOL(vlan_dev_real_dev);
 
index 3770249..2b40660 100644 (file)
@@ -244,7 +244,7 @@ config NETPRIO_CGROUP
          Cgroup subsystem for use in assigning processes to network priorities on
          a per-interface basis
 
-config NET_LL_RX_POLL
+config NET_RX_BUSY_POLL
        boolean
        default y
 
index e14531f..264de88 100644 (file)
@@ -1529,6 +1529,8 @@ out:
  * in these cases, the skb is further handled by this function and
  * returns 1, otherwise it returns 0 and the caller shall further
  * process the skb.
+ *
+ * This call might reallocate skb data.
  */
 int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
                  unsigned short vid)
index f105219..7614af3 100644 (file)
@@ -508,6 +508,7 @@ out:
        return 0;
 }
 
+/* this call might reallocate skb data */
 static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
 {
        int ret = false;
@@ -568,6 +569,7 @@ out:
        return ret;
 }
 
+/* this call might reallocate skb data */
 bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
 {
        struct ethhdr *ethhdr;
@@ -619,6 +621,12 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
 
        if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
                return false;
+
+       /* skb->data might have been reallocated by pskb_may_pull() */
+       ethhdr = (struct ethhdr *)skb->data;
+       if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
+               ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
+
        udphdr = (struct udphdr *)(skb->data + *header_len);
        *header_len += sizeof(*udphdr);
 
@@ -634,12 +642,14 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
        return true;
 }
 
+/* this call might reallocate skb data */
 bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
-                           struct sk_buff *skb, struct ethhdr *ethhdr)
+                           struct sk_buff *skb)
 {
        struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
        struct batadv_orig_node *orig_dst_node = NULL;
        struct batadv_gw_node *curr_gw = NULL;
+       struct ethhdr *ethhdr;
        bool ret, out_of_range = false;
        unsigned int header_len = 0;
        uint8_t curr_tq_avg;
@@ -648,6 +658,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
        if (!ret)
                goto out;
 
+       ethhdr = (struct ethhdr *)skb->data;
        orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
                                                 ethhdr->h_dest);
        if (!orig_dst_node)
index 039902d..1037d75 100644 (file)
@@ -34,7 +34,6 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
 void batadv_gw_node_purge(struct batadv_priv *bat_priv);
 int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
 bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
-bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
-                           struct sk_buff *skb, struct ethhdr *ethhdr);
+bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
index 700d0b4..0f04e1c 100644 (file)
@@ -180,6 +180,9 @@ static int batadv_interface_tx(struct sk_buff *skb,
        if (batadv_bla_tx(bat_priv, skb, vid))
                goto dropped;
 
+       /* skb->data might have been reallocated by batadv_bla_tx() */
+       ethhdr = (struct ethhdr *)skb->data;
+
        /* Register the client MAC in the transtable */
        if (!is_multicast_ether_addr(ethhdr->h_source))
                batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
@@ -220,6 +223,10 @@ static int batadv_interface_tx(struct sk_buff *skb,
                default:
                        break;
                }
+
+               /* reminder: ethhdr might have become unusable from here on
+                * (batadv_gw_is_dhcp_target() might have reallocated skb data)
+                */
        }
 
        /* ethernet packet should be broadcasted */
@@ -266,7 +273,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
        /* unicast packet */
        } else {
                if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
-                       ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr);
+                       ret = batadv_gw_out_of_range(bat_priv, skb);
                        if (ret)
                                goto dropped;
                }
index dc8b5d4..688a041 100644 (file)
@@ -326,7 +326,9 @@ static bool batadv_unicast_push_and_fill_skb(struct sk_buff *skb, int hdr_size,
  * @skb: the skb containing the payload to encapsulate
  * @orig_node: the destination node
  *
- * Returns false if the payload could not be encapsulated or true otherwise
+ * Returns false if the payload could not be encapsulated or true otherwise.
+ *
+ * This call might reallocate skb data.
  */
 static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
                                       struct batadv_orig_node *orig_node)
@@ -343,7 +345,9 @@ static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
  * @orig_node: the destination node
  * @packet_subtype: the batman 4addr packet subtype to use
  *
- * Returns false if the payload could not be encapsulated or true otherwise
+ * Returns false if the payload could not be encapsulated or true otherwise.
+ *
+ * This call might reallocate skb data.
  */
 bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv,
                                      struct sk_buff *skb,
@@ -401,7 +405,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
        struct batadv_neigh_node *neigh_node;
        int data_len = skb->len;
        int ret = NET_RX_DROP;
-       unsigned int dev_mtu;
+       unsigned int dev_mtu, header_len;
 
        /* get routing information */
        if (is_multicast_ether_addr(ethhdr->h_dest)) {
@@ -429,10 +433,12 @@ find_router:
        switch (packet_type) {
        case BATADV_UNICAST:
                batadv_unicast_prepare_skb(skb, orig_node);
+               header_len = sizeof(struct batadv_unicast_packet);
                break;
        case BATADV_UNICAST_4ADDR:
                batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node,
                                                 packet_subtype);
+               header_len = sizeof(struct batadv_unicast_4addr_packet);
                break;
        default:
                /* this function supports UNICAST and UNICAST_4ADDR only. It
@@ -441,6 +447,7 @@ find_router:
                goto out;
        }
 
+       ethhdr = (struct ethhdr *)(skb->data + header_len);
        unicast_packet = (struct batadv_unicast_packet *)skb->data;
 
        /* inform the destination node that we are still missing a correct route
index e3a3499..cc27297 100644 (file)
@@ -513,7 +513,10 @@ static void hci_init2_req(struct hci_request *req, unsigned long opt)
 
        hci_setup_event_mask(req);
 
-       if (hdev->hci_ver > BLUETOOTH_VER_1_1)
+       /* AVM Berlin (31), aka "BlueFRITZ!", doesn't support the read
+        * local supported commands HCI command.
+        */
+       if (hdev->manufacturer != 31 && hdev->hci_ver > BLUETOOTH_VER_1_1)
                hci_req_add(req, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
 
        if (lmp_ssp_capable(hdev)) {
@@ -2165,10 +2168,6 @@ int hci_register_dev(struct hci_dev *hdev)
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       write_lock(&hci_dev_list_lock);
-       list_add(&hdev->list, &hci_dev_list);
-       write_unlock(&hci_dev_list_lock);
-
        hdev->workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
                                          WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->workqueue) {
@@ -2203,6 +2202,10 @@ int hci_register_dev(struct hci_dev *hdev)
        if (hdev->dev_type != HCI_AMP)
                set_bit(HCI_AUTO_OFF, &hdev->dev_flags);
 
+       write_lock(&hci_dev_list_lock);
+       list_add(&hdev->list, &hci_dev_list);
+       write_unlock(&hci_dev_list_lock);
+
        hci_notify(hdev, HCI_DEV_REG);
        hci_dev_hold(hdev);
 
@@ -2215,9 +2218,6 @@ err_wqueue:
        destroy_workqueue(hdev->req_workqueue);
 err:
        ida_simple_remove(&hci_index_ida, hdev->id);
-       write_lock(&hci_dev_list_lock);
-       list_del(&hdev->list);
-       write_unlock(&hci_dev_list_lock);
 
        return error;
 }
@@ -3399,8 +3399,16 @@ void hci_req_cmd_complete(struct hci_dev *hdev, u16 opcode, u8 status)
         */
        if (hdev->sent_cmd) {
                req_complete = bt_cb(hdev->sent_cmd)->req.complete;
-               if (req_complete)
+
+               if (req_complete) {
+                       /* We must set the complete callback to NULL to
+                        * avoid calling the callback more than once if
+                        * this function gets called again.
+                        */
+                       bt_cb(hdev->sent_cmd)->req.complete = NULL;
+
                        goto call_complete;
+               }
        }
 
        /* Remove all pending commands belonging to this request */
index 2ef6678..69363bd 100644 (file)
@@ -70,7 +70,8 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
                }
 
                mdst = br_mdb_get(br, skb, vid);
-               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb))
+               if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
+                   br_multicast_querier_exists(br))
                        br_multicast_deliver(mdst, skb);
                else
                        br_flood_deliver(br, skb, false);
index 1b8b8b8..8c561c0 100644 (file)
@@ -101,7 +101,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
                unicast = false;
        } else if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb, vid);
-               if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
+               if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) &&
+                   br_multicast_querier_exists(br)) {
                        if ((mdst && mdst->mglist) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
index 69af490..08e576a 100644 (file)
@@ -619,6 +619,9 @@ rehash:
        mp->br = br;
        mp->addr = *group;
 
+       setup_timer(&mp->timer, br_multicast_group_expired,
+                   (unsigned long)mp);
+
        hlist_add_head_rcu(&mp->hlist[mdb->ver], &mdb->mhash[hash]);
        mdb->size++;
 
@@ -1011,6 +1014,16 @@ static int br_ip6_multicast_mld2_report(struct net_bridge *br,
 }
 #endif
 
+static void br_multicast_update_querier_timer(struct net_bridge *br,
+                                             unsigned long max_delay)
+{
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       mod_timer(&br->multicast_querier_timer,
+                 jiffies + br->multicast_querier_interval);
+}
+
 /*
  * Add port to router_list
  *  list is maintained ordered by pointer value
@@ -1061,11 +1074,11 @@ timer:
 
 static void br_multicast_query_received(struct net_bridge *br,
                                        struct net_bridge_port *port,
-                                       int saddr)
+                                       int saddr,
+                                       unsigned long max_delay)
 {
        if (saddr)
-               mod_timer(&br->multicast_querier_timer,
-                         jiffies + br->multicast_querier_interval);
+               br_multicast_update_querier_timer(br, max_delay);
        else if (timer_pending(&br->multicast_querier_timer))
                return;
 
@@ -1093,8 +1106,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !!iph->saddr);
-
        group = ih->group;
 
        if (skb->len == sizeof(*ih)) {
@@ -1118,6 +1129,8 @@ static int br_ip4_multicast_query(struct net_bridge *br,
                            IGMPV3_MRC(ih3->code) * (HZ / IGMP_TIMER_SCALE) : 1;
        }
 
+       br_multicast_query_received(br, port, !!iph->saddr, max_delay);
+
        if (!group)
                goto out;
 
@@ -1126,7 +1139,6 @@ static int br_ip4_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1174,8 +1186,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
            (port && port->state == BR_STATE_DISABLED))
                goto out;
 
-       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr));
-
        if (skb->len == sizeof(*mld)) {
                if (!pskb_may_pull(skb, sizeof(*mld))) {
                        err = -EINVAL;
@@ -1185,7 +1195,7 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = msecs_to_jiffies(ntohs(mld->mld_maxdelay));
                if (max_delay)
                        group = &mld->mld_mca;
-       } else if (skb->len >= sizeof(*mld2q)) {
+       } else {
                if (!pskb_may_pull(skb, sizeof(*mld2q))) {
                        err = -EINVAL;
                        goto out;
@@ -1196,6 +1206,9 @@ static int br_ip6_multicast_query(struct net_bridge *br,
                max_delay = mld2q->mld2q_mrc ? MLDV2_MRC(ntohs(mld2q->mld2q_mrc)) : 1;
        }
 
+       br_multicast_query_received(br, port, !ipv6_addr_any(&ip6h->saddr),
+                                   max_delay);
+
        if (!group)
                goto out;
 
@@ -1204,7 +1217,6 @@ static int br_ip6_multicast_query(struct net_bridge *br,
        if (!mp)
                goto out;
 
-       setup_timer(&mp->timer, br_multicast_group_expired, (unsigned long)mp);
        mod_timer(&mp->timer, now + br->multicast_membership_interval);
        mp->timer_armed = true;
 
@@ -1642,6 +1654,8 @@ void br_multicast_init(struct net_bridge *br)
        br->multicast_querier_interval = 255 * HZ;
        br->multicast_membership_interval = 260 * HZ;
 
+       br->multicast_querier_delay_time = 0;
+
        spin_lock_init(&br->multicast_lock);
        setup_timer(&br->multicast_router_timer,
                    br_multicast_local_router_expired, 0);
@@ -1830,6 +1844,8 @@ unlock:
 
 int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
 {
+       unsigned long max_delay;
+
        val = !!val;
 
        spin_lock_bh(&br->multicast_lock);
@@ -1837,8 +1853,14 @@ int br_multicast_set_querier(struct net_bridge *br, unsigned long val)
                goto unlock;
 
        br->multicast_querier = val;
-       if (val)
-               br_multicast_start_querier(br);
+       if (!val)
+               goto unlock;
+
+       max_delay = br->multicast_query_response_interval;
+       if (!timer_pending(&br->multicast_querier_timer))
+               br->multicast_querier_delay_time = jiffies + max_delay;
+
+       br_multicast_start_querier(br);
 
 unlock:
        spin_unlock_bh(&br->multicast_lock);
index 3be89b3..2f7da41 100644 (file)
@@ -267,6 +267,7 @@ struct net_bridge
        unsigned long                   multicast_query_interval;
        unsigned long                   multicast_query_response_interval;
        unsigned long                   multicast_startup_query_interval;
+       unsigned long                   multicast_querier_delay_time;
 
        spinlock_t                      multicast_lock;
        struct net_bridge_mdb_htable __rcu *mdb;
@@ -501,6 +502,13 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
               (br->multicast_router == 1 &&
                timer_pending(&br->multicast_router_timer));
 }
+
+static inline bool br_multicast_querier_exists(struct net_bridge *br)
+{
+       return time_is_before_jiffies(br->multicast_querier_delay_time) &&
+              (br->multicast_querier ||
+               timer_pending(&br->multicast_querier_timer));
+}
 #else
 static inline int br_multicast_rcv(struct net_bridge *br,
                                   struct net_bridge_port *port,
@@ -557,6 +565,10 @@ static inline bool br_multicast_is_router(struct net_bridge *br)
 {
        return 0;
 }
+static inline bool br_multicast_querier_exists(struct net_bridge *br)
+{
+       return false;
+}
 static inline void br_mdb_init(void)
 {
 }
index 394bb96..3b9637f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     Sysfs attributes of bridge ports
+ *     Sysfs attributes of bridge
  *     Linux ethernet bridge
  *
  *     Authors:
index 00ee068..b84a1b1 100644 (file)
@@ -65,6 +65,7 @@ ipv6:
                nhoff += sizeof(struct ipv6hdr);
                break;
        }
+       case __constant_htons(ETH_P_8021AD):
        case __constant_htons(ETH_P_8021Q): {
                const struct vlan_hdr *vlan;
                struct vlan_hdr _vlan;
index b7de821..60533db 100644 (file)
@@ -1441,16 +1441,18 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
                atomic_set(&p->refcnt, 1);
                p->reachable_time =
                                neigh_rand_reach_time(p->base_reachable_time);
+               dev_hold(dev);
+               p->dev = dev;
+               write_pnet(&p->net, hold_net(net));
+               p->sysctl_table = NULL;
 
                if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) {
+                       release_net(net);
+                       dev_put(dev);
                        kfree(p);
                        return NULL;
                }
 
-               dev_hold(dev);
-               p->dev = dev;
-               write_pnet(&p->net, hold_net(net));
-               p->sysctl_table = NULL;
                write_lock_bh(&tbl->lock);
                p->next         = tbl->parms.next;
                tbl->parms.next = p;
@@ -2767,6 +2769,7 @@ EXPORT_SYMBOL(neigh_app_ns);
 
 #ifdef CONFIG_SYSCTL
 static int zero;
+static int int_max = INT_MAX;
 static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN);
 
 static int proc_unres_qlen(struct ctl_table *ctl, int write,
@@ -2819,19 +2822,25 @@ static struct neigh_sysctl_table {
                        .procname       = "mcast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_UCAST_PROBE] = {
                        .procname       = "ucast_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_APP_PROBE] = {
                        .procname       = "app_solicit",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_RETRANS_TIME] = {
                        .procname       = "retrans_time",
@@ -2874,7 +2883,9 @@ static struct neigh_sysctl_table {
                        .procname       = "proxy_qlen",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_ANYCAST_DELAY] = {
                        .procname       = "anycast_delay",
@@ -2916,19 +2927,25 @@ static struct neigh_sysctl_table {
                        .procname       = "gc_thresh1",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH2] = {
                        .procname       = "gc_thresh2",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                [NEIGH_VAR_GC_THRESH3] = {
                        .procname       = "gc_thresh3",
                        .maxlen         = sizeof(int),
                        .mode           = 0644,
-                       .proc_handler   = proc_dointvec,
+                       .extra1         = &zero,
+                       .extra2         = &int_max,
+                       .proc_handler   = proc_dointvec_minmax,
                },
                {},
        },
index 3de7408..ca198c1 100644 (file)
@@ -2156,7 +2156,7 @@ int ndo_dflt_fdb_del(struct ndmsg *ndm,
        /* If aging addresses are supported device will need to
         * implement its own handler for this.
         */
-       if (ndm->ndm_state & NUD_PERMANENT) {
+       if (!(ndm->ndm_state & NUD_PERMANENT)) {
                pr_info("%s: FDB only supports static addresses\n", dev->name);
                return -EINVAL;
        }
@@ -2384,7 +2384,7 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb)
        struct nlattr *extfilt;
        u32 filter_mask = 0;
 
-       extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct rtgenmsg),
+       extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg),
                                  IFLA_EXT_MASK);
        if (extfilt)
                filter_mask = nla_get_u32(extfilt);
index 20e02d2..2c3d0f5 100644 (file)
@@ -309,7 +309,8 @@ EXPORT_SYMBOL(__alloc_skb);
  * @frag_size: size of fragment, or 0 if head was kmalloced
  *
  * Allocate a new &sk_buff. Caller provides space holding head and
- * skb_shared_info. @data must have been allocated by kmalloc()
+ * skb_shared_info. @data must have been allocated by kmalloc() only if
+ * @frag_size is 0, otherwise data should come from the page allocator.
  * The return is the new skb buffer.
  * On a failure the return is %NULL, and @data is not freed.
  * Notes :
@@ -739,7 +740,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 
        skb_copy_secmark(new, old);
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        new->napi_id    = old->napi_id;
 #endif
 }
index 548d716..2c097c5 100644 (file)
@@ -900,7 +900,7 @@ set_rcvbuf:
                sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
                break;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        case SO_BUSY_POLL:
                /* allow unprivileged users to decrease the value */
                if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN))
@@ -1170,7 +1170,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE);
                break;
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        case SO_BUSY_POLL:
                v.val = sk->sk_ll_usec;
                break;
@@ -2292,7 +2292,7 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
        sk->sk_stamp = ktime_set(-1L, 0);
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        sk->sk_napi_id          =       0;
        sk->sk_ll_usec          =       sysctl_net_busy_read;
 #endif
index 6609686..31107ab 100644 (file)
@@ -21,7 +21,9 @@
 #include <net/net_ratelimit.h>
 #include <net/busy_poll.h>
 
+static int zero = 0;
 static int one = 1;
+static int ushort_max = USHRT_MAX;
 
 #ifdef CONFIG_RPS
 static int rps_sock_flow_sysctl(struct ctl_table *table, int write,
@@ -298,7 +300,7 @@ static struct ctl_table net_core_table[] = {
                .proc_handler   = flow_limit_table_len_sysctl
        },
 #endif /* CONFIG_NET_FLOW_LIMIT */
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
        {
                .procname       = "busy_poll",
                .data           = &sysctl_net_busy_poll,
@@ -339,7 +341,9 @@ static struct ctl_table netns_core_table[] = {
                .data           = &init_net.core.sysctl_somaxconn,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .extra1         = &zero,
+               .extra2         = &ushort_max,
+               .proc_handler   = proc_dointvec_minmax
        },
        { }
 };
index 8d48c39..34ca6d5 100644 (file)
@@ -772,7 +772,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
                ci = nla_data(tb[IFA_CACHEINFO]);
                if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) {
                        err = -EINVAL;
-                       goto errout;
+                       goto errout_free;
                }
                *pvalid_lft = ci->ifa_valid;
                *pprefered_lft = ci->ifa_prefered;
@@ -780,6 +780,8 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
 
        return ifa;
 
+errout_free:
+       inet_free_ifa(ifa);
 errout:
        return ERR_PTR(err);
 }
index ab3d814..109ee89 100644 (file)
@@ -477,7 +477,7 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
        }
 
        return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) -
-                net_adj) & ~(align - 1)) + (net_adj - 2);
+                net_adj) & ~(align - 1)) + net_adj - 2;
 }
 
 static void esp4_err(struct sk_buff *skb, u32 info)
index 49616fe..3df6d3e 100644 (file)
@@ -71,7 +71,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/slab.h>
-#include <linux/prefetch.h>
 #include <linux/export.h>
 #include <net/net_namespace.h>
 #include <net/ip.h>
@@ -1761,10 +1760,8 @@ static struct leaf *leaf_walk_rcu(struct tnode *p, struct rt_trie_node *c)
                        if (!c)
                                continue;
 
-                       if (IS_LEAF(c)) {
-                               prefetch(rcu_dereference_rtnl(p->child[idx]));
+                       if (IS_LEAF(c))
                                return (struct leaf *) c;
-                       }
 
                        /* Rescan start scanning in new node */
                        p = (struct tnode *) c;
@@ -2133,7 +2130,7 @@ static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat)
                max--;
 
        pointers = 0;
-       for (i = 1; i <= max; i++)
+       for (i = 1; i < max; i++)
                if (stat->nodesizes[i] != 0) {
                        seq_printf(seq, "  %u: %u",  i, stat->nodesizes[i]);
                        pointers += (1<<i) * stat->nodesizes[i];
index 1f6eab6..8d6939e 100644 (file)
@@ -383,7 +383,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev,
        if (daddr)
                memcpy(&iph->daddr, daddr, 4);
        if (iph->daddr)
-               return t->hlen;
+               return t->hlen + sizeof(*iph);
 
        return -(t->hlen + sizeof(*iph));
 }
index 7167b08..850525b 100644 (file)
@@ -76,9 +76,7 @@ int iptunnel_xmit(struct net *net, struct rtable *rt,
        iph->daddr      =       dst;
        iph->saddr      =       src;
        iph->ttl        =       ttl;
-       tunnel_ip_select_ident(skb,
-                              (const struct iphdr *)skb_inner_network_header(skb),
-                              &rt->dst);
+       __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
        err = ip_local_out(skb);
        if (unlikely(net_xmit_eval(err)))
index 6577a11..463bd12 100644 (file)
@@ -273,7 +273,7 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPFastOpenListenOverflow", LINUX_MIB_TCPFASTOPENLISTENOVERFLOW),
        SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD),
        SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES),
-       SNMP_MIB_ITEM("LowLatencyRxPackets", LINUX_MIB_LOWLATENCYRXPACKETS),
+       SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS),
        SNMP_MIB_SENTINEL
 };
 
index b2c123c..610e324 100644 (file)
@@ -36,6 +36,8 @@ static int tcp_adv_win_scale_min = -31;
 static int tcp_adv_win_scale_max = 31;
 static int ip_ttl_min = 1;
 static int ip_ttl_max = 255;
+static int tcp_syn_retries_min = 1;
+static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
 static int ip_ping_group_range_min[] = { 0, 0 };
 static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
 
@@ -332,7 +334,9 @@ static struct ctl_table ipv4_table[] = {
                .data           = &sysctl_tcp_syn_retries,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &tcp_syn_retries_min,
+               .extra2         = &tcp_syn_retries_max
        },
        {
                .procname       = "tcp_synack_retries",
index a9077f4..b6ae92a 100644 (file)
@@ -206,8 +206,8 @@ static u32 cubic_root(u64 a)
  */
 static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
 {
-       u64 offs;
-       u32 delta, t, bic_target, max_cnt;
+       u32 delta, bic_target, max_cnt;
+       u64 offs, t;
 
        ca->ack_cnt++;  /* count the number of ACKs */
 
@@ -250,9 +250,11 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
         * if the cwnd < 1 million packets !!!
         */
 
+       t = (s32)(tcp_time_stamp - ca->epoch_start);
+       t += msecs_to_jiffies(ca->delay_min >> 3);
        /* change the unit from HZ to bictcp_HZ */
-       t = ((tcp_time_stamp + msecs_to_jiffies(ca->delay_min>>3)
-             - ca->epoch_start) << BICTCP_HZ) / HZ;
+       t <<= BICTCP_HZ;
+       do_div(t, HZ);
 
        if (t < ca->bic_K)              /* t - K */
                offs = ca->bic_K - t;
@@ -414,7 +416,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us)
                return;
 
        /* Discard delay samples right after fast recovery */
-       if ((s32)(tcp_time_stamp - ca->epoch_start) < HZ)
+       if (ca->epoch_start && (s32)(tcp_time_stamp - ca->epoch_start) < HZ)
                return;
 
        delay = (rtt_us << 3) / USEC_PER_MSEC;
index cfdcf7b..da4241c 100644 (file)
@@ -813,8 +813,9 @@ static u32 inet6_addr_hash(const struct in6_addr *addr)
 /* On success it returns ifp with increased reference count */
 
 static struct inet6_ifaddr *
-ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
-             int scope, u32 flags)
+ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
+             const struct in6_addr *peer_addr, int pfxlen,
+             int scope, u32 flags, u32 valid_lft, u32 prefered_lft)
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
@@ -863,6 +864,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        }
 
        ifa->addr = *addr;
+       if (peer_addr)
+               ifa->peer_addr = *peer_addr;
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
@@ -872,6 +875,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
        ifa->flags = flags | IFA_F_TENTATIVE;
+       ifa->valid_lft = valid_lft;
+       ifa->prefered_lft = prefered_lft;
        ifa->cstamp = ifa->tstamp = jiffies;
        ifa->tokenized = false;
 
@@ -1123,8 +1128,9 @@ retry:
 
        ift = !max_addresses ||
              ipv6_count_addresses(idev) < max_addresses ?
-               ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_scope(&addr),
-                             addr_flags) : NULL;
+               ipv6_add_addr(idev, &addr, NULL, tmp_plen,
+                             ipv6_addr_scope(&addr), addr_flags,
+                             tmp_valid_lft, tmp_prefered_lft) : NULL;
        if (IS_ERR_OR_NULL(ift)) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
@@ -1136,8 +1142,6 @@ retry:
 
        spin_lock_bh(&ift->lock);
        ift->ifpub = ifp;
-       ift->valid_lft = tmp_valid_lft;
-       ift->prefered_lft = tmp_prefered_lft;
        ift->cstamp = now;
        ift->tstamp = tmp_tstamp;
        spin_unlock_bh(&ift->lock);
@@ -2179,16 +2183,19 @@ ok:
                         */
                        if (!max_addresses ||
                            ipv6_count_addresses(in6_dev) < max_addresses)
-                               ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+                               ifp = ipv6_add_addr(in6_dev, &addr, NULL,
+                                                   pinfo->prefix_len,
                                                    addr_type&IPV6_ADDR_SCOPE_MASK,
-                                                   addr_flags);
+                                                   addr_flags, valid_lft,
+                                                   prefered_lft);
 
                        if (IS_ERR_OR_NULL(ifp)) {
                                in6_dev_put(in6_dev);
                                return;
                        }
 
-                       update_lft = create = 1;
+                       update_lft = 0;
+                       create = 1;
                        ifp->cstamp = jiffies;
                        ifp->tokenized = tokenized;
                        addrconf_dad_start(ifp);
@@ -2209,7 +2216,7 @@ ok:
                                stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                        else
                                stored_lft = 0;
-                       if (!update_lft && stored_lft) {
+                       if (!update_lft && !create && stored_lft) {
                                if (valid_lft > MIN_VALID_LIFETIME ||
                                    valid_lft > stored_lft)
                                        update_lft = 1;
@@ -2455,17 +2462,10 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
                prefered_lft = timeout;
        }
 
-       ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+       ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags,
+                           valid_lft, prefered_lft);
 
        if (!IS_ERR(ifp)) {
-               spin_lock_bh(&ifp->lock);
-               ifp->valid_lft = valid_lft;
-               ifp->prefered_lft = prefered_lft;
-               ifp->tstamp = jiffies;
-               if (peer_pfx)
-                       ifp->peer_addr = *peer_pfx;
-               spin_unlock_bh(&ifp->lock);
-
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
                                      expires, flags);
                /*
@@ -2557,7 +2557,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 {
        struct inet6_ifaddr *ifp;
 
-       ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT);
+       ifp = ipv6_add_addr(idev, addr, NULL, plen,
+                           scope, IFA_F_PERMANENT, 0, 0);
        if (!IS_ERR(ifp)) {
                spin_lock_bh(&ifp->lock);
                ifp->flags &= ~IFA_F_TENTATIVE;
@@ -2683,7 +2684,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
 #endif
 
 
-       ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
+       ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0);
        if (!IS_ERR(ifp)) {
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp);
index 40ffd72..aeac0dc 100644 (file)
@@ -425,7 +425,7 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
                net_adj = 0;
 
        return ((mtu - x->props.header_len - crypto_aead_authsize(esp->aead) -
-                net_adj) & ~(align - 1)) + (net_adj - 2);
+                net_adj) & ~(align - 1)) + net_adj - 2;
 }
 
 static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
index 5fc9c7a..c4ff5bb 100644 (file)
@@ -993,14 +993,22 @@ static struct fib6_node * fib6_lookup_1(struct fib6_node *root,
 
                        if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) {
 #ifdef CONFIG_IPV6_SUBTREES
-                               if (fn->subtree)
-                                       fn = fib6_lookup_1(fn->subtree, args + 1);
+                               if (fn->subtree) {
+                                       struct fib6_node *sfn;
+                                       sfn = fib6_lookup_1(fn->subtree,
+                                                           args + 1);
+                                       if (!sfn)
+                                               goto backtrack;
+                                       fn = sfn;
+                               }
 #endif
-                               if (!fn || fn->fn_flags & RTN_RTINFO)
+                               if (fn->fn_flags & RTN_RTINFO)
                                        return fn;
                        }
                }
-
+#ifdef CONFIG_IPV6_SUBTREES
+backtrack:
+#endif
                if (fn->fn_flags & RTN_ROOT)
                        break;
 
@@ -1632,27 +1640,28 @@ static int fib6_age(struct rt6_info *rt, void *arg)
 
 static DEFINE_SPINLOCK(fib6_gc_lock);
 
-void fib6_run_gc(unsigned long expires, struct net *net)
+void fib6_run_gc(unsigned long expires, struct net *net, bool force)
 {
-       if (expires != ~0UL) {
+       unsigned long now;
+
+       if (force) {
                spin_lock_bh(&fib6_gc_lock);
-               gc_args.timeout = expires ? (int)expires :
-                       net->ipv6.sysctl.ip6_rt_gc_interval;
-       } else {
-               if (!spin_trylock_bh(&fib6_gc_lock)) {
-                       mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
-                       return;
-               }
-               gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
+       } else if (!spin_trylock_bh(&fib6_gc_lock)) {
+               mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ);
+               return;
        }
+       gc_args.timeout = expires ? (int)expires :
+                         net->ipv6.sysctl.ip6_rt_gc_interval;
 
        gc_args.more = icmp6_dst_gc();
 
        fib6_clean_all(net, fib6_age, 0, NULL);
+       now = jiffies;
+       net->ipv6.ip6_rt_last_gc = now;
 
        if (gc_args.more)
                mod_timer(&net->ipv6.ip6_fib_timer,
-                         round_jiffies(jiffies
+                         round_jiffies(now
                                        + net->ipv6.sysctl.ip6_rt_gc_interval));
        else
                del_timer(&net->ipv6.ip6_fib_timer);
@@ -1661,7 +1670,7 @@ void fib6_run_gc(unsigned long expires, struct net *net)
 
 static void fib6_gc_timer_cb(unsigned long arg)
 {
-       fib6_run_gc(0, (struct net *)arg);
+       fib6_run_gc(0, (struct net *)arg, true);
 }
 
 static int __net_init fib6_net_init(struct net *net)
index 583e8d4..03986d3 100644 (file)
@@ -259,10 +259,12 @@ static void __net_exit ip6mr_rules_exit(struct net *net)
 {
        struct mr6_table *mrt, *next;
 
+       rtnl_lock();
        list_for_each_entry_safe(mrt, next, &net->ipv6.mr6_tables, list) {
                list_del(&mrt->list);
                ip6mr_free_table(mrt);
        }
+       rtnl_unlock();
        fib_rules_unregister(net->ipv6.mr6_rules_ops);
 }
 #else
@@ -289,7 +291,10 @@ static int __net_init ip6mr_rules_init(struct net *net)
 
 static void __net_exit ip6mr_rules_exit(struct net *net)
 {
+       rtnl_lock();
        ip6mr_free_table(net->ipv6.mrt6);
+       net->ipv6.mrt6 = NULL;
+       rtnl_unlock();
 }
 #endif
 
index 24c0339..79aa965 100644 (file)
@@ -1576,7 +1576,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
        switch (event) {
        case NETDEV_CHANGEADDR:
                neigh_changeaddr(&nd_tbl, dev);
-               fib6_run_gc(~0UL, net);
+               fib6_run_gc(0, net, false);
                idev = in6_dev_get(dev);
                if (!idev)
                        break;
@@ -1586,7 +1586,7 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event,
                break;
        case NETDEV_DOWN:
                neigh_ifdown(&nd_tbl, dev);
-               fib6_run_gc(~0UL, net);
+               fib6_run_gc(0, net, false);
                break;
        case NETDEV_NOTIFY_PEERS:
                ndisc_send_unsol_na(dev);
index a8c891a..b70f897 100644 (file)
@@ -1311,7 +1311,6 @@ static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg),
 
 static int ip6_dst_gc(struct dst_ops *ops)
 {
-       unsigned long now = jiffies;
        struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops);
        int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval;
        int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size;
@@ -1321,13 +1320,12 @@ static int ip6_dst_gc(struct dst_ops *ops)
        int entries;
 
        entries = dst_entries_get_fast(ops);
-       if (time_after(rt_last_gc + rt_min_interval, now) &&
+       if (time_after(rt_last_gc + rt_min_interval, jiffies) &&
            entries <= rt_max_size)
                goto out;
 
        net->ipv6.ip6_rt_gc_expire++;
-       fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net);
-       net->ipv6.ip6_rt_last_gc = now;
+       fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, entries > rt_max_size);
        entries = dst_entries_get_slow(ops);
        if (entries < ops->gc_thresh)
                net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1;
@@ -2827,7 +2825,7 @@ int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write,
        net = (struct net *)ctl->extra1;
        delay = net->ipv6.sysctl.flush_delay;
        proc_dointvec(ctl, write, buffer, lenp, ppos);
-       fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
+       fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0);
        return 0;
 }
 
index 9da8620..ab8bd2c 100644 (file)
@@ -2081,6 +2081,7 @@ static int pfkey_xfrm_policy2msg(struct sk_buff *skb, const struct xfrm_policy *
                        pol->sadb_x_policy_type = IPSEC_POLICY_NONE;
        }
        pol->sadb_x_policy_dir = dir+1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = xp->index;
        pol->sadb_x_policy_priority = xp->priority;
 
@@ -3137,7 +3138,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
        pol->sadb_x_policy_dir = XFRM_POLICY_OUT + 1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = xp->index;
+       pol->sadb_x_policy_priority = xp->priority;
 
        /* Set sadb_comb's. */
        if (x->id.proto == IPPROTO_AH)
@@ -3525,6 +3528,7 @@ static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
        pol->sadb_x_policy_dir = dir + 1;
+       pol->sadb_x_policy_reserved = 0;
        pol->sadb_x_policy_id = 0;
        pol->sadb_x_policy_priority = 0;
 
index 8184d12..43dd752 100644 (file)
@@ -666,6 +666,8 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy,
                        if (sta->sdata->dev != dev)
                                continue;
 
+                       sinfo.filled = 0;
+                       sta_set_sinfo(sta, &sinfo);
                        i = 0;
                        ADD_STA_STATS(sta);
                }
index 3b7bfc0..22290a9 100644 (file)
@@ -229,6 +229,10 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta)
        enum nl80211_mesh_power_mode pm;
        bool do_buffer;
 
+       /* For non-assoc STA, prevent buffering or frame transmission */
+       if (sta->sta_state < IEEE80211_STA_ASSOC)
+               return;
+
        /*
         * use peer-specific power mode if peering is established and the
         * peer's power mode is known
index ae31968..cc9e02d 100644 (file)
 #include "led.h"
 
 #define IEEE80211_AUTH_TIMEOUT         (HZ / 5)
+#define IEEE80211_AUTH_TIMEOUT_LONG    (HZ / 2)
 #define IEEE80211_AUTH_TIMEOUT_SHORT   (HZ / 10)
 #define IEEE80211_AUTH_MAX_TRIES       3
 #define IEEE80211_AUTH_WAIT_ASSOC      (HZ * 5)
 #define IEEE80211_ASSOC_TIMEOUT                (HZ / 5)
+#define IEEE80211_ASSOC_TIMEOUT_LONG   (HZ / 2)
 #define IEEE80211_ASSOC_TIMEOUT_SHORT  (HZ / 10)
 #define IEEE80211_ASSOC_MAX_TRIES      3
 
@@ -209,8 +211,9 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_channel *channel,
                             const struct ieee80211_ht_operation *ht_oper,
                             const struct ieee80211_vht_operation *vht_oper,
-                            struct cfg80211_chan_def *chandef, bool verbose)
+                            struct cfg80211_chan_def *chandef, bool tracking)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct cfg80211_chan_def vht_chandef;
        u32 ht_cfreq, ret;
 
@@ -229,7 +232,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        ht_cfreq = ieee80211_channel_to_frequency(ht_oper->primary_chan,
                                                  channel->band);
        /* check that channel matches the right operating channel */
-       if (channel->center_freq != ht_cfreq) {
+       if (!tracking && channel->center_freq != ht_cfreq) {
                /*
                 * It's possible that some APs are confused here;
                 * Netgear WNDR3700 sometimes reports 4 higher than
@@ -237,11 +240,10 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                 * since we look at probe response/beacon data here
                 * it should be OK.
                 */
-               if (verbose)
-                       sdata_info(sdata,
-                                  "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
-                                  channel->center_freq, ht_cfreq,
-                                  ht_oper->primary_chan, channel->band);
+               sdata_info(sdata,
+                          "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n",
+                          channel->center_freq, ht_cfreq,
+                          ht_oper->primary_chan, channel->band);
                ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
                goto out;
        }
@@ -295,7 +297,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                                channel->band);
                break;
        default:
-               if (verbose)
+               if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                        sdata_info(sdata,
                                   "AP VHT operation IE has invalid channel width (%d), disable VHT\n",
                                   vht_oper->chan_width);
@@ -304,7 +306,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        }
 
        if (!cfg80211_chandef_valid(&vht_chandef)) {
-               if (verbose)
+               if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                        sdata_info(sdata,
                                   "AP VHT information is invalid, disable VHT\n");
                ret = IEEE80211_STA_DISABLE_VHT;
@@ -317,7 +319,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
        }
 
        if (!cfg80211_chandef_compatible(chandef, &vht_chandef)) {
-               if (verbose)
+               if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
                        sdata_info(sdata,
                                   "AP VHT information doesn't match HT, disable VHT\n");
                ret = IEEE80211_STA_DISABLE_VHT;
@@ -333,18 +335,27 @@ out:
        if (ret & IEEE80211_STA_DISABLE_VHT)
                vht_chandef = *chandef;
 
+       /*
+        * Ignore the DISABLED flag when we're already connected and only
+        * tracking the APs beacon for bandwidth changes - otherwise we
+        * might get disconnected here if we connect to an AP, update our
+        * regulatory information based on the AP's country IE and the
+        * information we have is wrong/outdated and disables the channel
+        * that we're actually using for the connection to the AP.
+        */
        while (!cfg80211_chandef_usable(sdata->local->hw.wiphy, chandef,
-                                       IEEE80211_CHAN_DISABLED)) {
+                                       tracking ? 0 :
+                                                  IEEE80211_CHAN_DISABLED)) {
                if (WARN_ON(chandef->width == NL80211_CHAN_WIDTH_20_NOHT)) {
                        ret = IEEE80211_STA_DISABLE_HT |
                              IEEE80211_STA_DISABLE_VHT;
-                       goto out;
+                       break;
                }
 
                ret |= chandef_downgrade(chandef);
        }
 
-       if (chandef->width != vht_chandef.width && verbose)
+       if (chandef->width != vht_chandef.width && !tracking)
                sdata_info(sdata,
                           "capabilities/regulatory prevented using AP HT/VHT configuration, downgraded\n");
 
@@ -384,7 +395,7 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
 
        /* calculate new channel (type) based on HT/VHT operation IEs */
        flags = ieee80211_determine_chantype(sdata, sband, chan, ht_oper,
-                                            vht_oper, &chandef, false);
+                                            vht_oper, &chandef, true);
 
        /*
         * Downgrade the new channel if we associated with restricted
@@ -3394,10 +3405,13 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
 
        if (tx_flags == 0) {
                auth_data->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
-               ifmgd->auth_data->timeout_started = true;
+               auth_data->timeout_started = true;
                run_again(sdata, auth_data->timeout);
        } else {
-               auth_data->timeout_started = false;
+               auth_data->timeout =
+                       round_jiffies_up(jiffies + IEEE80211_AUTH_TIMEOUT_LONG);
+               auth_data->timeout_started = true;
+               run_again(sdata, auth_data->timeout);
        }
 
        return 0;
@@ -3434,7 +3448,11 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
                assoc_data->timeout_started = true;
                run_again(sdata, assoc_data->timeout);
        } else {
-               assoc_data->timeout_started = false;
+               assoc_data->timeout =
+                       round_jiffies_up(jiffies +
+                                        IEEE80211_ASSOC_TIMEOUT_LONG);
+               assoc_data->timeout_started = true;
+               run_again(sdata, assoc_data->timeout);
        }
 
        return 0;
@@ -3829,7 +3847,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        ifmgd->flags |= ieee80211_determine_chantype(sdata, sband,
                                                     cbss->channel,
                                                     ht_oper, vht_oper,
-                                                    &chandef, true);
+                                                    &chandef, false);
 
        sdata->needed_rx_chains = min(ieee80211_ht_vht_rx_chains(sdata, cbss),
                                      local->rx_chains);
index 7fc5d0d..3401262 100644 (file)
@@ -99,10 +99,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        }
        mutex_unlock(&local->sta_mtx);
 
-       /* remove all interfaces */
+       /* remove all interfaces that were created in the driver */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               if (!ieee80211_sdata_running(sdata))
+               if (!ieee80211_sdata_running(sdata) ||
+                   sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR)
                        continue;
+
                drv_remove_interface(local, sdata);
        }
 
index ac7ef54..e6512e2 100644 (file)
@@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        struct minstrel_rate *msr, *mr;
        unsigned int ndx;
        bool mrr_capable;
-       bool prev_sample = mi->prev_sample;
+       bool prev_sample;
        int delta;
        int sampling_ratio;
 
@@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
                        (mi->sample_count + mi->sample_deferred / 2);
 
        /* delta < 0: no sampling required */
+       prev_sample = mi->prev_sample;
        mi->prev_sample = false;
        if (delta < 0 || (!mrr_capable && prev_sample))
                return;
index 5b2d301..f5aed96 100644 (file)
@@ -804,10 +804,18 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 
        sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES];
        info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+       rate->count = 1;
+
+       if (sample_idx / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) {
+               int idx = sample_idx % ARRAY_SIZE(mp->cck_rates);
+               rate->idx = mp->cck_rates[idx];
+               rate->flags = 0;
+               return;
+       }
+
        rate->idx = sample_idx % MCS_GROUP_RATES +
                    (sample_group->streams - 1) * MCS_GROUP_RATES;
        rate->flags = IEEE80211_TX_RC_MCS | sample_group->flags;
-       rate->count = 1;
 }
 
 static void
index 23dbcfc..2c5a79b 100644 (file)
@@ -936,8 +936,14 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
 
-       /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */
-       if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) {
+       /*
+        * Drop duplicate 802.11 retransmissions
+        * (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
+        */
+       if (rx->skb->len >= 24 && rx->sta &&
+           !ieee80211_is_ctl(hdr->frame_control) &&
+           !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
+           !is_multicast_ether_addr(hdr->addr1)) {
                if (unlikely(ieee80211_has_retry(hdr->frame_control) &&
                             rx->sta->last_seq_ctrl[rx->seqno_idx] ==
                             hdr->seq_ctrl)) {
index c63b618..4fd1ca9 100644 (file)
@@ -293,6 +293,11 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
                       sizeof(exp->tuple.dst.u3) - len);
 
        exp->tuple.dst.u.all = *dst;
+
+#ifdef CONFIG_NF_NAT_NEEDED
+       memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
+       memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+#endif
 }
 EXPORT_SYMBOL_GPL(nf_ct_expect_init);
 
index 7dcc376..2f80107 100644 (file)
@@ -526,7 +526,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
        const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
        __u32 seq, ack, sack, end, win, swin;
        s16 receiver_offset;
-       bool res;
+       bool res, in_recv_win;
 
        /*
         * Get the required data from the packet.
@@ -649,14 +649,18 @@ static bool tcp_in_window(const struct nf_conn *ct,
                 receiver->td_end, receiver->td_maxend, receiver->td_maxwin,
                 receiver->td_scale);
 
+       /* Is the ending sequence in the receive window (if available)? */
+       in_recv_win = !receiver->td_maxwin ||
+                     after(end, sender->td_end - receiver->td_maxwin - 1);
+
        pr_debug("tcp_in_window: I=%i II=%i III=%i IV=%i\n",
                 before(seq, sender->td_maxend + 1),
-                after(end, sender->td_end - receiver->td_maxwin - 1),
+                (in_recv_win ? 1 : 0),
                 before(sack, receiver->td_end + 1),
                 after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1));
 
        if (before(seq, sender->td_maxend + 1) &&
-           after(end, sender->td_end - receiver->td_maxwin - 1) &&
+           in_recv_win &&
            before(sack, receiver->td_end + 1) &&
            after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1)) {
                /*
@@ -725,7 +729,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
                        nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
                        "nf_ct_tcp: %s ",
                        before(seq, sender->td_maxend + 1) ?
-                       after(end, sender->td_end - receiver->td_maxwin - 1) ?
+                       in_recv_win ?
                        before(sack, receiver->td_end + 1) ?
                        after(sack, receiver->td_end - MAXACKWINDOW(sender) - 1) ? "BUG"
                        : "ACK is under the lower bound (possible overly delayed ACK)"
index 962e979..d92cc31 100644 (file)
@@ -419,6 +419,7 @@ __build_packet_message(struct nfnl_log_net *log,
        nfmsg->version = NFNETLINK_V0;
        nfmsg->res_id = htons(inst->group_num);
 
+       memset(&pmsg, 0, sizeof(pmsg));
        pmsg.hw_protocol        = skb->protocol;
        pmsg.hook               = hooknum;
 
@@ -498,7 +499,10 @@ __build_packet_message(struct nfnl_log_net *log,
        if (indev && skb->dev &&
            skb->mac_header != skb->network_header) {
                struct nfulnl_msg_packet_hw phw;
-               int len = dev_parse_header(skb, phw.hw_addr);
+               int len;
+
+               memset(&phw, 0, sizeof(phw));
+               len = dev_parse_header(skb, phw.hw_addr);
                if (len > 0) {
                        phw.hw_addrlen = htons(len);
                        if (nla_put(inst->skb, NFULA_HWADDR, sizeof(phw), &phw))
index 971ea14..8a703c3 100644 (file)
@@ -463,7 +463,10 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
        if (indev && entskb->dev &&
            entskb->mac_header != entskb->network_header) {
                struct nfqnl_msg_packet_hw phw;
-               int len = dev_parse_header(entskb, phw.hw_addr);
+               int len;
+
+               memset(&phw, 0, sizeof(phw));
+               len = dev_parse_header(entskb, phw.hw_addr);
                if (len) {
                        phw.hw_addrlen = htons(len);
                        if (nla_put(skb, NFQA_HWADDR, sizeof(phw), &phw))
index 7011c71..6113cc7 100644 (file)
@@ -52,7 +52,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
 {
        const struct xt_tcpmss_info *info = par->targinfo;
        struct tcphdr *tcph;
-       unsigned int tcplen, i;
+       int len, tcp_hdrlen;
+       unsigned int i;
        __be16 oldval;
        u16 newmss;
        u8 *opt;
@@ -64,11 +65,14 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        if (!skb_make_writable(skb, skb->len))
                return -1;
 
-       tcplen = skb->len - tcphoff;
+       len = skb->len - tcphoff;
+       if (len < (int)sizeof(struct tcphdr))
+               return -1;
+
        tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
+       tcp_hdrlen = tcph->doff * 4;
 
-       /* Header cannot be larger than the packet */
-       if (tcplen < tcph->doff*4)
+       if (len < tcp_hdrlen)
                return -1;
 
        if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
@@ -87,9 +91,8 @@ tcpmss_mangle_packet(struct sk_buff *skb,
                newmss = info->mss;
 
        opt = (u_int8_t *)tcph;
-       for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
-               if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
-                   opt[i+1] == TCPOLEN_MSS) {
+       for (i = sizeof(struct tcphdr); i <= tcp_hdrlen - TCPOLEN_MSS; i += optlen(opt, i)) {
+               if (opt[i] == TCPOPT_MSS && opt[i+1] == TCPOLEN_MSS) {
                        u_int16_t oldmss;
 
                        oldmss = (opt[i+2] << 8) | opt[i+3];
@@ -112,9 +115,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
        }
 
        /* There is data after the header so the option can't be added
-          without moving it, and doing so may make the SYN packet
-          itself too large. Accept the packet unmodified instead. */
-       if (tcplen > tcph->doff*4)
+        * without moving it, and doing so may make the SYN packet
+        * itself too large. Accept the packet unmodified instead.
+        */
+       if (len > tcp_hdrlen)
                return 0;
 
        /*
@@ -143,10 +147,10 @@ tcpmss_mangle_packet(struct sk_buff *skb,
                newmss = min(newmss, (u16)1220);
 
        opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
-       memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
+       memmove(opt + TCPOLEN_MSS, opt, len - sizeof(struct tcphdr));
 
        inet_proto_csum_replace2(&tcph->check, skb,
-                                htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
+                                htons(len), htons(len + TCPOLEN_MSS), 1);
        opt[0] = TCPOPT_MSS;
        opt[1] = TCPOLEN_MSS;
        opt[2] = (newmss & 0xff00) >> 8;
index b68fa19..625fa1d 100644 (file)
@@ -38,7 +38,7 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
        struct tcphdr *tcph;
        u_int16_t n, o;
        u_int8_t *opt;
-       int len;
+       int len, tcp_hdrlen;
 
        /* This is a fragment, no TCP header is available */
        if (par->fragoff != 0)
@@ -52,7 +52,9 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
                return NF_DROP;
 
        tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
-       if (tcph->doff * 4 > len)
+       tcp_hdrlen = tcph->doff * 4;
+
+       if (len < tcp_hdrlen)
                return NF_DROP;
 
        opt  = (u_int8_t *)tcph;
@@ -61,10 +63,10 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb,
         * Walk through all TCP options - if we find some option to remove,
         * set all octets to %TCPOPT_NOP and adjust checksum.
         */
-       for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) {
+       for (i = sizeof(struct tcphdr); i < tcp_hdrlen - 1; i += optl) {
                optl = optlen(opt, i);
 
-               if (i + optl > tcp_hdrlen(skb))
+               if (i + optl > tcp_hdrlen)
                        break;
 
                if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i]))
index f8b7191..20b1591 100644 (file)
@@ -172,7 +172,7 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
 
                /* Ignore non-transparent sockets,
                   if XT_SOCKET_TRANSPARENT is used */
-               if (info && info->flags & XT_SOCKET_TRANSPARENT)
+               if (info->flags & XT_SOCKET_TRANSPARENT)
                        transparent = ((sk->sk_state != TCP_TIME_WAIT &&
                                        inet_sk(sk)->transparent) ||
                                       (sk->sk_state == TCP_TIME_WAIT &&
@@ -196,7 +196,11 @@ socket_match(const struct sk_buff *skb, struct xt_action_param *par,
 static bool
 socket_mt4_v0(const struct sk_buff *skb, struct xt_action_param *par)
 {
-       return socket_match(skb, par, NULL);
+       static struct xt_socket_mtinfo1 xt_info_v0 = {
+               .flags = 0,
+       };
+
+       return socket_match(skb, par, &xt_info_v0);
 }
 
 static bool
@@ -314,7 +318,7 @@ socket_mt6_v1_v2(const struct sk_buff *skb, struct xt_action_param *par)
 
                /* Ignore non-transparent sockets,
                   if XT_SOCKET_TRANSPARENT is used */
-               if (info && info->flags & XT_SOCKET_TRANSPARENT)
+               if (info->flags & XT_SOCKET_TRANSPARENT)
                        transparent = ((sk->sk_state != TCP_TIME_WAIT &&
                                        inet_sk(sk)->transparent) ||
                                       (sk->sk_state == TCP_TIME_WAIT &&
index c15042f..a110064 100644 (file)
@@ -691,8 +691,8 @@ static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
 {
        struct netlbl_domhsh_walk_arg *cb_arg = arg;
 
-       if (entry->type == NETLBL_NLTYPE_CIPSOV4 &&
-           entry->type_def.cipsov4->doi == cb_arg->doi)
+       if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
+           entry->def.cipso->doi == cb_arg->doi)
                return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
 
        return 0;
index 6bb1d42..85d842e 100644 (file)
@@ -84,15 +84,15 @@ static void netlbl_domhsh_free_entry(struct rcu_head *entry)
 #endif /* IPv6 */
 
        ptr = container_of(entry, struct netlbl_dom_map, rcu);
-       if (ptr->type == NETLBL_NLTYPE_ADDRSELECT) {
+       if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) {
                netlbl_af4list_foreach_safe(iter4, tmp4,
-                                           &ptr->type_def.addrsel->list4) {
+                                           &ptr->def.addrsel->list4) {
                        netlbl_af4list_remove_entry(iter4);
                        kfree(netlbl_domhsh_addr4_entry(iter4));
                }
 #if IS_ENABLED(CONFIG_IPV6)
                netlbl_af6list_foreach_safe(iter6, tmp6,
-                                           &ptr->type_def.addrsel->list6) {
+                                           &ptr->def.addrsel->list6) {
                        netlbl_af6list_remove_entry(iter6);
                        kfree(netlbl_domhsh_addr6_entry(iter6));
                }
@@ -213,21 +213,21 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
                if (addr4 != NULL) {
                        struct netlbl_domaddr4_map *map4;
                        map4 = netlbl_domhsh_addr4_entry(addr4);
-                       type = map4->type;
-                       cipsov4 = map4->type_def.cipsov4;
+                       type = map4->def.type;
+                       cipsov4 = map4->def.cipso;
                        netlbl_af4list_audit_addr(audit_buf, 0, NULL,
                                                  addr4->addr, addr4->mask);
 #if IS_ENABLED(CONFIG_IPV6)
                } else if (addr6 != NULL) {
                        struct netlbl_domaddr6_map *map6;
                        map6 = netlbl_domhsh_addr6_entry(addr6);
-                       type = map6->type;
+                       type = map6->def.type;
                        netlbl_af6list_audit_addr(audit_buf, 0, NULL,
                                                  &addr6->addr, &addr6->mask);
 #endif /* IPv6 */
                } else {
-                       type = entry->type;
-                       cipsov4 = entry->type_def.cipsov4;
+                       type = entry->def.type;
+                       cipsov4 = entry->def.cipso;
                }
                switch (type) {
                case NETLBL_NLTYPE_UNLABELED:
@@ -265,26 +265,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
        if (entry == NULL)
                return -EINVAL;
 
-       switch (entry->type) {
+       switch (entry->def.type) {
        case NETLBL_NLTYPE_UNLABELED:
-               if (entry->type_def.cipsov4 != NULL ||
-                   entry->type_def.addrsel != NULL)
+               if (entry->def.cipso != NULL || entry->def.addrsel != NULL)
                        return -EINVAL;
                break;
        case NETLBL_NLTYPE_CIPSOV4:
-               if (entry->type_def.cipsov4 == NULL)
+               if (entry->def.cipso == NULL)
                        return -EINVAL;
                break;
        case NETLBL_NLTYPE_ADDRSELECT:
-               netlbl_af4list_foreach(iter4, &entry->type_def.addrsel->list4) {
+               netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) {
                        map4 = netlbl_domhsh_addr4_entry(iter4);
-                       switch (map4->type) {
+                       switch (map4->def.type) {
                        case NETLBL_NLTYPE_UNLABELED:
-                               if (map4->type_def.cipsov4 != NULL)
+                               if (map4->def.cipso != NULL)
                                        return -EINVAL;
                                break;
                        case NETLBL_NLTYPE_CIPSOV4:
-                               if (map4->type_def.cipsov4 == NULL)
+                               if (map4->def.cipso == NULL)
                                        return -EINVAL;
                                break;
                        default:
@@ -292,9 +291,9 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
                        }
                }
 #if IS_ENABLED(CONFIG_IPV6)
-               netlbl_af6list_foreach(iter6, &entry->type_def.addrsel->list6) {
+               netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) {
                        map6 = netlbl_domhsh_addr6_entry(iter6);
-                       switch (map6->type) {
+                       switch (map6->def.type) {
                        case NETLBL_NLTYPE_UNLABELED:
                                break;
                        default:
@@ -402,32 +401,31 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                        rcu_assign_pointer(netlbl_domhsh_def, entry);
                }
 
-               if (entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+               if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
                        netlbl_af4list_foreach_rcu(iter4,
-                                              &entry->type_def.addrsel->list4)
+                                                  &entry->def.addrsel->list4)
                                netlbl_domhsh_audit_add(entry, iter4, NULL,
                                                        ret_val, audit_info);
 #if IS_ENABLED(CONFIG_IPV6)
                        netlbl_af6list_foreach_rcu(iter6,
-                                              &entry->type_def.addrsel->list6)
+                                                  &entry->def.addrsel->list6)
                                netlbl_domhsh_audit_add(entry, NULL, iter6,
                                                        ret_val, audit_info);
 #endif /* IPv6 */
                } else
                        netlbl_domhsh_audit_add(entry, NULL, NULL,
                                                ret_val, audit_info);
-       } else if (entry_old->type == NETLBL_NLTYPE_ADDRSELECT &&
-                  entry->type == NETLBL_NLTYPE_ADDRSELECT) {
+       } else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT &&
+                  entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
                struct list_head *old_list4;
                struct list_head *old_list6;
 
-               old_list4 = &entry_old->type_def.addrsel->list4;
-               old_list6 = &entry_old->type_def.addrsel->list6;
+               old_list4 = &entry_old->def.addrsel->list4;
+               old_list6 = &entry_old->def.addrsel->list6;
 
                /* we only allow the addition of address selectors if all of
                 * the selectors do not exist in the existing domain map */
-               netlbl_af4list_foreach_rcu(iter4,
-                                          &entry->type_def.addrsel->list4)
+               netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4)
                        if (netlbl_af4list_search_exact(iter4->addr,
                                                        iter4->mask,
                                                        old_list4)) {
@@ -435,8 +433,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                                goto add_return;
                        }
 #if IS_ENABLED(CONFIG_IPV6)
-               netlbl_af6list_foreach_rcu(iter6,
-                                          &entry->type_def.addrsel->list6)
+               netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6)
                        if (netlbl_af6list_search_exact(&iter6->addr,
                                                        &iter6->mask,
                                                        old_list6)) {
@@ -446,7 +443,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
 #endif /* IPv6 */
 
                netlbl_af4list_foreach_safe(iter4, tmp4,
-                                           &entry->type_def.addrsel->list4) {
+                                           &entry->def.addrsel->list4) {
                        netlbl_af4list_remove_entry(iter4);
                        iter4->valid = 1;
                        ret_val = netlbl_af4list_add(iter4, old_list4);
@@ -457,7 +454,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
                }
 #if IS_ENABLED(CONFIG_IPV6)
                netlbl_af6list_foreach_safe(iter6, tmp6,
-                                           &entry->type_def.addrsel->list6) {
+                                           &entry->def.addrsel->list6) {
                        netlbl_af6list_remove_entry(iter6);
                        iter6->valid = 1;
                        ret_val = netlbl_af6list_add(iter6, old_list6);
@@ -538,18 +535,18 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
                struct netlbl_af4list *iter4;
                struct netlbl_domaddr4_map *map4;
 
-               switch (entry->type) {
+               switch (entry->def.type) {
                case NETLBL_NLTYPE_ADDRSELECT:
                        netlbl_af4list_foreach_rcu(iter4,
-                                            &entry->type_def.addrsel->list4) {
+                                            &entry->def.addrsel->list4) {
                                map4 = netlbl_domhsh_addr4_entry(iter4);
-                               cipso_v4_doi_putdef(map4->type_def.cipsov4);
+                               cipso_v4_doi_putdef(map4->def.cipso);
                        }
                        /* no need to check the IPv6 list since we currently
                         * support only unlabeled protocols for IPv6 */
                        break;
                case NETLBL_NLTYPE_CIPSOV4:
-                       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+                       cipso_v4_doi_putdef(entry->def.cipso);
                        break;
                }
                call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
@@ -590,20 +587,21 @@ int netlbl_domhsh_remove_af4(const char *domain,
                entry_map = netlbl_domhsh_search(domain);
        else
                entry_map = netlbl_domhsh_search_def(domain);
-       if (entry_map == NULL || entry_map->type != NETLBL_NLTYPE_ADDRSELECT)
+       if (entry_map == NULL ||
+           entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
                goto remove_af4_failure;
 
        spin_lock(&netlbl_domhsh_lock);
        entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
-                                          &entry_map->type_def.addrsel->list4);
+                                          &entry_map->def.addrsel->list4);
        spin_unlock(&netlbl_domhsh_lock);
 
        if (entry_addr == NULL)
                goto remove_af4_failure;
-       netlbl_af4list_foreach_rcu(iter4, &entry_map->type_def.addrsel->list4)
+       netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
                goto remove_af4_single_addr;
 #if IS_ENABLED(CONFIG_IPV6)
-       netlbl_af6list_foreach_rcu(iter6, &entry_map->type_def.addrsel->list6)
+       netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
                goto remove_af4_single_addr;
 #endif /* IPv6 */
        /* the domain mapping is empty so remove it from the mapping table */
@@ -616,7 +614,7 @@ remove_af4_single_addr:
         * shouldn't be a problem */
        synchronize_rcu();
        entry = netlbl_domhsh_addr4_entry(entry_addr);
-       cipso_v4_doi_putdef(entry->type_def.cipsov4);
+       cipso_v4_doi_putdef(entry->def.cipso);
        kfree(entry);
        return 0;
 
@@ -693,8 +691,8 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
  * responsible for ensuring that rcu_read_[un]lock() is called.
  *
  */
-struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
-                                                      __be32 addr)
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
+                                                    __be32 addr)
 {
        struct netlbl_dom_map *dom_iter;
        struct netlbl_af4list *addr_iter;
@@ -702,15 +700,13 @@ struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
        dom_iter = netlbl_domhsh_search_def(domain);
        if (dom_iter == NULL)
                return NULL;
-       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
-               return NULL;
 
-       addr_iter = netlbl_af4list_search(addr,
-                                         &dom_iter->type_def.addrsel->list4);
+       if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
+               return &dom_iter->def;
+       addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4);
        if (addr_iter == NULL)
                return NULL;
-
-       return netlbl_domhsh_addr4_entry(addr_iter);
+       return &(netlbl_domhsh_addr4_entry(addr_iter)->def);
 }
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -725,7 +721,7 @@ struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
  * responsible for ensuring that rcu_read_[un]lock() is called.
  *
  */
-struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
                                                   const struct in6_addr *addr)
 {
        struct netlbl_dom_map *dom_iter;
@@ -734,15 +730,13 @@ struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
        dom_iter = netlbl_domhsh_search_def(domain);
        if (dom_iter == NULL)
                return NULL;
-       if (dom_iter->type != NETLBL_NLTYPE_ADDRSELECT)
-               return NULL;
 
-       addr_iter = netlbl_af6list_search(addr,
-                                         &dom_iter->type_def.addrsel->list6);
+       if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
+               return &dom_iter->def;
+       addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6);
        if (addr_iter == NULL)
                return NULL;
-
-       return netlbl_domhsh_addr6_entry(addr_iter);
+       return &(netlbl_domhsh_addr6_entry(addr_iter)->def);
 }
 #endif /* IPv6 */
 
index 90872c4..b9be0ee 100644 (file)
 #define NETLBL_DOMHSH_BITSIZE       7
 
 /* Domain mapping definition structures */
+struct netlbl_domaddr_map {
+       struct list_head list4;
+       struct list_head list6;
+};
+struct netlbl_dommap_def {
+       u32 type;
+       union {
+               struct netlbl_domaddr_map *addrsel;
+               struct cipso_v4_doi *cipso;
+       };
+};
 #define netlbl_domhsh_addr4_entry(iter) \
        container_of(iter, struct netlbl_domaddr4_map, list)
 struct netlbl_domaddr4_map {
-       u32 type;
-       union {
-               struct cipso_v4_doi *cipsov4;
-       } type_def;
+       struct netlbl_dommap_def def;
 
        struct netlbl_af4list list;
 };
 #define netlbl_domhsh_addr6_entry(iter) \
        container_of(iter, struct netlbl_domaddr6_map, list)
 struct netlbl_domaddr6_map {
-       u32 type;
-
-       /* NOTE: no 'type_def' union needed at present since we don't currently
-        *       support any IPv6 labeling protocols */
+       struct netlbl_dommap_def def;
 
        struct netlbl_af6list list;
 };
-struct netlbl_domaddr_map {
-       struct list_head list4;
-       struct list_head list6;
-};
+
 struct netlbl_dom_map {
        char *domain;
-       u32 type;
-       union {
-               struct cipso_v4_doi *cipsov4;
-               struct netlbl_domaddr_map *addrsel;
-       } type_def;
+       struct netlbl_dommap_def def;
 
        u32 valid;
        struct list_head list;
@@ -97,16 +95,16 @@ int netlbl_domhsh_remove_af4(const char *domain,
 int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
 int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
 struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
-struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
-                                                      __be32 addr);
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
+                                                    __be32 addr);
+#if IS_ENABLED(CONFIG_IPV6)
+struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
+                                                  const struct in6_addr *addr);
+#endif /* IPv6 */
+
 int netlbl_domhsh_walk(u32 *skip_bkt,
                     u32 *skip_chain,
                     int (*callback) (struct netlbl_dom_map *entry, void *arg),
                     void *cb_arg);
 
-#if IS_ENABLED(CONFIG_IPV6)
-struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
-                                                 const struct in6_addr *addr);
-#endif /* IPv6 */
-
 #endif
index 7c94aed..96a458e 100644 (file)
@@ -122,7 +122,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
        }
 
        if (addr == NULL && mask == NULL)
-               entry->type = NETLBL_NLTYPE_UNLABELED;
+               entry->def.type = NETLBL_NLTYPE_UNLABELED;
        else if (addr != NULL && mask != NULL) {
                addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
                if (addrmap == NULL)
@@ -137,7 +137,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        map4 = kzalloc(sizeof(*map4), GFP_ATOMIC);
                        if (map4 == NULL)
                                goto cfg_unlbl_map_add_failure;
-                       map4->type = NETLBL_NLTYPE_UNLABELED;
+                       map4->def.type = NETLBL_NLTYPE_UNLABELED;
                        map4->list.addr = addr4->s_addr & mask4->s_addr;
                        map4->list.mask = mask4->s_addr;
                        map4->list.valid = 1;
@@ -154,7 +154,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        map6 = kzalloc(sizeof(*map6), GFP_ATOMIC);
                        if (map6 == NULL)
                                goto cfg_unlbl_map_add_failure;
-                       map6->type = NETLBL_NLTYPE_UNLABELED;
+                       map6->def.type = NETLBL_NLTYPE_UNLABELED;
                        map6->list.addr = *addr6;
                        map6->list.addr.s6_addr32[0] &= mask6->s6_addr32[0];
                        map6->list.addr.s6_addr32[1] &= mask6->s6_addr32[1];
@@ -174,8 +174,8 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
                        break;
                }
 
-               entry->type_def.addrsel = addrmap;
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
        } else {
                ret_val = -EINVAL;
                goto cfg_unlbl_map_add_failure;
@@ -355,8 +355,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
        }
 
        if (addr == NULL && mask == NULL) {
-               entry->type_def.cipsov4 = doi_def;
-               entry->type = NETLBL_NLTYPE_CIPSOV4;
+               entry->def.cipso = doi_def;
+               entry->def.type = NETLBL_NLTYPE_CIPSOV4;
        } else if (addr != NULL && mask != NULL) {
                addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
                if (addrmap == NULL)
@@ -367,8 +367,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
                addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
                if (addrinfo == NULL)
                        goto out_addrinfo;
-               addrinfo->type_def.cipsov4 = doi_def;
-               addrinfo->type = NETLBL_NLTYPE_CIPSOV4;
+               addrinfo->def.cipso = doi_def;
+               addrinfo->def.type = NETLBL_NLTYPE_CIPSOV4;
                addrinfo->list.addr = addr->s_addr & mask->s_addr;
                addrinfo->list.mask = mask->s_addr;
                addrinfo->list.valid = 1;
@@ -376,8 +376,8 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
                if (ret_val != 0)
                        goto cfg_cipsov4_map_add_failure;
 
-               entry->type_def.addrsel = addrmap;
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
        } else {
                ret_val = -EINVAL;
                goto out_addrmap;
@@ -657,14 +657,14 @@ int netlbl_sock_setattr(struct sock *sk,
        }
        switch (family) {
        case AF_INET:
-               switch (dom_entry->type) {
+               switch (dom_entry->def.type) {
                case NETLBL_NLTYPE_ADDRSELECT:
                        ret_val = -EDESTADDRREQ;
                        break;
                case NETLBL_NLTYPE_CIPSOV4:
                        ret_val = cipso_v4_sock_setattr(sk,
-                                                   dom_entry->type_def.cipsov4,
-                                                   secattr);
+                                                       dom_entry->def.cipso,
+                                                       secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        ret_val = 0;
@@ -754,23 +754,22 @@ int netlbl_conn_setattr(struct sock *sk,
 {
        int ret_val;
        struct sockaddr_in *addr4;
-       struct netlbl_domaddr4_map *af4_entry;
+       struct netlbl_dommap_def *entry;
 
        rcu_read_lock();
        switch (addr->sa_family) {
        case AF_INET:
                addr4 = (struct sockaddr_in *)addr;
-               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
-                                                      addr4->sin_addr.s_addr);
-               if (af4_entry == NULL) {
+               entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                  addr4->sin_addr.s_addr);
+               if (entry == NULL) {
                        ret_val = -ENOENT;
                        goto conn_setattr_return;
                }
-               switch (af4_entry->type) {
+               switch (entry->type) {
                case NETLBL_NLTYPE_CIPSOV4:
                        ret_val = cipso_v4_sock_setattr(sk,
-                                                  af4_entry->type_def.cipsov4,
-                                                  secattr);
+                                                       entry->cipso, secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        /* just delete the protocols we support for right now
@@ -812,36 +811,21 @@ int netlbl_req_setattr(struct request_sock *req,
                       const struct netlbl_lsm_secattr *secattr)
 {
        int ret_val;
-       struct netlbl_dom_map *dom_entry;
-       struct netlbl_domaddr4_map *af4_entry;
-       u32 proto_type;
-       struct cipso_v4_doi *proto_cv4;
+       struct netlbl_dommap_def *entry;
 
        rcu_read_lock();
-       dom_entry = netlbl_domhsh_getentry(secattr->domain);
-       if (dom_entry == NULL) {
-               ret_val = -ENOENT;
-               goto req_setattr_return;
-       }
        switch (req->rsk_ops->family) {
        case AF_INET:
-               if (dom_entry->type == NETLBL_NLTYPE_ADDRSELECT) {
-                       struct inet_request_sock *req_inet = inet_rsk(req);
-                       af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
-                                                           req_inet->rmt_addr);
-                       if (af4_entry == NULL) {
-                               ret_val = -ENOENT;
-                               goto req_setattr_return;
-                       }
-                       proto_type = af4_entry->type;
-                       proto_cv4 = af4_entry->type_def.cipsov4;
-               } else {
-                       proto_type = dom_entry->type;
-                       proto_cv4 = dom_entry->type_def.cipsov4;
+               entry = netlbl_domhsh_getentry_af4(secattr->domain,
+                                                  inet_rsk(req)->rmt_addr);
+               if (entry == NULL) {
+                       ret_val = -ENOENT;
+                       goto req_setattr_return;
                }
-               switch (proto_type) {
+               switch (entry->type) {
                case NETLBL_NLTYPE_CIPSOV4:
-                       ret_val = cipso_v4_req_setattr(req, proto_cv4, secattr);
+                       ret_val = cipso_v4_req_setattr(req,
+                                                      entry->cipso, secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        /* just delete the protocols we support for right now
@@ -899,23 +883,21 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
 {
        int ret_val;
        struct iphdr *hdr4;
-       struct netlbl_domaddr4_map *af4_entry;
+       struct netlbl_dommap_def *entry;
 
        rcu_read_lock();
        switch (family) {
        case AF_INET:
                hdr4 = ip_hdr(skb);
-               af4_entry = netlbl_domhsh_getentry_af4(secattr->domain,
-                                                      hdr4->daddr);
-               if (af4_entry == NULL) {
+               entry = netlbl_domhsh_getentry_af4(secattr->domain,hdr4->daddr);
+               if (entry == NULL) {
                        ret_val = -ENOENT;
                        goto skbuff_setattr_return;
                }
-               switch (af4_entry->type) {
+               switch (entry->type) {
                case NETLBL_NLTYPE_CIPSOV4:
-                       ret_val = cipso_v4_skbuff_setattr(skb,
-                                                  af4_entry->type_def.cipsov4,
-                                                  secattr);
+                       ret_val = cipso_v4_skbuff_setattr(skb, entry->cipso,
+                                                         secattr);
                        break;
                case NETLBL_NLTYPE_UNLABELED:
                        /* just delete the protocols we support for right now
index c5384ff..dd1c37d 100644 (file)
@@ -104,7 +104,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                ret_val = -ENOMEM;
                goto add_failure;
        }
-       entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
+       entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
        if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
                size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
                entry->domain = kmalloc(tmp_size, GFP_KERNEL);
@@ -116,12 +116,12 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                            info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
        }
 
-       /* NOTE: internally we allow/use a entry->type value of
+       /* NOTE: internally we allow/use a entry->def.type value of
         *       NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
         *       to pass that as a protocol value because we need to know the
         *       "real" protocol */
 
-       switch (entry->type) {
+       switch (entry->def.type) {
        case NETLBL_NLTYPE_UNLABELED:
                break;
        case NETLBL_NLTYPE_CIPSOV4:
@@ -132,7 +132,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                cipsov4 = cipso_v4_doi_getdef(tmp_val);
                if (cipsov4 == NULL)
                        goto add_failure;
-               entry->type_def.cipsov4 = cipsov4;
+               entry->def.cipso = cipsov4;
                break;
        default:
                goto add_failure;
@@ -172,9 +172,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                map->list.addr = addr->s_addr & mask->s_addr;
                map->list.mask = mask->s_addr;
                map->list.valid = 1;
-               map->type = entry->type;
+               map->def.type = entry->def.type;
                if (cipsov4)
-                       map->type_def.cipsov4 = cipsov4;
+                       map->def.cipso = cipsov4;
 
                ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
                if (ret_val != 0) {
@@ -182,8 +182,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                        goto add_failure;
                }
 
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
-               entry->type_def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
 #if IS_ENABLED(CONFIG_IPV6)
        } else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
                struct in6_addr *addr;
@@ -223,7 +223,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
                map->list.mask = *mask;
                map->list.valid = 1;
-               map->type = entry->type;
+               map->def.type = entry->def.type;
 
                ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
                if (ret_val != 0) {
@@ -231,8 +231,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
                        goto add_failure;
                }
 
-               entry->type = NETLBL_NLTYPE_ADDRSELECT;
-               entry->type_def.addrsel = addrmap;
+               entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
+               entry->def.addrsel = addrmap;
 #endif /* IPv6 */
        }
 
@@ -281,14 +281,13 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                        return ret_val;
        }
 
-       switch (entry->type) {
+       switch (entry->def.type) {
        case NETLBL_NLTYPE_ADDRSELECT:
                nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
                if (nla_a == NULL)
                        return -ENOMEM;
 
-               netlbl_af4list_foreach_rcu(iter4,
-                                          &entry->type_def.addrsel->list4) {
+               netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
                        struct netlbl_domaddr4_map *map4;
                        struct in_addr addr_struct;
 
@@ -310,13 +309,13 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                                return ret_val;
                        map4 = netlbl_domhsh_addr4_entry(iter4);
                        ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
-                                             map4->type);
+                                             map4->def.type);
                        if (ret_val != 0)
                                return ret_val;
-                       switch (map4->type) {
+                       switch (map4->def.type) {
                        case NETLBL_NLTYPE_CIPSOV4:
                                ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
-                                                 map4->type_def.cipsov4->doi);
+                                                     map4->def.cipso->doi);
                                if (ret_val != 0)
                                        return ret_val;
                                break;
@@ -325,8 +324,7 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                        nla_nest_end(skb, nla_b);
                }
 #if IS_ENABLED(CONFIG_IPV6)
-               netlbl_af6list_foreach_rcu(iter6,
-                                          &entry->type_def.addrsel->list6) {
+               netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
                        struct netlbl_domaddr6_map *map6;
 
                        nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
@@ -345,7 +343,7 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                                return ret_val;
                        map6 = netlbl_domhsh_addr6_entry(iter6);
                        ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
-                                             map6->type);
+                                             map6->def.type);
                        if (ret_val != 0)
                                return ret_val;
 
@@ -356,14 +354,14 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
                nla_nest_end(skb, nla_a);
                break;
        case NETLBL_NLTYPE_UNLABELED:
-               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
                break;
        case NETLBL_NLTYPE_CIPSOV4:
-               ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, entry->type);
+               ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
                if (ret_val != 0)
                        return ret_val;
                ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
-                                     entry->type_def.cipsov4->doi);
+                                     entry->def.cipso->doi);
                break;
        }
 
index af35319..8f08974 100644 (file)
@@ -1541,7 +1541,7 @@ int __init netlbl_unlabel_defconf(void)
        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
        if (entry == NULL)
                return -ENOMEM;
-       entry->type = NETLBL_NLTYPE_UNLABELED;
+       entry->def.type = NETLBL_NLTYPE_UNLABELED;
        ret_val = netlbl_domhsh_add_default(entry, &audit_info);
        if (ret_val != 0)
                return ret_val;
index 2fd6dbe..f85f8a2 100644 (file)
@@ -571,7 +571,7 @@ static int genl_family_rcv_msg(struct genl_family *family,
            !capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ops->dumpit,
                        .done = ops->done,
@@ -789,6 +789,10 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
        struct net *net = sock_net(skb->sk);
        int chains_to_skip = cb->args[0];
        int fams_to_skip = cb->args[1];
+       bool need_locking = chains_to_skip || fams_to_skip;
+
+       if (need_locking)
+               genl_lock();
 
        for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
                n = 0;
@@ -810,6 +814,9 @@ errout:
        cb->args[0] = i;
        cb->args[1] = n;
 
+       if (need_locking)
+               genl_unlock();
+
        return skb->len;
 }
 
@@ -877,8 +884,10 @@ static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info)
 #ifdef CONFIG_MODULES
                if (res == NULL) {
                        genl_unlock();
+                       up_read(&cb_lock);
                        request_module("net-pf-%d-proto-%d-family-%s",
                                       PF_NETLINK, NETLINK_GENERIC, name);
+                       down_read(&cb_lock);
                        genl_lock();
                        res = genl_family_find_byname(name);
                }
index dc96a83..1d074dd 100644 (file)
@@ -44,7 +44,7 @@ DEFINE_MUTEX(nfc_devlist_mutex);
 /* NFC device ID bitmap */
 static DEFINE_IDA(nfc_index_ida);
 
-int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
+int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name)
 {
        int rc = 0;
 
@@ -62,28 +62,28 @@ int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name)
                goto error;
        }
 
-       if (!dev->ops->fw_upload) {
+       if (!dev->ops->fw_download) {
                rc = -EOPNOTSUPP;
                goto error;
        }
 
-       dev->fw_upload_in_progress = true;
-       rc = dev->ops->fw_upload(dev, firmware_name);
+       dev->fw_download_in_progress = true;
+       rc = dev->ops->fw_download(dev, firmware_name);
        if (rc)
-               dev->fw_upload_in_progress = false;
+               dev->fw_download_in_progress = false;
 
 error:
        device_unlock(&dev->dev);
        return rc;
 }
 
-int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
+int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
 {
-       dev->fw_upload_in_progress = false;
+       dev->fw_download_in_progress = false;
 
-       return nfc_genl_fw_upload_done(dev, firmware_name);
+       return nfc_genl_fw_download_done(dev, firmware_name);
 }
-EXPORT_SYMBOL(nfc_fw_upload_done);
+EXPORT_SYMBOL(nfc_fw_download_done);
 
 /**
  * nfc_dev_up - turn on the NFC device
@@ -110,7 +110,7 @@ int nfc_dev_up(struct nfc_dev *dev)
                goto error;
        }
 
-       if (dev->fw_upload_in_progress) {
+       if (dev->fw_download_in_progress) {
                rc = -EBUSY;
                goto error;
        }
index 7b1c186..fe66908 100644 (file)
@@ -809,14 +809,14 @@ static void nfc_hci_recv_from_llc(struct nfc_hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
-static int hci_fw_upload(struct nfc_dev *nfc_dev, const char *firmware_name)
+static int hci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name)
 {
        struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
 
-       if (!hdev->ops->fw_upload)
+       if (!hdev->ops->fw_download)
                return -ENOTSUPP;
 
-       return hdev->ops->fw_upload(hdev, firmware_name);
+       return hdev->ops->fw_download(hdev, firmware_name);
 }
 
 static struct nfc_ops hci_nfc_ops = {
@@ -831,7 +831,7 @@ static struct nfc_ops hci_nfc_ops = {
        .im_transceive = hci_transceive,
        .tm_send = hci_tm_send,
        .check_presence = hci_check_presence,
-       .fw_upload = hci_fw_upload,
+       .fw_download = hci_fw_download,
        .discover_se = hci_discover_se,
        .enable_se = hci_enable_se,
        .disable_se = hci_disable_se,
index 2a24160..a4f1e42 100644 (file)
@@ -11,6 +11,7 @@ config NFC_NCI
 
 config NFC_NCI_SPI
        depends on NFC_NCI && SPI
+       select CRC_CCITT
        bool "NCI over SPI protocol support"
        default n
        help
index b05ad90..f16fd59 100644 (file)
@@ -1089,7 +1089,7 @@ exit:
        return rc;
 }
 
-static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
+static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info)
 {
        struct nfc_dev *dev;
        int rc;
@@ -1108,13 +1108,13 @@ static int nfc_genl_fw_upload(struct sk_buff *skb, struct genl_info *info)
        nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME],
                    sizeof(firmware_name));
 
-       rc = nfc_fw_upload(dev, firmware_name);
+       rc = nfc_fw_download(dev, firmware_name);
 
        nfc_put_device(dev);
        return rc;
 }
 
-int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
+int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -1124,7 +1124,7 @@ int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name)
                return -ENOMEM;
 
        hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
-                         NFC_CMD_FW_UPLOAD);
+                         NFC_CMD_FW_DOWNLOAD);
        if (!hdr)
                goto free_msg;
 
@@ -1251,8 +1251,8 @@ static struct genl_ops nfc_genl_ops[] = {
                .policy = nfc_genl_policy,
        },
        {
-               .cmd = NFC_CMD_FW_UPLOAD,
-               .doit = nfc_genl_fw_upload,
+               .cmd = NFC_CMD_FW_DOWNLOAD,
+               .doit = nfc_genl_fw_download,
                .policy = nfc_genl_policy,
        },
        {
index ee85a1f..820a785 100644 (file)
@@ -123,10 +123,10 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
        class_dev_iter_exit(iter);
 }
 
-int nfc_fw_upload(struct nfc_dev *dev, const char *firmware_name);
-int nfc_genl_fw_upload_done(struct nfc_dev *dev, const char *firmware_name);
+int nfc_fw_download(struct nfc_dev *dev, const char *firmware_name);
+int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
 
-int nfc_fw_upload_done(struct nfc_dev *dev, const char *firmware_name);
+int nfc_fw_download_done(struct nfc_dev *dev, const char *firmware_name);
 
 int nfc_dev_up(struct nfc_dev *dev);
 
index 22c5f39..ab101f7 100644 (file)
@@ -535,6 +535,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
 {
        struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
 
+       OVS_CB(skb)->tun_key = NULL;
        return do_execute_actions(dp, skb, acts->actions,
                                         acts->actions_len, false);
 }
index f7e3a0d..f2ed760 100644 (file)
@@ -2076,9 +2076,6 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
        ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
        return 0;
 
-       rtnl_unlock();
-       return 0;
-
 exit_free:
        kfree_skb(reply);
 exit_unlock:
index 5c519b1..1aa84dc 100644 (file)
@@ -240,7 +240,7 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets)
        struct flex_array *buckets;
        int i, err;
 
-       buckets = flex_array_alloc(sizeof(struct hlist_head *),
+       buckets = flex_array_alloc(sizeof(struct hlist_head),
                                   n_buckets, GFP_KERNEL);
        if (!buckets)
                return NULL;
index 281c1bd..51b968d 100644 (file)
@@ -285,6 +285,45 @@ static struct Qdisc_ops *qdisc_lookup_ops(struct nlattr *kind)
        return q;
 }
 
+/* The linklayer setting were not transferred from iproute2, in older
+ * versions, and the rate tables lookup systems have been dropped in
+ * the kernel. To keep backward compatible with older iproute2 tc
+ * utils, we detect the linklayer setting by detecting if the rate
+ * table were modified.
+ *
+ * For linklayer ATM table entries, the rate table will be aligned to
+ * 48 bytes, thus some table entries will contain the same value.  The
+ * mpu (min packet unit) is also encoded into the old rate table, thus
+ * starting from the mpu, we find low and high table entries for
+ * mapping this cell.  If these entries contain the same value, when
+ * the rate tables have been modified for linklayer ATM.
+ *
+ * This is done by rounding mpu to the nearest 48 bytes cell/entry,
+ * and then roundup to the next cell, calc the table entry one below,
+ * and compare.
+ */
+static __u8 __detect_linklayer(struct tc_ratespec *r, __u32 *rtab)
+{
+       int low       = roundup(r->mpu, 48);
+       int high      = roundup(low+1, 48);
+       int cell_low  = low >> r->cell_log;
+       int cell_high = (high >> r->cell_log) - 1;
+
+       /* rtab is too inaccurate at rates > 100Mbit/s */
+       if ((r->rate > (100000000/8)) || (rtab[0] == 0)) {
+               pr_debug("TC linklayer: Giving up ATM detection\n");
+               return TC_LINKLAYER_ETHERNET;
+       }
+
+       if ((cell_high > cell_low) && (cell_high < 256)
+           && (rtab[cell_low] == rtab[cell_high])) {
+               pr_debug("TC linklayer: Detected ATM, low(%d)=high(%d)=%u\n",
+                        cell_low, cell_high, rtab[cell_high]);
+               return TC_LINKLAYER_ATM;
+       }
+       return TC_LINKLAYER_ETHERNET;
+}
+
 static struct qdisc_rate_table *qdisc_rtab_list;
 
 struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *tab)
@@ -308,6 +347,8 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, struct nlattr *ta
                rtab->rate = *r;
                rtab->refcnt = 1;
                memcpy(rtab->data, nla_data(tab), 1024);
+               if (r->linklayer == TC_LINKLAYER_UNAWARE)
+                       r->linklayer = __detect_linklayer(r, rtab->data);
                rtab->next = qdisc_rtab_list;
                qdisc_rtab_list = rtab;
        }
index ca8e0a5..1f9c314 100644 (file)
@@ -605,6 +605,7 @@ static int atm_tc_dump_class(struct Qdisc *sch, unsigned long cl,
                struct sockaddr_atmpvc pvc;
                int state;
 
+               memset(&pvc, 0, sizeof(pvc));
                pvc.sap_family = AF_ATMPVC;
                pvc.sap_addr.itf = flow->vcc->dev ? flow->vcc->dev->number : -1;
                pvc.sap_addr.vpi = flow->vcc->vpi;
index 71a5688..7a42c81 100644 (file)
@@ -1465,6 +1465,7 @@ static int cbq_dump_wrr(struct sk_buff *skb, struct cbq_class *cl)
        unsigned char *b = skb_tail_pointer(skb);
        struct tc_cbq_wrropt opt;
 
+       memset(&opt, 0, sizeof(opt));
        opt.flags = 0;
        opt.allot = cl->allot;
        opt.priority = cl->priority + 1;
index 4626cef..48be3d5 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/rcupdate.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/if_vlan.h>
 #include <net/sch_generic.h>
 #include <net/pkt_sched.h>
 #include <net/dst.h>
@@ -207,15 +208,19 @@ void __qdisc_run(struct Qdisc *q)
 
 unsigned long dev_trans_start(struct net_device *dev)
 {
-       unsigned long val, res = dev->trans_start;
+       unsigned long val, res;
        unsigned int i;
 
+       if (is_vlan_dev(dev))
+               dev = vlan_dev_real_dev(dev);
+       res = dev->trans_start;
        for (i = 0; i < dev->num_tx_queues; i++) {
                val = netdev_get_tx_queue(dev, i)->trans_start;
                if (val && time_after(val, res))
                        res = val;
        }
        dev->trans_start = res;
+
        return res;
 }
 EXPORT_SYMBOL(dev_trans_start);
@@ -904,6 +909,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r,
        memset(r, 0, sizeof(*r));
        r->overhead = conf->overhead;
        r->rate_bytes_ps = conf->rate;
+       r->linklayer = (conf->linklayer & TC_LINKLAYER_MASK);
        r->mult = 1;
        /*
         * The deal here is to replace a divide by a reciprocal one
index c2124ea..c2178b1 100644 (file)
@@ -100,7 +100,7 @@ struct htb_class {
        struct psched_ratecfg   ceil;
        s64                     buffer, cbuffer;/* token bucket depth/rate */
        s64                     mbuffer;        /* max wait time */
-       int                     prio;           /* these two are used only by leaves... */
+       u32                     prio;           /* these two are used only by leaves... */
        int                     quantum;        /* but stored for parent-to-leaf return */
 
        struct tcf_proto        *filter_list;   /* class attached filters */
@@ -1329,6 +1329,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
        struct htb_sched *q = qdisc_priv(sch);
        struct htb_class *cl = (struct htb_class *)*arg, *parent;
        struct nlattr *opt = tca[TCA_OPTIONS];
+       struct qdisc_rate_table *rtab = NULL, *ctab = NULL;
        struct nlattr *tb[TCA_HTB_MAX + 1];
        struct tc_htb_opt *hopt;
 
@@ -1350,6 +1351,18 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
        if (!hopt->rate.rate || !hopt->ceil.rate)
                goto failure;
 
+       /* Keeping backward compatible with rate_table based iproute2 tc */
+       if (hopt->rate.linklayer == TC_LINKLAYER_UNAWARE) {
+               rtab = qdisc_get_rtab(&hopt->rate, tb[TCA_HTB_RTAB]);
+               if (rtab)
+                       qdisc_put_rtab(rtab);
+       }
+       if (hopt->ceil.linklayer == TC_LINKLAYER_UNAWARE) {
+               ctab = qdisc_get_rtab(&hopt->ceil, tb[TCA_HTB_CTAB]);
+               if (ctab)
+                       qdisc_put_rtab(ctab);
+       }
+
        if (!cl) {              /* new class */
                struct Qdisc *new_q;
                int prio;
index bce5b79..ab67efc 100644 (file)
@@ -846,12 +846,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
                else
                        spc_state = SCTP_ADDR_AVAILABLE;
                /* Don't inform ULP about transition from PF to
-                * active state and set cwnd to 1, see SCTP
+                * active state and set cwnd to 1 MTU, see SCTP
                 * Quick failover draft section 5.1, point 5
                 */
                if (transport->state == SCTP_PF) {
                        ulp_notify = false;
-                       transport->cwnd = 1;
+                       transport->cwnd = asoc->pathmtu;
                }
                transport->state = SCTP_ACTIVE;
                break;
index bdbbc3f..8fdd160 100644 (file)
@@ -181,12 +181,12 @@ static void sctp_transport_destroy(struct sctp_transport *transport)
                return;
        }
 
-       call_rcu(&transport->rcu, sctp_transport_destroy_rcu);
-
        sctp_packet_free(&transport->packet);
 
        if (transport->asoc)
                sctp_association_put(transport->asoc);
+
+       call_rcu(&transport->rcu, sctp_transport_destroy_rcu);
 }
 
 /* Start T3_rtx timer if it is not already running and update the heartbeat
index 829b460..b2d7c62 100644 (file)
 #include <linux/atalk.h>
 #include <net/busy_poll.h>
 
-#ifdef CONFIG_NET_LL_RX_POLL
+#ifdef CONFIG_NET_RX_BUSY_POLL
 unsigned int sysctl_net_busy_read __read_mostly;
 unsigned int sysctl_net_busy_poll __read_mostly;
 #endif
index d304f41..af7ffd4 100644 (file)
@@ -120,7 +120,7 @@ static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt)
        if (IS_ERR(clnt)) {
                dprintk("RPC:       failed to create AF_LOCAL gssproxy "
                                "client (errno %ld).\n", PTR_ERR(clnt));
-               result = -PTR_ERR(clnt);
+               result = PTR_ERR(clnt);
                *_clnt = NULL;
                goto out;
        }
@@ -328,7 +328,6 @@ void gssp_free_upcall_data(struct gssp_upcall_data *data)
        kfree(data->in_handle.data);
        kfree(data->out_handle.data);
        kfree(data->out_token.data);
-       kfree(data->mech_oid.data);
        free_svc_cred(&data->creds);
 }
 
index 357f613..3c85d1c 100644 (file)
@@ -430,7 +430,7 @@ static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
 static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
                                    struct gssx_name_attr_array *naa)
 {
-       struct gssx_name_attr dummy;
+       struct gssx_name_attr dummy = { .attr = {.len = 0} };
        u32 count, i;
        __be32 *p;
 
@@ -493,12 +493,13 @@ static int gssx_enc_name(struct xdr_stream *xdr,
        return err;
 }
 
+
 static int gssx_dec_name(struct xdr_stream *xdr,
                         struct gssx_name *name)
 {
-       struct xdr_netobj dummy_netobj;
-       struct gssx_name_attr_array dummy_name_attr_array;
-       struct gssx_option_array dummy_option_array;
+       struct xdr_netobj dummy_netobj = { .len = 0 };
+       struct gssx_name_attr_array dummy_name_attr_array = { .count = 0 };
+       struct gssx_option_array dummy_option_array = { .count = 0 };
        int err;
 
        /* name->display_name */
index d0347d1..09fb638 100644 (file)
@@ -1180,6 +1180,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
                gm = gss_mech_get_by_OID(&ud->mech_oid);
                if (!gm)
                        goto out;
+               rsci.cred.cr_gss_mech = gm;
 
                status = -EINVAL;
                /* mech-specific data: */
@@ -1195,7 +1196,6 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
        rscp = rsc_update(cd, &rsci, rscp);
        status = 0;
 out:
-       gss_mech_put(gm);
        rsc_free(&rsci);
        if (rscp)
                cache_put(&rscp->h, cd);
index 74f6a70..ecbc4e3 100644 (file)
@@ -1660,6 +1660,10 @@ call_connect(struct rpc_task *task)
                task->tk_action = call_connect_status;
                if (task->tk_status < 0)
                        return;
+               if (task->tk_flags & RPC_TASK_NOCONNECT) {
+                       rpc_exit(task, -ENOTCONN);
+                       return;
+               }
                xprt_connect(task);
        }
 }
index 74d948f..779742c 100644 (file)
@@ -23,6 +23,7 @@ struct sunrpc_net {
        struct rpc_clnt *rpcb_local_clnt4;
        spinlock_t rpcb_clnt_lock;
        unsigned int rpcb_users;
+       unsigned int rpcb_is_af_local : 1;
 
        struct mutex gssp_lock;
        wait_queue_head_t gssp_wq;
index 3df764d..1891a10 100644 (file)
@@ -204,13 +204,15 @@ void rpcb_put_local(struct net *net)
 }
 
 static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
-                       struct rpc_clnt *clnt4)
+                       struct rpc_clnt *clnt4,
+                       bool is_af_local)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        /* Protected by rpcb_create_local_mutex */
        sn->rpcb_local_clnt = clnt;
        sn->rpcb_local_clnt4 = clnt4;
+       sn->rpcb_is_af_local = is_af_local ? 1 : 0;
        smp_wmb(); 
        sn->rpcb_users = 1;
        dprintk("RPC:       created new rpcb local clients (rpcb_local_clnt: "
@@ -238,6 +240,14 @@ static int rpcb_create_local_unix(struct net *net)
                .program        = &rpcb_program,
                .version        = RPCBVERS_2,
                .authflavor     = RPC_AUTH_NULL,
+               /*
+                * We turn off the idle timeout to prevent the kernel
+                * from automatically disconnecting the socket.
+                * Otherwise, we'd have to cache the mount namespace
+                * of the caller and somehow pass that to the socket
+                * reconnect code.
+                */
+               .flags          = RPC_CLNT_CREATE_NO_IDLE_TIMEOUT,
        };
        struct rpc_clnt *clnt, *clnt4;
        int result = 0;
@@ -263,7 +273,7 @@ static int rpcb_create_local_unix(struct net *net)
                clnt4 = NULL;
        }
 
-       rpcb_set_local(net, clnt, clnt4);
+       rpcb_set_local(net, clnt, clnt4, true);
 
 out:
        return result;
@@ -315,7 +325,7 @@ static int rpcb_create_local_net(struct net *net)
                clnt4 = NULL;
        }
 
-       rpcb_set_local(net, clnt, clnt4);
+       rpcb_set_local(net, clnt, clnt4, false);
 
 out:
        return result;
@@ -376,13 +386,16 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
        return rpc_create(&args);
 }
 
-static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
+static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set)
 {
-       int result, error = 0;
+       int flags = RPC_TASK_NOCONNECT;
+       int error, result = 0;
 
+       if (is_set || !sn->rpcb_is_af_local)
+               flags = RPC_TASK_SOFTCONN;
        msg->rpc_resp = &result;
 
-       error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN);
+       error = rpc_call_sync(clnt, msg, flags);
        if (error < 0) {
                dprintk("RPC:       failed to contact local rpcbind "
                                "server (errno %d).\n", -error);
@@ -439,16 +452,19 @@ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short
                .rpc_argp       = &map,
        };
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       bool is_set = false;
 
        dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
                        "rpcbind\n", (port ? "" : "un"),
                        prog, vers, prot, port);
 
        msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
-       if (port)
+       if (port != 0) {
                msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
+               is_set = true;
+       }
 
-       return rpcb_register_call(sn->rpcb_local_clnt, &msg);
+       return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set);
 }
 
 /*
@@ -461,6 +477,7 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
        const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
        unsigned short port = ntohs(sin->sin_port);
+       bool is_set = false;
        int result;
 
        map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
@@ -471,10 +488,12 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
                        map->r_addr, map->r_netid);
 
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
-       if (port)
+       if (port != 0) {
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+               is_set = true;
+       }
 
-       result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
+       result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
        kfree(map->r_addr);
        return result;
 }
@@ -489,6 +508,7 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
        const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
        unsigned short port = ntohs(sin6->sin6_port);
+       bool is_set = false;
        int result;
 
        map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
@@ -499,10 +519,12 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
                        map->r_addr, map->r_netid);
 
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
-       if (port)
+       if (port != 0) {
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+               is_set = true;
+       }
 
-       result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
+       result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
        kfree(map->r_addr);
        return result;
 }
@@ -519,7 +541,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
        map->r_addr = "";
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
 
-       return rpcb_register_call(sn->rpcb_local_clnt4, msg);
+       return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false);
 }
 
 /**
index 305374d..7762b9f 100644 (file)
@@ -1193,7 +1193,9 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt)
        if (test_bit(XPT_LISTENER, &xprt->xpt_flags))
                return 1;
        required = atomic_read(&xprt->xpt_reserved) + serv->sv_max_mesg;
-       if (sk_stream_wspace(svsk->sk_sk) >= required)
+       if (sk_stream_wspace(svsk->sk_sk) >= required ||
+           (sk_stream_min_wspace(svsk->sk_sk) == 0 &&
+            atomic_read(&xprt->xpt_reserved) == 0))
                return 1;
        set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
        return 0;
index cb29ef7..609c30c 100644 (file)
@@ -460,6 +460,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
 {
        struct tipc_link *l_ptr;
        struct tipc_link *temp_l_ptr;
+       struct tipc_link_req *temp_req;
 
        pr_info("Disabling bearer <%s>\n", b_ptr->name);
        spin_lock_bh(&b_ptr->lock);
@@ -468,9 +469,13 @@ static void bearer_disable(struct tipc_bearer *b_ptr)
        list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) {
                tipc_link_delete(l_ptr);
        }
-       if (b_ptr->link_req)
-               tipc_disc_delete(b_ptr->link_req);
+       temp_req = b_ptr->link_req;
+       b_ptr->link_req = NULL;
        spin_unlock_bh(&b_ptr->lock);
+
+       if (temp_req)
+               tipc_disc_delete(temp_req);
+
        memset(b_ptr, 0, sizeof(struct tipc_bearer));
 }
 
index 19da5ab..fd3fa57 100644 (file)
@@ -355,8 +355,12 @@ static int tipc_open_listening_sock(struct tipc_server *s)
                return PTR_ERR(con);
 
        sock = tipc_create_listen_sock(con);
-       if (!sock)
+       if (!sock) {
+               idr_remove(&s->conn_idr, con->conid);
+               s->idr_in_use--;
+               kfree(con);
                return -EINVAL;
+       }
 
        tipc_register_callbacks(sock, con);
        return 0;
@@ -563,9 +567,14 @@ int tipc_server_start(struct tipc_server *s)
                kmem_cache_destroy(s->rcvbuf_cache);
                return ret;
        }
+       ret = tipc_open_listening_sock(s);
+       if (ret < 0) {
+               tipc_work_stop(s);
+               kmem_cache_destroy(s->rcvbuf_cache);
+               return ret;
+       }
        s->enabled = 1;
-
-       return tipc_open_listening_sock(s);
+       return ret;
 }
 
 void tipc_server_stop(struct tipc_server *s)
index 593071d..4d93346 100644 (file)
@@ -347,7 +347,7 @@ void vsock_for_each_connected_socket(void (*fn)(struct sock *sk))
        for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++) {
                struct vsock_sock *vsk;
                list_for_each_entry(vsk, &vsock_connected_table[i],
-                                   connected_table);
+                                   connected_table)
                        fn(sk_vsock(vsk));
        }
 
index 4f9f216..a8c29fa 100644 (file)
@@ -765,6 +765,7 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev,
                cfg80211_leave_mesh(rdev, dev);
                break;
        case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
                cfg80211_stop_ap(rdev, dev);
                break;
        default:
index 1cc47ac..3fcba69 100644 (file)
@@ -441,10 +441,12 @@ static int nl80211_prepare_wdev_dump(struct sk_buff *skb,
                        goto out_unlock;
                }
                *rdev = wiphy_to_dev((*wdev)->wiphy);
-               cb->args[0] = (*rdev)->wiphy_idx;
+               /* 0 is the first index - add 1 to parse only once */
+               cb->args[0] = (*rdev)->wiphy_idx + 1;
                cb->args[1] = (*wdev)->identifier;
        } else {
-               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0]);
+               /* subtract the 1 again here */
+               struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
                struct wireless_dev *tmp;
 
                if (!wiphy) {
@@ -4770,9 +4772,9 @@ do {                                                                          \
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, 0, 1,
                                  mask, NL80211_MESHCONF_FORWARDING,
                                  nla_get_u8);
-       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, 1, 255,
+       FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, -255, 0,
                                  mask, NL80211_MESHCONF_RSSI_THRESHOLD,
-                                 nla_get_u32);
+                                 nla_get_s32);
        FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, 0, 16,
                                  mask, NL80211_MESHCONF_HT_OPMODE,
                                  nla_get_u16);
@@ -6613,12 +6615,14 @@ EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
 
 void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
 {
+       struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
        void *hdr = ((void **)skb->cb)[1];
        struct nlattr *data = ((void **)skb->cb)[2];
 
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
-       genlmsg_multicast(skb, 0, nl80211_testmode_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), skb, 0,
+                               nl80211_testmode_mcgrp.id, gfp);
 }
 EXPORT_SYMBOL(cfg80211_testmode_event);
 #endif
@@ -10064,7 +10068,8 @@ void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie,
 
        genlmsg_end(msg, hdr);
 
-       genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
index 5a24c98..de06d5d 100644 (file)
@@ -2247,10 +2247,13 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 void wiphy_regulatory_register(struct wiphy *wiphy)
 {
+       struct regulatory_request *lr;
+
        if (!reg_dev_ignore_cell_hint(wiphy))
                reg_num_devs_support_basehint++;
 
-       wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
+       lr = get_last_request();
+       wiphy_update_regulatory(wiphy, lr->initiator);
 }
 
 void wiphy_regulatory_deregister(struct wiphy *wiphy)
@@ -2279,7 +2282,9 @@ void wiphy_regulatory_deregister(struct wiphy *wiphy)
 static void reg_timeout_work(struct work_struct *work)
 {
        REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
+       rtnl_lock();
        restore_regulatory_settings(true);
+       rtnl_unlock();
 }
 
 int __init regulatory_init(void)
index 1d3cfb1..81c8a10 100644 (file)
@@ -34,8 +34,10 @@ struct cfg80211_conn {
                CFG80211_CONN_SCAN_AGAIN,
                CFG80211_CONN_AUTHENTICATE_NEXT,
                CFG80211_CONN_AUTHENTICATING,
+               CFG80211_CONN_AUTH_FAILED,
                CFG80211_CONN_ASSOCIATE_NEXT,
                CFG80211_CONN_ASSOCIATING,
+               CFG80211_CONN_ASSOC_FAILED,
                CFG80211_CONN_DEAUTH,
                CFG80211_CONN_CONNECTED,
        } state;
@@ -164,6 +166,8 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                          NULL, 0,
                                          params->key, params->key_len,
                                          params->key_idx, NULL, 0);
+       case CFG80211_CONN_AUTH_FAILED:
+               return -ENOTCONN;
        case CFG80211_CONN_ASSOCIATE_NEXT:
                BUG_ON(!rdev->ops->assoc);
                wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -188,10 +192,17 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
                                             WLAN_REASON_DEAUTH_LEAVING,
                                             false);
                return err;
+       case CFG80211_CONN_ASSOC_FAILED:
+               cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
+                                    NULL, 0,
+                                    WLAN_REASON_DEAUTH_LEAVING, false);
+               return -ENOTCONN;
        case CFG80211_CONN_DEAUTH:
                cfg80211_mlme_deauth(rdev, wdev->netdev, params->bssid,
                                     NULL, 0,
                                     WLAN_REASON_DEAUTH_LEAVING, false);
+               /* free directly, disconnected event already sent */
+               cfg80211_sme_free(wdev);
                return 0;
        default:
                return 0;
@@ -371,7 +382,7 @@ bool cfg80211_sme_rx_assoc_resp(struct wireless_dev *wdev, u16 status)
                return true;
        }
 
-       wdev->conn->state = CFG80211_CONN_DEAUTH;
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
        schedule_work(&rdev->conn_work);
        return false;
 }
@@ -383,7 +394,13 @@ void cfg80211_sme_deauth(struct wireless_dev *wdev)
 
 void cfg80211_sme_auth_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_free(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_AUTH_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 void cfg80211_sme_disassoc(struct wireless_dev *wdev)
@@ -399,7 +416,13 @@ void cfg80211_sme_disassoc(struct wireless_dev *wdev)
 
 void cfg80211_sme_assoc_timeout(struct wireless_dev *wdev)
 {
-       cfg80211_sme_disassoc(wdev);
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+
+       if (!wdev->conn)
+               return;
+
+       wdev->conn->state = CFG80211_CONN_ASSOC_FAILED;
+       schedule_work(&rdev->conn_work);
 }
 
 static int cfg80211_sme_connect(struct wireless_dev *wdev,
index 3f7682a..eefbd10 100644 (file)
@@ -1998,12 +1998,11 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
  *
  * Create or update the port list entry
  */
-static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address,
+static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
                                int act)
 {
        __be16 *bep;
        __be32 *be32p;
-       struct sockaddr_in6 *addr6;
        struct smk_port_label *spp;
        struct socket_smack *ssp = sk->sk_security;
        struct smack_known *skp;
@@ -2025,10 +2024,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr *address,
        /*
         * Get the IP address and port from the address.
         */
-       addr6 = (struct sockaddr_in6 *)address;
-       port = ntohs(addr6->sin6_port);
-       bep = (__be16 *)(&addr6->sin6_addr);
-       be32p = (__be32 *)(&addr6->sin6_addr);
+       port = ntohs(address->sin6_port);
+       bep = (__be16 *)(&address->sin6_addr);
+       be32p = (__be32 *)(&address->sin6_addr);
 
        /*
         * It's remote, so port lookup does no good.
@@ -2060,9 +2058,9 @@ auditout:
        ad.a.u.net->family = sk->sk_family;
        ad.a.u.net->dport = port;
        if (act == SMK_RECEIVING)
-               ad.a.u.net->v6info.saddr = addr6->sin6_addr;
+               ad.a.u.net->v6info.saddr = address->sin6_addr;
        else
-               ad.a.u.net->v6info.daddr = addr6->sin6_addr;
+               ad.a.u.net->v6info.daddr = address->sin6_addr;
 #endif
        return smk_access(skp, object, MAY_WRITE, &ad);
 }
@@ -2201,7 +2199,8 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
        case PF_INET6:
                if (addrlen < sizeof(struct sockaddr_in6))
                        return -EINVAL;
-               rc = smk_ipv6_port_check(sock->sk, sap, SMK_CONNECTING);
+               rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap,
+                                               SMK_CONNECTING);
                break;
        }
        return rc;
@@ -3034,7 +3033,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                int size)
 {
        struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name;
-       struct sockaddr *sap = (struct sockaddr *) msg->msg_name;
+       struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
        int rc = 0;
 
        /*
@@ -3121,9 +3120,8 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap,
        return smack_net_ambient;
 }
 
-static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr *sap)
+static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
 {
-       struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap;
        u8 nexthdr;
        int offset;
        int proto = -EINVAL;
@@ -3181,7 +3179,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
        struct netlbl_lsm_secattr secattr;
        struct socket_smack *ssp = sk->sk_security;
        struct smack_known *skp;
-       struct sockaddr sadd;
+       struct sockaddr_in6 sadd;
        int rc = 0;
        struct smk_audit_info ad;
 #ifdef CONFIG_AUDIT
index ce431e6..5066a37 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/dmaengine.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/regs-ac97.h>
 #include <mach/audio.h>
@@ -41,20 +43,20 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_reset,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_out = {
-       .name                   = "AC97 PCM out",
-       .dev_addr               = __PREG(PCDR),
-       .drcmr                  = &DRCMR(12),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_out_req = 12;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
+       .addr           = __PREG(PCDR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .maxburst       = 32,
+       .filter_data    = &pxa2xx_ac97_pcm_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_in = {
-       .name                   = "AC97 PCM in",
-       .dev_addr               = __PREG(PCDR),
-       .drcmr                  = &DRCMR(11),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_in_req = 11;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
+       .addr           = __PREG(PCDR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .maxburst       = 32,
+       .filter_data    = &pxa2xx_ac97_pcm_in_req,
 };
 
 static struct snd_pcm *pxa2xx_ac97_pcm;
index 823359e..a61d7a9 100644 (file)
@@ -7,11 +7,13 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/dma.h>
 
@@ -43,6 +45,35 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        size_t period = params_period_bytes(params);
        pxa_dma_desc *dma_desc;
        dma_addr_t dma_buff_phys, next_desc_phys;
+       u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
+
+       /* temporary transition hack */
+       switch (rtd->params->addr_width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               dcmd |= DCMD_WIDTH1;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               dcmd |= DCMD_WIDTH2;
+               break;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               dcmd |= DCMD_WIDTH4;
+               break;
+       default:
+               /* can't happen */
+               break;
+       }
+
+       switch (rtd->params->maxburst) {
+       case 8:
+               dcmd |= DCMD_BURST8;
+               break;
+       case 16:
+               dcmd |= DCMD_BURST16;
+               break;
+       case 32:
+               dcmd |= DCMD_BURST32;
+               break;
+       }
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
        runtime->dma_bytes = totsize;
@@ -55,14 +86,14 @@ int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
                dma_desc->ddadr = next_desc_phys;
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        dma_desc->dsadr = dma_buff_phys;
-                       dma_desc->dtadr = rtd->params->dev_addr;
+                       dma_desc->dtadr = rtd->params->addr;
                } else {
-                       dma_desc->dsadr = rtd->params->dev_addr;
+                       dma_desc->dsadr = rtd->params->addr;
                        dma_desc->dtadr = dma_buff_phys;
                }
                if (period > totsize)
                        period = totsize;
-               dma_desc->dcmd = rtd->params->dcmd | period | DCMD_ENDIRQEN;
+               dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
                dma_desc++;
                dma_buff_phys += period;
        } while (totsize -= period);
@@ -76,8 +107,10 @@ int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
 
-       if (rtd && rtd->params && rtd->params->drcmr)
-               *rtd->params->drcmr = 0;
+       if (rtd && rtd->params && rtd->params->filter_data) {
+               unsigned long req = *(unsigned long *) rtd->params->filter_data;
+               DRCMR(req) = 0;
+       }
 
        snd_pcm_set_runtime_buffer(substream, NULL);
        return 0;
@@ -136,6 +169,7 @@ EXPORT_SYMBOL(pxa2xx_pcm_pointer);
 int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 {
        struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
+       unsigned long req;
 
        if (!prtd || !prtd->params)
                return 0;
@@ -146,7 +180,8 @@ int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
        DCSR(prtd->dma_ch) &= ~DCSR_RUN;
        DCSR(prtd->dma_ch) = 0;
        DCMD(prtd->dma_ch) = 0;
-       *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
+       req = *(unsigned long *) prtd->params->filter_data;
+       DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;
 
        return 0;
 }
@@ -155,7 +190,6 @@ EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
 void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
 {
        struct snd_pcm_substream *substream = dev_id;
-       struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
        int dcsr;
 
        dcsr = DCSR(dma_ch);
@@ -164,8 +198,8 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
        if (dcsr & DCSR_ENDINTR) {
                snd_pcm_period_elapsed(substream);
        } else {
-               printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
-                       rtd->params->name, dma_ch, dcsr);
+               printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
+                       dma_ch, dcsr);
                snd_pcm_stream_lock(substream);
                snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
                snd_pcm_stream_unlock(substream);
index 26422a3..69a2455 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/dmaengine.h>
+
 #include <sound/core.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "pxa2xx-pcm.h"
 
@@ -40,7 +43,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 
        rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
                      client->playback_params : client->capture_params;
-       ret = pxa_request_dma(rtd->params->name, DMA_PRIO_LOW,
+       ret = pxa_request_dma("dma", DMA_PRIO_LOW,
                              pxa2xx_pcm_dma_irq, substream);
        if (ret < 0)
                goto err2;
index 65f86b5..2a8fc08 100644 (file)
 
 struct pxa2xx_runtime_data {
        int dma_ch;
-       struct pxa2xx_pcm_dma_params *params;
+       struct snd_dmaengine_dai_dma_data *params;
        pxa_dma_desc *dma_desc_array;
        dma_addr_t dma_desc_array_phys;
 };
 
 struct pxa2xx_pcm_client {
-       struct pxa2xx_pcm_dma_params *playback_params;
-       struct pxa2xx_pcm_dma_params *capture_params;
+       struct snd_dmaengine_dai_dma_data *playback_params;
+       struct snd_dmaengine_dai_dma_data *capture_params;
        int (*startup)(struct snd_pcm_substream *);
        void (*shutdown)(struct snd_pcm_substream *);
        int (*prepare)(struct snd_pcm_substream *);
index c0c2f57..313f22e 100644 (file)
@@ -6,6 +6,9 @@ config SND_PCM
        tristate
        select SND_TIMER
 
+config SND_DMAENGINE_PCM
+       tristate
+
 config SND_HWDEP
        tristate
 
index 43d4117..5e890cf 100644 (file)
@@ -13,6 +13,8 @@ snd-$(CONFIG_SND_JACK)          += jack.o
 snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
                pcm_memory.o
 
+snd-pcm-dmaengine-objs := pcm_dmaengine.o
+
 snd-page-alloc-y := memalloc.o
 snd-page-alloc-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
 
@@ -30,6 +32,7 @@ obj-$(CONFIG_SND_TIMER)               += snd-timer.o
 obj-$(CONFIG_SND_HRTIMER)      += snd-hrtimer.o
 obj-$(CONFIG_SND_RTCTIMER)     += snd-rtctimer.o
 obj-$(CONFIG_SND_PCM)          += snd-pcm.o snd-page-alloc.o
+obj-$(CONFIG_SND_DMAENGINE_PCM)        += snd-pcm-dmaengine.o
 obj-$(CONFIG_SND_RAWMIDI)      += snd-rawmidi.o
 
 obj-$(CONFIG_SND_OSSEMUL)      += oss/
index 99db892..9896954 100644 (file)
@@ -743,7 +743,7 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
        mutex_lock(&stream->device->lock);
        switch (_IOC_NR(cmd)) {
        case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION):
-               put_user(SNDRV_COMPRESS_VERSION,
+               retval = put_user(SNDRV_COMPRESS_VERSION,
                                (int __user *)arg) ? -EFAULT : 0;
                break;
        case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
index 7c11d46..48a9d00 100644 (file)
@@ -860,7 +860,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec,
                }
        }
        if (id < 0 && quirk) {
-               for (q = quirk; q->subvendor; q++) {
+               for (q = quirk; q->subvendor || q->subdevice; q++) {
                        unsigned int vendorid =
                                q->subdevice | (q->subvendor << 16);
                        unsigned int mask = 0xffff0000 | q->subdevice_mask;
index 8e77cbb..e3c7ba8 100644 (file)
@@ -522,7 +522,7 @@ static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
 }
 
 #define nid_has_mute(codec, nid, dir) \
-       check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
+       check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))
 #define nid_has_volume(codec, nid, dir) \
        check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
 
@@ -624,7 +624,7 @@ static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
                if (enable)
                        val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
        }
-       if (caps & AC_AMPCAP_MUTE) {
+       if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
                if (!enable)
                        val |= HDA_AMP_MUTE;
        }
@@ -648,7 +648,7 @@ static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
 {
        unsigned int mask = 0xff;
 
-       if (caps & AC_AMPCAP_MUTE) {
+       if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
                if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
                        mask &= ~0x80;
        }
index 8bd2261..f303cd8 100644 (file)
@@ -1031,6 +1031,7 @@ enum {
        ALC880_FIXUP_GPIO2,
        ALC880_FIXUP_MEDION_RIM,
        ALC880_FIXUP_LG,
+       ALC880_FIXUP_LG_LW25,
        ALC880_FIXUP_W810,
        ALC880_FIXUP_EAPD_COEF,
        ALC880_FIXUP_TCL_S700,
@@ -1089,6 +1090,14 @@ static const struct hda_fixup alc880_fixups[] = {
                        { }
                }
        },
+       [ALC880_FIXUP_LG_LW25] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x0181344f }, /* line-in */
+                       { 0x1b, 0x0321403f }, /* headphone */
+                       { }
+               }
+       },
        [ALC880_FIXUP_W810] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -1341,6 +1350,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
        SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
        SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
        SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
 
        /* Below is the copied entries from alc880_quirks.c.
@@ -4329,6 +4339,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
        SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
index 92b9b43..6d1924c 100644 (file)
@@ -2819,6 +2819,7 @@ static const struct hda_pintbl ecs202_pin_configs[] = {
 
 /* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */
 static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3),
        SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1),
        SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2),
        SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2),
index 45eeaa9..5138b84 100644 (file)
@@ -26,12 +26,9 @@ if SND_SOC
 config SND_SOC_AC97_BUS
        bool
 
-config SND_SOC_DMAENGINE_PCM
-       bool
-
 config SND_SOC_GENERIC_DMAENGINE_PCM
        bool
-       select SND_SOC_DMAENGINE_PCM
+       select SND_DMAENGINE_PCM
 
 # All the supported SoCs
 source "sound/soc/atmel/Kconfig"
index bc02614..61a64d2 100644 (file)
@@ -1,10 +1,6 @@
 snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
 snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o
 
-ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),)
-snd-soc-core-objs += soc-dmaengine-pcm.o
-endif
-
 ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
 snd-soc-core-objs += soc-generic-dmaengine-pcm.o
 endif
index 3fdd87f..e48d38a 100644 (file)
@@ -13,6 +13,7 @@ config SND_ATMEL_SOC_PDC
 config SND_ATMEL_SOC_DMA
        tristate
        depends on SND_ATMEL_SOC
+       select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_ATMEL_SOC_SSC
        tristate
@@ -32,6 +33,26 @@ config SND_AT91_SOC_SAM9G20_WM8731
          Say Y if you want to add support for SoC audio on WM8731-based
          AT91sam9g20 evaluation board.
 
+config SND_ATMEL_SOC_WM8904
+       tristate "Atmel ASoC driver for boards using WM8904 codec"
+       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
+       select SND_ATMEL_SOC_SSC
+       select SND_ATMEL_SOC_DMA
+       select SND_SOC_WM8904
+       help
+         Say Y if you want to add support for Atmel ASoC driver for boards using
+         WM8904 codec.
+
+config SND_AT91_SOC_SAM9X5_WM8731
+       tristate "SoC Audio support for WM8731-based at91sam9x5 board"
+       depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5
+       select SND_ATMEL_SOC_SSC
+       select SND_ATMEL_SOC_DMA
+       select SND_SOC_WM8731
+       help
+         Say Y if you want to add support for audio SoC on an
+         at91sam9x5 based board that is using WM8731 codec.
+
 config SND_AT91_SOC_AFEB9260
        tristate "SoC Audio support for AFEB9260 board"
        depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
index 41967cc..5baabc8 100644 (file)
@@ -11,6 +11,10 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o
 
 # AT91 Machine Support
 snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o
+snd-atmel-soc-wm8904-objs := atmel_wm8904.o
+snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
 
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
+obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
+obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
 obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
index d128265..06082e5 100644 (file)
@@ -91,138 +91,52 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
        }
 }
 
-/*--------------------------------------------------------------------------*\
- * DMAENGINE operations
-\*--------------------------------------------------------------------------*/
-static bool filter(struct dma_chan *chan, void *slave)
-{
-       struct at_dma_slave *sl = slave;
-
-       if (sl->dma_dev == chan->device->dev) {
-               chan->private = sl;
-               return true;
-       } else {
-               return false;
-       }
-}
-
 static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
+       struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct atmel_pcm_dma_params *prtd;
        struct ssc_device *ssc;
-       struct dma_chan *dma_chan;
-       struct dma_slave_config slave_config;
        int ret;
 
+       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
        ssc = prtd->ssc;
 
-       ret = snd_hwparams_to_dma_slave_config(substream, params,
-                       &slave_config);
+       ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
        if (ret) {
                pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
                return ret;
        }
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.dst_addr = (dma_addr_t)ssc->phybase + SSC_THR;
-               slave_config.dst_maxburst = 1;
+               slave_config->dst_addr = ssc->phybase + SSC_THR;
+               slave_config->dst_maxburst = 1;
        } else {
-               slave_config.src_addr = (dma_addr_t)ssc->phybase + SSC_RHR;
-               slave_config.src_maxburst = 1;
-       }
-
-       dma_chan = snd_dmaengine_pcm_get_chan(substream);
-       if (dmaengine_slave_config(dma_chan, &slave_config)) {
-               pr_err("atmel-pcm: failed to configure dma channel\n");
-               ret = -EBUSY;
-               return ret;
-       }
-
-       return 0;
-}
-
-static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct atmel_pcm_dma_params *prtd;
-       struct ssc_device *ssc;
-       struct at_dma_slave *sdata = NULL;
-       int ret;
-
-       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-
-       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       ssc = prtd->ssc;
-       if (ssc->pdev)
-               sdata = ssc->pdev->dev.platform_data;
-
-       ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
-       if (ret) {
-               pr_err("atmel-pcm: dmaengine pcm open failed\n");
-               return -EINVAL;
-       }
-
-       ret = atmel_pcm_configure_dma(substream, params, prtd);
-       if (ret) {
-               pr_err("atmel-pcm: failed to configure dmai\n");
-               goto err;
+               slave_config->src_addr = ssc->phybase + SSC_RHR;
+               slave_config->src_maxburst = 1;
        }
 
        prtd->dma_intr_handler = atmel_pcm_dma_irq;
 
        return 0;
-err:
-       snd_dmaengine_pcm_close_release_chan(substream);
-       return ret;
 }
 
-static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct atmel_pcm_dma_params *prtd;
-
-       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
-       ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
-
-       return 0;
-}
-
-static int atmel_pcm_open(struct snd_pcm_substream *substream)
-{
-       snd_soc_set_runtime_hwparams(substream, &atmel_pcm_dma_hardware);
-
-       return 0;
-}
-
-static struct snd_pcm_ops atmel_pcm_ops = {
-       .open           = atmel_pcm_open,
-       .close          = snd_dmaengine_pcm_close_release_chan,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = atmel_pcm_hw_params,
-       .prepare        = atmel_pcm_dma_prepare,
-       .trigger        = snd_dmaengine_pcm_trigger,
-       .pointer        = snd_dmaengine_pcm_pointer_no_residue,
-       .mmap           = atmel_pcm_mmap,
-};
-
-static struct snd_soc_platform_driver atmel_soc_platform = {
-       .ops            = &atmel_pcm_ops,
-       .pcm_new        = atmel_pcm_new,
-       .pcm_free       = atmel_pcm_free,
+static const struct snd_dmaengine_pcm_config atmel_dmaengine_pcm_config = {
+       .prepare_slave_config = atmel_pcm_configure_dma,
+       .pcm_hardware = &atmel_pcm_dma_hardware,
+       .prealloc_buffer_size = ATMEL_SSC_DMABUF_SIZE,
 };
 
 int atmel_pcm_dma_platform_register(struct device *dev)
 {
-       return snd_soc_register_platform(dev, &atmel_soc_platform);
+       return snd_dmaengine_pcm_register(dev, &atmel_dmaengine_pcm_config,
+                       SND_DMAENGINE_PCM_FLAG_NO_RESIDUE);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_register);
 
 void atmel_pcm_dma_platform_unregister(struct device *dev)
 {
-       snd_soc_unregister_platform(dev);
+       snd_dmaengine_pcm_unregister(dev);
 }
 EXPORT_SYMBOL(atmel_pcm_dma_platform_unregister);
 
index f3fdfa0..0ecf356 100644 (file)
@@ -73,6 +73,7 @@ static struct atmel_ssc_mask ssc_tx_mask = {
        .ssc_disable    = SSC_BIT(CR_TXDIS),
        .ssc_endx       = SSC_BIT(SR_ENDTX),
        .ssc_endbuf     = SSC_BIT(SR_TXBUFE),
+       .ssc_error      = SSC_BIT(SR_OVRUN),
        .pdc_enable     = ATMEL_PDC_TXTEN,
        .pdc_disable    = ATMEL_PDC_TXTDIS,
 };
@@ -82,6 +83,7 @@ static struct atmel_ssc_mask ssc_rx_mask = {
        .ssc_disable    = SSC_BIT(CR_RXDIS),
        .ssc_endx       = SSC_BIT(SR_ENDRX),
        .ssc_endbuf     = SSC_BIT(SR_RXBUFF),
+       .ssc_error      = SSC_BIT(SR_OVRUN),
        .pdc_enable     = ATMEL_PDC_RXTEN,
        .pdc_disable    = ATMEL_PDC_RXTDIS,
 };
@@ -196,15 +198,27 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *dai)
 {
        struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
-       int dir_mask;
+       struct atmel_pcm_dma_params *dma_params;
+       int dir, dir_mask;
 
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
                ssc_readl(ssc_p->ssc->regs, SR));
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               dir = 0;
                dir_mask = SSC_DIR_MASK_PLAYBACK;
-       else
+       } else {
+               dir = 1;
                dir_mask = SSC_DIR_MASK_CAPTURE;
+       }
+
+       dma_params = &ssc_dma_params[dai->id][dir];
+       dma_params->ssc = ssc_p->ssc;
+       dma_params->substream = substream;
+
+       ssc_p->dma_params[dir] = dma_params;
+
+       snd_soc_dai_set_dma_data(dai, substream, dma_params);
 
        spin_lock_irq(&ssc_p->lock);
        if (ssc_p->dir_mask & dir_mask) {
@@ -325,7 +339,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct snd_soc_dai *dai)
 {
-       struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
        int id = dai->id;
        struct atmel_ssc_info *ssc_p = &ssc_info[id];
        struct atmel_pcm_dma_params *dma_params;
@@ -344,19 +357,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        else
                dir = 1;
 
-       dma_params = &ssc_dma_params[id][dir];
-       dma_params->ssc = ssc_p->ssc;
-       dma_params->substream = substream;
-
-       ssc_p->dma_params[dir] = dma_params;
-
-       /*
-        * The snd_soc_pcm_stream->dma_data field is only used to communicate
-        * the appropriate DMA parameters to the pcm driver hw_params()
-        * function.  It should not be used for other purposes
-        * as it is common to all substreams.
-        */
-       snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
+       dma_params = ssc_p->dma_params[dir];
 
        channels = params_channels(params);
 
@@ -648,6 +649,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
        dma_params = ssc_p->dma_params[dir];
 
        ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
+       ssc_writel(ssc_p->ssc->regs, IER, dma_params->mask->ssc_error);
 
        pr_debug("%s enabled SSC_SR=0x%08x\n",
                        dir ? "receive" : "transmit",
diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c
new file mode 100644 (file)
index 0000000..7222380
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * atmel_wm8904 - Atmel ASoC driver for boards with WM8904 codec.
+ *
+ * Copyright (C) 2012 Atmel
+ *
+ * Author: Bo Shen <voice.shen@atmel.com>
+ *
+ * GPLv2 or later
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <sound/soc.h>
+
+#include "../codecs/wm8904.h"
+#include "atmel_ssc_dai.h"
+
+#define MCLK_RATE 32768
+
+static struct clk *mclk;
+
+static const struct snd_soc_dapm_widget atmel_asoc_wm8904_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_MIC("Mic", NULL),
+       SND_SOC_DAPM_LINE("Line In Jack", NULL),
+};
+
+static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream,
+               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_pll(codec_dai, WM8904_FLL_MCLK, WM8904_FLL_MCLK,
+               32768, params_rate(params) * 256);
+       if (ret < 0) {
+               pr_err("%s - failed to set wm8904 codec PLL.", __func__);
+               return ret;
+       }
+
+       /*
+        * As here wm8904 use FLL output as its system clock
+        * so calling set_sysclk won't care freq parameter
+        * then we pass 0
+        */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8904_CLK_FLL,
+                       0, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               pr_err("%s -failed to set wm8904 SYSCLK\n", __func__);
+               return ret;
+       }
+
+       return 0;
+}
+
+static struct snd_soc_ops atmel_asoc_wm8904_ops = {
+       .hw_params = atmel_asoc_wm8904_hw_params,
+};
+
+static int atmel_set_bias_level(struct snd_soc_card *card,
+               struct snd_soc_dapm_context *dapm,
+               enum snd_soc_bias_level level)
+{
+       if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+               switch (level) {
+               case SND_SOC_BIAS_PREPARE:
+                       clk_prepare_enable(mclk);
+                       break;
+               case SND_SOC_BIAS_OFF:
+                       clk_disable_unprepare(mclk);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+};
+
+static struct snd_soc_dai_link atmel_asoc_wm8904_dailink = {
+       .name = "WM8904",
+       .stream_name = "WM8904 PCM",
+       .codec_dai_name = "wm8904-hifi",
+       .dai_fmt = SND_SOC_DAIFMT_I2S
+               | SND_SOC_DAIFMT_NB_NF
+               | SND_SOC_DAIFMT_CBM_CFM,
+       .ops = &atmel_asoc_wm8904_ops,
+};
+
+static struct snd_soc_card atmel_asoc_wm8904_card = {
+       .name = "atmel_asoc_wm8904",
+       .owner = THIS_MODULE,
+       .set_bias_level = atmel_set_bias_level,
+       .dai_link = &atmel_asoc_wm8904_dailink,
+       .num_links = 1,
+       .dapm_widgets = atmel_asoc_wm8904_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(atmel_asoc_wm8904_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int atmel_asoc_wm8904_dt_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *codec_np, *cpu_np;
+       struct snd_soc_card *card = &atmel_asoc_wm8904_card;
+       struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "only device tree supported\n");
+               return -EINVAL;
+       }
+
+       ret = snd_soc_of_parse_card_name(card, "atmel,model");
+       if (ret) {
+               dev_err(&pdev->dev, "failed to parse card name\n");
+               return ret;
+       }
+
+       ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "failed to parse audio routing\n");
+               return ret;
+       }
+
+       cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "failed to get dai and pcm info\n");
+               ret = -EINVAL;
+               return ret;
+       }
+       dailink->cpu_of_node = cpu_np;
+       dailink->platform_of_node = cpu_np;
+       of_node_put(cpu_np);
+
+       codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "failed to get codec info\n");
+               ret = -EINVAL;
+               return ret;
+       }
+       dailink->codec_of_node = codec_np;
+       of_node_put(codec_np);
+
+       return 0;
+}
+
+static int atmel_asoc_wm8904_probe(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = &atmel_asoc_wm8904_card;
+       struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+       struct clk *clk_src;
+       struct pinctrl *pinctrl;
+       int id, ret;
+
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl)) {
+               dev_err(&pdev->dev, "failed to request pinctrl\n");
+               return PTR_ERR(pinctrl);
+       }
+
+       card->dev = &pdev->dev;
+       ret = atmel_asoc_wm8904_dt_init(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to init dt info\n");
+               return ret;
+       }
+
+       id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
+       ret = atmel_ssc_set_audio(id);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to set SSC %d for audio\n", id);
+               return ret;
+       }
+
+       mclk = clk_get(NULL, "pck0");
+       if (IS_ERR(mclk)) {
+               dev_err(&pdev->dev, "failed to get pck0\n");
+               ret = PTR_ERR(mclk);
+               goto err_set_audio;
+       }
+
+       clk_src = clk_get(NULL, "clk32k");
+       if (IS_ERR(clk_src)) {
+               dev_err(&pdev->dev, "failed to get clk32k\n");
+               ret = PTR_ERR(clk_src);
+               goto err_set_audio;
+       }
+
+       ret = clk_set_parent(mclk, clk_src);
+       clk_put(clk_src);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to set MCLK parent\n");
+               goto err_set_audio;
+       }
+
+       dev_info(&pdev->dev, "setting pck0 to %dHz\n", MCLK_RATE);
+       clk_set_rate(mclk, MCLK_RATE);
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed\n");
+               goto err_set_audio;
+       }
+
+       return 0;
+
+err_set_audio:
+       atmel_ssc_put_audio(id);
+       return ret;
+}
+
+static int atmel_asoc_wm8904_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct snd_soc_dai_link *dailink = &atmel_asoc_wm8904_dailink;
+       int id;
+
+       id = of_alias_get_id((struct device_node *)dailink->cpu_of_node, "ssc");
+
+       snd_soc_unregister_card(card);
+       atmel_ssc_put_audio(id);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_asoc_wm8904_dt_ids[] = {
+       { .compatible = "atmel,asoc-wm8904", },
+       { }
+};
+#endif
+
+static struct platform_driver atmel_asoc_wm8904_driver = {
+       .driver = {
+               .name = "atmel-wm8904-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids),
+       },
+       .probe = atmel_asoc_wm8904_probe,
+       .remove = atmel_asoc_wm8904_remove,
+};
+
+module_platform_driver(atmel_asoc_wm8904_driver);
+
+/* Module information */
+MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
+MODULE_DESCRIPTION("ALSA SoC machine driver for Atmel EK with WM8904 codec");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c
new file mode 100644 (file)
index 0000000..992ae38
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * sam9x5_wm8731   --  SoC audio for AT91SAM9X5-based boards
+ *                     that are using WM8731 as codec.
+ *
+ *  Copyright (C) 2011 Atmel,
+ *               Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ *  Copyright (C) 2013 Paratronic,
+ *               Richard Genoud <richard.genoud@gmail.com>
+ *
+ * Based on sam9g20_wm8731.c by:
+ * Sedji Gaouaou <sedji.gaouaou@atmel.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/of.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/wm8731.h"
+#include "atmel_ssc_dai.h"
+
+
+#define MCLK_RATE 12288000
+
+#define DRV_NAME "sam9x5-snd-wm8731"
+
+struct sam9x5_drvdata {
+       int ssc_id;
+};
+
+/*
+ * Logic for a wm8731 as connected on a at91sam9x5ek based board.
+ */
+static int sam9x5_wm8731_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct device *dev = rtd->dev;
+       int ret;
+
+       dev_dbg(dev, "ASoC: %s called\n", __func__);
+
+       /* set the codec system clock for DAC and ADC */
+       ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+                                    MCLK_RATE, SND_SOC_CLOCK_IN);
+       if (ret < 0) {
+               dev_err(dev, "ASoC: Failed to set WM8731 SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Audio paths on at91sam9x5ek board:
+ *
+ *  |A| ------------> |      | ---R----> Headphone Jack
+ *  |T| <----\        |  WM  | ---L--/
+ *  |9| ---> CLK <--> | 8731 | <--R----- Line In Jack
+ *  |1| <------------ |      | <--L--/
+ */
+static const struct snd_soc_dapm_widget sam9x5_dapm_widgets[] = {
+       SND_SOC_DAPM_HP("Headphone Jack", NULL),
+       SND_SOC_DAPM_LINE("Line In Jack", NULL),
+};
+
+static int sam9x5_wm8731_driver_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *codec_np, *cpu_np;
+       struct snd_soc_card *card;
+       struct snd_soc_dai_link *dai;
+       struct sam9x5_drvdata *priv;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "No device node supplied\n");
+               return -EINVAL;
+       }
+
+       card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       dai = devm_kzalloc(&pdev->dev, sizeof(*dai), GFP_KERNEL);
+       if (!dai || !card || !priv) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       card->dev = &pdev->dev;
+       card->owner = THIS_MODULE;
+       card->dai_link = dai;
+       card->num_links = 1;
+       card->dapm_widgets = sam9x5_dapm_widgets;
+       card->num_dapm_widgets = ARRAY_SIZE(sam9x5_dapm_widgets);
+       dai->name = "WM8731";
+       dai->stream_name = "WM8731 PCM";
+       dai->codec_dai_name = "wm8731-hifi";
+       dai->init = sam9x5_wm8731_init;
+       dai->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+               | SND_SOC_DAIFMT_CBM_CFM;
+
+       ret = snd_soc_of_parse_card_name(card, "atmel,model");
+       if (ret) {
+               dev_err(&pdev->dev, "atmel,model node missing\n");
+               goto out;
+       }
+
+       ret = snd_soc_of_parse_audio_routing(card, "atmel,audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "atmel,audio-routing node missing\n");
+               goto out;
+       }
+
+       codec_np = of_parse_phandle(np, "atmel,audio-codec", 0);
+       if (!codec_np) {
+               dev_err(&pdev->dev, "atmel,audio-codec node missing\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       dai->codec_of_node = codec_np;
+
+       cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0);
+       if (!cpu_np) {
+               dev_err(&pdev->dev, "atmel,ssc-controller node missing\n");
+               ret = -EINVAL;
+               goto out;
+       }
+       dai->cpu_of_node = cpu_np;
+       dai->platform_of_node = cpu_np;
+
+       priv->ssc_id = of_alias_get_id(cpu_np, "ssc");
+
+       ret = atmel_ssc_set_audio(priv->ssc_id);
+       if (ret != 0) {
+               dev_err(&pdev->dev,
+                       "ASoC: Failed to set SSC %d for audio: %d\n",
+                       ret, priv->ssc_id);
+               goto out;
+       }
+
+       of_node_put(codec_np);
+       of_node_put(cpu_np);
+
+       platform_set_drvdata(pdev, card);
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "ASoC: Platform device allocation failed\n");
+               goto out_put_audio;
+       }
+
+       dev_dbg(&pdev->dev, "ASoC: %s ok\n", __func__);
+
+       return ret;
+
+out_put_audio:
+       atmel_ssc_put_audio(priv->ssc_id);
+out:
+       return ret;
+}
+
+static int sam9x5_wm8731_driver_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct sam9x5_drvdata *priv = card->drvdata;
+
+       snd_soc_unregister_card(card);
+       atmel_ssc_put_audio(priv->ssc_id);
+
+       return 0;
+}
+
+static const struct of_device_id sam9x5_wm8731_of_match[] = {
+       { .compatible = "atmel,sam9x5-wm8731-audio", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sam9x5_wm8731_of_match);
+
+static struct platform_driver sam9x5_wm8731_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(sam9x5_wm8731_of_match),
+       },
+       .probe = sam9x5_wm8731_driver_probe,
+       .remove = sam9x5_wm8731_driver_remove,
+};
+module_platform_driver(sam9x5_wm8731_driver);
+
+/* Module information */
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@atmel.com>");
+MODULE_AUTHOR("Richard Genoud <richard.genoud@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC machine driver for AT91SAM9x5 - WM8731");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
index d6f7694..c8a2de1 100644 (file)
@@ -341,7 +341,7 @@ static struct platform_driver au1xac97c_driver = {
        .remove         = au1xac97c_drvremove,
 };
 
-module_platform_driver(&au1xac97c_driver);
+module_platform_driver(au1xac97c_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
index a497a0c..decba87 100644 (file)
@@ -73,12 +73,14 @@ static struct snd_soc_dai_link db1300_ac97_dai = {
 
 static struct snd_soc_card db1300_ac97_machine = {
        .name           = "DB1300_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1300_ac97_dai,
        .num_links      = 1,
 };
 
 static struct snd_soc_card db1550_ac97_machine = {
        .name           = "DB1550_AC97",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1200_ac97_dai,
        .num_links      = 1,
 };
@@ -145,6 +147,7 @@ static struct snd_soc_dai_link db1300_i2s_dai = {
 
 static struct snd_soc_card db1300_i2s_machine = {
        .name           = "DB1300_I2S",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1300_i2s_dai,
        .num_links      = 1,
 };
@@ -161,6 +164,7 @@ static struct snd_soc_dai_link db1550_i2s_dai = {
 
 static struct snd_soc_card db1550_i2s_machine = {
        .name           = "DB1550_I2S",
+       .owner          = THIS_MODULE,
        .dai_link       = &db1550_i2s_dai,
        .num_links      = 1,
 };
index a822ab8..986dcec 100644 (file)
@@ -379,9 +379,6 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
        mutex_init(&wd->lock);
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -ENODEV;
-
        wd->mmio = devm_ioremap_resource(&pdev->dev, iores);
        if (IS_ERR(wd->mmio))
                return PTR_ERR(wd->mmio);
index efb1dae..e82eb37 100644 (file)
@@ -294,11 +294,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
        /* Request PB3 as reset pin */
        ret = devm_gpio_request_one(&pdev->dev,
                                    CONFIG_SND_BF5XX_RESET_GPIO_NUM,
-                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") {
+                                   GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET");
+       if (ret) {
                dev_err(&pdev->dev,
                        "Failed to request GPIO_%d for reset: %d\n",
                        CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
-               goto gpio_err;
+               return ret;
        }
 #endif
 
index 15c635e..a680fdc 100644 (file)
@@ -9,8 +9,6 @@
 #ifndef _BF5XX_AC97_H
 #define _BF5XX_AC97_H
 
-extern struct snd_ac97_bus_ops bf5xx_ac97_ops;
-extern struct snd_ac97 *ac97;
 /* Frame format in memory, only support stereo currently */
 struct ac97_frame {
        u16 ac97_tag;           /* slot 0 */
index 04491f0..efa75b5 100644 (file)
@@ -363,9 +363,6 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        info->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(info->regs))
                return PTR_ERR(info->regs);
index 17ad70b..f23f331 100644 (file)
@@ -376,9 +376,6 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        info->regs = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(info->regs))
                return PTR_ERR(info->regs);
index badb6fb..15106c0 100644 (file)
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
 
 config SND_SOC_ALL_CODECS
        tristate "Build all ASoC CODEC drivers"
+       depends on COMPILE_TEST
        select SND_SOC_88PM860X if MFD_88PM860X
        select SND_SOC_L3
        select SND_SOC_AB8500_CODEC if ABX500_CORE
@@ -20,6 +21,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AD73311
        select SND_SOC_ADAU1373 if I2C
        select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI
+       select SND_SOC_ADAU1701 if I2C
        select SND_SOC_ADS117X
        select SND_SOC_AK4104 if SPI_MASTER
        select SND_SOC_AK4535 if I2C
@@ -54,6 +56,8 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_MC13783 if MFD_MC13XXX
        select SND_SOC_ML26124 if I2C
        select SND_SOC_HDMI_CODEC
+       select SND_SOC_PCM1681 if I2C
+       select SND_SOC_PCM1792A if SPI_MASTER
        select SND_SOC_PCM3008
        select SND_SOC_RT5631 if I2C
        select SND_SOC_RT5640 if I2C
@@ -122,6 +126,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8994 if MFD_WM8994
        select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8996 if I2C
+       select SND_SOC_WM8997 if MFD_WM8997
        select SND_SOC_WM9081 if I2C
        select SND_SOC_WM9090 if I2C
        select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@@ -145,8 +150,10 @@ config SND_SOC_ARIZONA
        tristate
        default y if SND_SOC_WM5102=y
        default y if SND_SOC_WM5110=y
+       default y if SND_SOC_WM8997=y
        default m if SND_SOC_WM5102=m
        default m if SND_SOC_WM5110=m
+       default m if SND_SOC_WM8997=m
 
 config SND_SOC_WM_HUBS
        tristate
@@ -198,6 +205,9 @@ config SND_SOC_AK4104
 config SND_SOC_AK4535
        tristate
 
+config SND_SOC_AK4554
+       tristate
+
 config SND_SOC_AK4641
        tristate
 
@@ -292,6 +302,12 @@ config SND_SOC_MAX9850
 config SND_SOC_HDMI_CODEC
        tristate
 
+config SND_SOC_PCM1681
+       tristate
+
+config SND_SOC_PCM1792A
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -500,6 +516,9 @@ config SND_SOC_WM8995
 config SND_SOC_WM8996
        tristate
 
+config SND_SOC_WM8997
+       tristate
+
 config SND_SOC_WM9081
        tristate
 
index 70fd806..bc12676 100644 (file)
@@ -11,6 +11,7 @@ snd-soc-adav80x-objs := adav80x.o
 snd-soc-ads117x-objs := ads117x.o
 snd-soc-ak4104-objs := ak4104.o
 snd-soc-ak4535-objs := ak4535.o
+snd-soc-ak4554-objs := ak4554.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
@@ -42,6 +43,8 @@ snd-soc-max9850-objs := max9850.o
 snd-soc-mc13783-objs := mc13783.o
 snd-soc-ml26124-objs := ml26124.o
 snd-soc-hdmi-codec-objs := hdmi.o
+snd-soc-pcm1681-objs := pcm1681.o
+snd-soc-pcm1792a-codec-objs := pcm1792a.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
@@ -114,6 +117,7 @@ snd-soc-wm8991-objs := wm8991.o
 snd-soc-wm8993-objs := wm8993.o
 snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o
 snd-soc-wm8995-objs := wm8995.o
+snd-soc-wm8997-objs := wm8997.o
 snd-soc-wm9081-objs := wm9081.o
 snd-soc-wm9090-objs := wm9090.o
 snd-soc-wm9705-objs := wm9705.o
@@ -138,6 +142,7 @@ obj-$(CONFIG_SND_SOC_ADAV80X)  += snd-soc-adav80x.o
 obj-$(CONFIG_SND_SOC_ADS117X)  += snd-soc-ads117x.o
 obj-$(CONFIG_SND_SOC_AK4104)   += snd-soc-ak4104.o
 obj-$(CONFIG_SND_SOC_AK4535)   += snd-soc-ak4535.o
+obj-$(CONFIG_SND_SOC_AK4554)   += snd-soc-ak4554.o
 obj-$(CONFIG_SND_SOC_AK4641)   += snd-soc-ak4641.o
 obj-$(CONFIG_SND_SOC_AK4642)   += snd-soc-ak4642.o
 obj-$(CONFIG_SND_SOC_AK4671)   += snd-soc-ak4671.o
@@ -171,6 +176,8 @@ obj-$(CONFIG_SND_SOC_MAX9850)       += snd-soc-max9850.o
 obj-$(CONFIG_SND_SOC_MC13783)  += snd-soc-mc13783.o
 obj-$(CONFIG_SND_SOC_ML26124)  += snd-soc-ml26124.o
 obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
+obj-$(CONFIG_SND_SOC_PCM1681)  += snd-soc-pcm1681.o
+obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
 obj-$(CONFIG_SND_SOC_PCM3008)  += snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(CONFIG_SND_SOC_RT5640)   += snd-soc-rt5640.o
@@ -239,6 +246,7 @@ obj-$(CONFIG_SND_SOC_WM8991)        += snd-soc-wm8991.o
 obj-$(CONFIG_SND_SOC_WM8993)   += snd-soc-wm8993.o
 obj-$(CONFIG_SND_SOC_WM8994)   += snd-soc-wm8994.o
 obj-$(CONFIG_SND_SOC_WM8995)   += snd-soc-wm8995.o
+obj-$(CONFIG_SND_SOC_WM8997)   += snd-soc-wm8997.o
 obj-$(CONFIG_SND_SOC_WM9081)   += snd-soc-wm9081.o
 obj-$(CONFIG_SND_SOC_WM9090)   += snd-soc-wm9090.o
 obj-$(CONFIG_SND_SOC_WM9705)   += snd-soc-wm9705.o
index ec73518..8d9ba4b 100644 (file)
 #include <sound/initval.h>
 #include <sound/soc.h>
 
+static const struct snd_soc_dapm_widget ac97_widgets[] = {
+       SND_SOC_DAPM_INPUT("RX"),
+       SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route ac97_routes[] = {
+       { "AC97 Capture", NULL, "RX" },
+       { "TX", NULL, "AC97 Playback" },
+};
+
 static int ac97_prepare(struct snd_pcm_substream *substream,
                        struct snd_soc_dai *dai)
 {
@@ -117,6 +127,11 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
        .probe =        ac97_soc_probe,
        .suspend =      ac97_soc_suspend,
        .resume =       ac97_soc_resume,
+
+       .dapm_widgets = ac97_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ac97_widgets),
+       .dapm_routes = ac97_routes,
+       .num_dapm_routes = ARRAY_SIZE(ac97_routes),
 };
 
 static int ac97_probe(struct platform_device *pdev)
index 89fcf7d..7257a88 100644 (file)
@@ -96,6 +96,44 @@ SOC_ENUM("Capture Source", ad1980_cap_src),
 SOC_SINGLE("Mic Boost Switch", AC97_MIC, 6, 1, 0),
 };
 
+static const struct snd_soc_dapm_widget ad1980_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MIC1"),
+SND_SOC_DAPM_INPUT("MIC2"),
+SND_SOC_DAPM_INPUT("CD_L"),
+SND_SOC_DAPM_INPUT("CD_R"),
+SND_SOC_DAPM_INPUT("AUX_L"),
+SND_SOC_DAPM_INPUT("AUX_R"),
+SND_SOC_DAPM_INPUT("LINE_IN_L"),
+SND_SOC_DAPM_INPUT("LINE_IN_R"),
+
+SND_SOC_DAPM_OUTPUT("LFE_OUT"),
+SND_SOC_DAPM_OUTPUT("CENTER_OUT"),
+SND_SOC_DAPM_OUTPUT("LINE_OUT_L"),
+SND_SOC_DAPM_OUTPUT("LINE_OUT_R"),
+SND_SOC_DAPM_OUTPUT("MONO_OUT"),
+SND_SOC_DAPM_OUTPUT("HP_OUT_L"),
+SND_SOC_DAPM_OUTPUT("HP_OUT_R"),
+};
+
+static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
+       { "Capture", NULL, "MIC1" },
+       { "Capture", NULL, "MIC2" },
+       { "Capture", NULL, "CD_L" },
+       { "Capture", NULL, "CD_R" },
+       { "Capture", NULL, "AUX_L" },
+       { "Capture", NULL, "AUX_R" },
+       { "Capture", NULL, "LINE_IN_L" },
+       { "Capture", NULL, "LINE_IN_R" },
+
+       { "LFE_OUT", NULL, "Playback" },
+       { "CENTER_OUT", NULL, "Playback" },
+       { "LINE_OUT_L", NULL, "Playback" },
+       { "LINE_OUT_R", NULL, "Playback" },
+       { "MONO_OUT", NULL, "Playback" },
+       { "HP_OUT_L", NULL, "Playback" },
+       { "HP_OUT_R", NULL, "Playback" },
+};
+
 static unsigned int ac97_read(struct snd_soc_codec *codec,
        unsigned int reg)
 {
@@ -253,6 +291,11 @@ static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
        .reg_cache_step = 2,
        .write = ac97_write,
        .read = ac97_read,
+
+       .dapm_widgets = ad1980_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
+       .dapm_routes = ad1980_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ad1980_dapm_routes),
 };
 
 static int ad1980_probe(struct platform_device *pdev)
index b1f2baf..5fac8ad 100644 (file)
 
 #include "ad73311.h"
 
+static const struct snd_soc_dapm_widget ad73311_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("VINP"),
+SND_SOC_DAPM_INPUT("VINN"),
+SND_SOC_DAPM_OUTPUT("VOUTN"),
+SND_SOC_DAPM_OUTPUT("VOUTP"),
+};
+
+static const struct snd_soc_dapm_route ad73311_dapm_routes[] = {
+       { "Capture", NULL, "VINP" },
+       { "Capture", NULL, "VINN" },
+
+       { "VOUTN", NULL, "Playback" },
+       { "VOUTP", NULL, "Playback" },
+};
+
 static struct snd_soc_dai_driver ad73311_dai = {
        .name = "ad73311-hifi",
        .playback = {
@@ -39,7 +54,12 @@ static struct snd_soc_dai_driver ad73311_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ad73311;
+static struct snd_soc_codec_driver soc_codec_dev_ad73311 = {
+       .dapm_widgets = ad73311_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ad73311_dapm_widgets),
+       .dapm_routes = ad73311_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ad73311_dapm_routes),
+};
 
 static int ad73311_probe(struct platform_device *pdev)
 {
index d1124a5..ebff112 100644 (file)
@@ -91,7 +91,7 @@
 #define ADAU1701_OSCIPOW_OPD           0x04
 #define ADAU1701_DACSET_DACINIT                1
 
-#define ADAU1707_CLKDIV_UNSET          (-1UL)
+#define ADAU1707_CLKDIV_UNSET          (-1U)
 
 #define ADAU1701_FIRMWARE "adau1701.bin"
 
@@ -247,21 +247,21 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
            gpio_is_valid(adau1701->gpio_pll_mode[1])) {
                switch (clkdiv) {
                case 64:
-                       gpio_set_value(adau1701->gpio_pll_mode[0], 0);
-                       gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
                        break;
                case 256:
-                       gpio_set_value(adau1701->gpio_pll_mode[0], 0);
-                       gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 0);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
                        break;
                case 384:
-                       gpio_set_value(adau1701->gpio_pll_mode[0], 1);
-                       gpio_set_value(adau1701->gpio_pll_mode[1], 0);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 0);
                        break;
                case 0: /* fallback */
                case 512:
-                       gpio_set_value(adau1701->gpio_pll_mode[0], 1);
-                       gpio_set_value(adau1701->gpio_pll_mode[1], 1);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[0], 1);
+                       gpio_set_value_cansleep(adau1701->gpio_pll_mode[1], 1);
                        break;
                }
        }
@@ -269,10 +269,10 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
        adau1701->pll_clkdiv = clkdiv;
 
        if (gpio_is_valid(adau1701->gpio_nreset)) {
-               gpio_set_value(adau1701->gpio_nreset, 0);
+               gpio_set_value_cansleep(adau1701->gpio_nreset, 0);
                /* minimum reset time is 20ns */
                udelay(1);
-               gpio_set_value(adau1701->gpio_nreset, 1);
+               gpio_set_value_cansleep(adau1701->gpio_nreset, 1);
                /* power-up time may be as long as 85ms */
                mdelay(85);
        }
@@ -734,7 +734,10 @@ static int adau1701_i2c_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id adau1701_i2c_id[] = {
+       { "adau1401", 0 },
+       { "adau1401a", 0 },
        { "adau1701", 0 },
+       { "adau1702", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id);
index 3c839cc..15b012d 100644 (file)
@@ -868,6 +868,12 @@ static int adav80x_bus_remove(struct device *dev)
 }
 
 #if defined(CONFIG_SPI_MASTER)
+static const struct spi_device_id adav80x_spi_id[] = {
+       { "adav801", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, adav80x_spi_id);
+
 static int adav80x_spi_probe(struct spi_device *spi)
 {
        return adav80x_bus_probe(&spi->dev, SND_SOC_SPI);
@@ -885,15 +891,16 @@ static struct spi_driver adav80x_spi_driver = {
        },
        .probe          = adav80x_spi_probe,
        .remove         = adav80x_spi_remove,
+       .id_table       = adav80x_spi_id,
 };
 #endif
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static const struct i2c_device_id adav80x_id[] = {
+static const struct i2c_device_id adav80x_i2c_id[] = {
        { "adav803", 0 },
        { }
 };
-MODULE_DEVICE_TABLE(i2c, adav80x_id);
+MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id);
 
 static int adav80x_i2c_probe(struct i2c_client *client,
                             const struct i2c_device_id *id)
@@ -913,7 +920,7 @@ static struct i2c_driver adav80x_i2c_driver = {
        },
        .probe = adav80x_i2c_probe,
        .remove = adav80x_i2c_remove,
-       .id_table = adav80x_id,
+       .id_table = adav80x_i2c_id,
 };
 #endif
 
index 506d474..8f388ed 100644 (file)
 #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
 #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 
+static const struct snd_soc_dapm_widget ads117x_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("Input1"),
+SND_SOC_DAPM_INPUT("Input2"),
+SND_SOC_DAPM_INPUT("Input3"),
+SND_SOC_DAPM_INPUT("Input4"),
+SND_SOC_DAPM_INPUT("Input5"),
+SND_SOC_DAPM_INPUT("Input6"),
+SND_SOC_DAPM_INPUT("Input7"),
+SND_SOC_DAPM_INPUT("Input8"),
+};
+
+static const struct snd_soc_dapm_route ads117x_dapm_routes[] = {
+       { "Capture", NULL, "Input1" },
+       { "Capture", NULL, "Input2" },
+       { "Capture", NULL, "Input3" },
+       { "Capture", NULL, "Input4" },
+       { "Capture", NULL, "Input5" },
+       { "Capture", NULL, "Input6" },
+       { "Capture", NULL, "Input7" },
+       { "Capture", NULL, "Input8" },
+};
+
 static struct snd_soc_dai_driver ads117x_dai = {
 /* ADC */
        .name = "ads117x-hifi",
@@ -34,7 +56,12 @@ static struct snd_soc_dai_driver ads117x_dai = {
                .formats = ADS117X_FORMATS,},
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_ads117x;
+static struct snd_soc_codec_driver soc_codec_dev_ads117x = {
+       .dapm_widgets = ads117x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ads117x_dapm_widgets),
+       .dapm_routes = ads117x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ads117x_dapm_routes),
+};
 
 static int ads117x_probe(struct platform_device *pdev)
 {
index c7cfdf9..71059c0 100644 (file)
@@ -51,6 +51,17 @@ struct ak4104_private {
        struct regmap *regmap;
 };
 
+static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = {
+SND_SOC_DAPM_PGA("TXE", AK4104_REG_TX, AK4104_TX_TXE, 0, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route ak4104_dapm_routes[] = {
+       { "TXE", NULL, "Playback" },
+       { "TX", NULL, "TXE" },
+};
+
 static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
 {
@@ -138,29 +149,11 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       /* enable transmitter */
-       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
-                                AK4104_TX_TXE, AK4104_TX_TXE);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
-static int ak4104_hw_free(struct snd_pcm_substream *substream,
-                         struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
-
-       /* disable transmitter */
-       return regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
-                                 AK4104_TX_TXE, 0);
-}
-
 static const struct snd_soc_dai_ops ak4101_dai_ops = {
        .hw_params = ak4104_hw_params,
-       .hw_free = ak4104_hw_free,
        .set_fmt = ak4104_set_dai_fmt,
 };
 
@@ -214,6 +207,11 @@ static int ak4104_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
        .probe =        ak4104_probe,
        .remove =       ak4104_remove,
+
+       .dapm_widgets = ak4104_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets),
+       .dapm_routes = ak4104_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ak4104_dapm_routes),
 };
 
 static const struct regmap_config ak4104_regmap = {
diff --git a/sound/soc/codecs/ak4554.c b/sound/soc/codecs/ak4554.c
new file mode 100644 (file)
index 0000000..79e9555
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ak4554.c
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+/*
+ * ak4554 is very simple DA/AD converter which has no setting register.
+ *
+ * CAUTION
+ *
+ * ak4554 playback format is SND_SOC_DAIFMT_RIGHT_J,
+ * and,   capture  format is SND_SOC_DAIFMT_LEFT_J
+ * on same bit clock, LR clock.
+ * But, this driver doesn't have snd_soc_dai_ops :: set_fmt
+ *
+ * CPU/Codec DAI image
+ *
+ * CPU-DAI1 (plaback only fmt = RIGHT_J) --+-- ak4554
+ *                                        |
+ * CPU-DAI2 (capture only fmt = LEFT_J) ---+
+ */
+
+static const struct snd_soc_dapm_widget ak4554_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+
+SND_SOC_DAPM_OUTPUT("AOUTL"),
+SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route ak4554_dapm_routes[] = {
+       { "Capture", NULL, "AINL" },
+       { "Capture", NULL, "AINR" },
+
+       { "AOUTL", NULL, "Playback" },
+       { "AOUTR", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver ak4554_dai = {
+       .name = "ak4554-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .symmetric_rates = 1,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_ak4554 = {
+       .dapm_widgets = ak4554_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak4554_dapm_widgets),
+       .dapm_routes = ak4554_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ak4554_dapm_routes),
+};
+
+static int ak4554_soc_probe(struct platform_device *pdev)
+{
+       return snd_soc_register_codec(&pdev->dev,
+                                     &soc_codec_dev_ak4554,
+                                     &ak4554_dai, 1);
+}
+
+static int ak4554_soc_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct of_device_id ak4554_of_match[] = {
+       { .compatible = "asahi-kasei,ak4554" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ak4554_of_match);
+
+static struct platform_driver ak4554_driver = {
+       .driver = {
+               .name = "ak4554-adc-dac",
+               .owner = THIS_MODULE,
+               .of_match_table = ak4554_of_match,
+       },
+       .probe  = ak4554_soc_probe,
+       .remove = ak4554_soc_remove,
+};
+module_platform_driver(ak4554_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SoC AK4554 driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 1f30398..72e953b 100644 (file)
@@ -22,7 +22,22 @@ struct ak5386_priv {
        int reset_gpio;
 };
 
-static struct snd_soc_codec_driver soc_codec_ak5386;
+static const struct snd_soc_dapm_widget ak5386_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+};
+
+static const struct snd_soc_dapm_route ak5386_dapm_routes[] = {
+       { "Capture", NULL, "AINL" },
+       { "Capture", NULL, "AINR" },
+};
+
+static struct snd_soc_codec_driver soc_codec_ak5386 = {
+       .dapm_widgets = ak5386_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(ak5386_dapm_widgets),
+       .dapm_routes = ak5386_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(ak5386_dapm_routes),
+};
 
 static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
index de62581..657808b 100644 (file)
@@ -19,6 +19,7 @@
 #include <sound/tlv.h>
 
 #include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/gpio.h>
 #include <linux/mfd/arizona/registers.h>
 
 #include "arizona.h"
@@ -199,9 +200,16 @@ int arizona_init_spk(struct snd_soc_codec *codec)
        if (ret != 0)
                return ret;
 
-       ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
-       if (ret != 0)
-               return ret;
+       switch (arizona->type) {
+       case WM8997:
+               break;
+       default:
+               ret = snd_soc_dapm_new_controls(&codec->dapm,
+                                               &arizona_spkr, 1);
+               if (ret != 0)
+                       return ret;
+               break;
+       }
 
        ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
                                  "Thermal warning", arizona_thermal_warn,
@@ -223,6 +231,41 @@ int arizona_init_spk(struct snd_soc_codec *codec)
 }
 EXPORT_SYMBOL_GPL(arizona_init_spk);
 
+int arizona_init_gpio(struct snd_soc_codec *codec)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       int i;
+
+       switch (arizona->type) {
+       case WM5110:
+               snd_soc_dapm_disable_pin(&codec->dapm, "DRC2 Signal Activity");
+               break;
+       default:
+               break;
+       }
+
+       snd_soc_dapm_disable_pin(&codec->dapm, "DRC1 Signal Activity");
+
+       for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) {
+               switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) {
+               case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT:
+                       snd_soc_dapm_enable_pin(&codec->dapm,
+                                               "DRC1 Signal Activity");
+                       break;
+               case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT:
+                       snd_soc_dapm_enable_pin(&codec->dapm,
+                                               "DRC2 Signal Activity");
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_gpio);
+
 const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "None",
        "Tone Generator 1",
@@ -517,6 +560,26 @@ const struct soc_enum arizona_ng_hold =
                        4, arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
+static const char * const arizona_in_dmic_osr_text[] = {
+       "1.536MHz", "3.072MHz", "6.144MHz",
+};
+
+const struct soc_enum arizona_in_dmic_osr[] = {
+       SOC_ENUM_SINGLE(ARIZONA_IN1L_CONTROL, ARIZONA_IN1_OSR_SHIFT,
+                       ARRAY_SIZE(arizona_in_dmic_osr_text),
+                       arizona_in_dmic_osr_text),
+       SOC_ENUM_SINGLE(ARIZONA_IN2L_CONTROL, ARIZONA_IN2_OSR_SHIFT,
+                       ARRAY_SIZE(arizona_in_dmic_osr_text),
+                       arizona_in_dmic_osr_text),
+       SOC_ENUM_SINGLE(ARIZONA_IN3L_CONTROL, ARIZONA_IN3_OSR_SHIFT,
+                       ARRAY_SIZE(arizona_in_dmic_osr_text),
+                       arizona_in_dmic_osr_text),
+       SOC_ENUM_SINGLE(ARIZONA_IN4L_CONTROL, ARIZONA_IN4_OSR_SHIFT,
+                       ARRAY_SIZE(arizona_in_dmic_osr_text),
+                       arizona_in_dmic_osr_text),
+};
+EXPORT_SYMBOL_GPL(arizona_in_dmic_osr);
+
 static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 {
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
index b60b08c..9e81b63 100644 (file)
@@ -150,7 +150,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MUX(name_str " Aux 5", &name##_aux5_mux), \
        ARIZONA_MUX(name_str " Aux 6", &name##_aux6_mux)
 
-#define ARIZONA_MUX_ROUTES(name) \
+#define ARIZONA_MUX_ROUTES(widget, name) \
+       { widget, NULL, name " Input" }, \
        ARIZONA_MIXER_INPUT_ROUTES(name " Input")
 
 #define ARIZONA_MIXER_ROUTES(widget, name) \
@@ -198,6 +199,7 @@ extern const struct soc_enum arizona_lhpf3_mode;
 extern const struct soc_enum arizona_lhpf4_mode;
 
 extern const struct soc_enum arizona_ng_hold;
+extern const struct soc_enum arizona_in_dmic_osr[];
 
 extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol,
@@ -242,6 +244,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source,
                           unsigned int Fref, unsigned int Fout);
 
 extern int arizona_init_spk(struct snd_soc_codec *codec);
+extern int arizona_init_gpio(struct snd_soc_codec *codec);
 
 extern int arizona_init_dai(struct arizona_priv *priv, int dai);
 
index a081d9f..c4cf069 100644 (file)
 
 #include <sound/soc.h>
 
+static const struct snd_soc_dapm_widget bt_sco_widgets[] = {
+       SND_SOC_DAPM_INPUT("RX"),
+       SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route bt_sco_routes[] = {
+       { "Capture", NULL, "RX" },
+       { "TX", NULL, "Playback" },
+};
+
 static struct snd_soc_dai_driver bt_sco_dai = {
        .name = "bt-sco-pcm",
        .playback = {
+               .stream_name = "Playback",
                .channels_min = 1,
                .channels_max = 1,
                .rates = SNDRV_PCM_RATE_8000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
+                .stream_name = "Capture",
                .channels_min = 1,
                .channels_max = 1,
                .rates = SNDRV_PCM_RATE_8000,
@@ -31,7 +43,12 @@ static struct snd_soc_dai_driver bt_sco_dai = {
        },
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_bt_sco;
+static struct snd_soc_codec_driver soc_codec_dev_bt_sco = {
+       .dapm_widgets = bt_sco_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(bt_sco_widgets),
+       .dapm_routes = bt_sco_routes,
+       .num_dapm_routes = ARRAY_SIZE(bt_sco_routes),
+};
 
 static int bt_sco_probe(struct platform_device *pdev)
 {
@@ -50,6 +67,9 @@ static struct platform_device_id bt_sco_driver_ids[] = {
        {
                .name           = "dfbmcs320",
        },
+       {
+               .name           = "bt-sco",
+       },
        {},
 };
 MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids);
index 8e47798..83c835d 100644 (file)
@@ -139,6 +139,22 @@ struct cs4270_private {
        struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
 };
 
+static const struct snd_soc_dapm_widget cs4270_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINL"),
+SND_SOC_DAPM_INPUT("AINR"),
+
+SND_SOC_DAPM_OUTPUT("AOUTL"),
+SND_SOC_DAPM_OUTPUT("AOUTR"),
+};
+
+static const struct snd_soc_dapm_route cs4270_dapm_routes[] = {
+       { "Capture", NULL, "AINA" },
+       { "Capture", NULL, "AINB" },
+
+       { "AOUTA", NULL, "Playback" },
+       { "AOUTB", NULL, "Playback" },
+};
+
 /**
  * struct cs4270_mode_ratios - clock ratio tables
  * @ratio: the ratio of MCLK to the sample rate
@@ -612,6 +628,10 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
 
        .controls =             cs4270_snd_controls,
        .num_controls =         ARRAY_SIZE(cs4270_snd_controls),
+       .dapm_widgets =         cs4270_dapm_widgets,
+       .num_dapm_widgets =     ARRAY_SIZE(cs4270_dapm_widgets),
+       .dapm_routes =          cs4270_dapm_routes,
+       .num_dapm_routes =      ARRAY_SIZE(cs4270_dapm_routes),
 };
 
 /*
index 03036b3..a20f1bb 100644 (file)
@@ -173,6 +173,26 @@ struct cs4271_private {
        bool                            enable_soft_reset;
 };
 
+static const struct snd_soc_dapm_widget cs4271_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("AINA"),
+SND_SOC_DAPM_INPUT("AINB"),
+
+SND_SOC_DAPM_OUTPUT("AOUTA+"),
+SND_SOC_DAPM_OUTPUT("AOUTA-"),
+SND_SOC_DAPM_OUTPUT("AOUTB+"),
+SND_SOC_DAPM_OUTPUT("AOUTB-"),
+};
+
+static const struct snd_soc_dapm_route cs4271_dapm_routes[] = {
+       { "Capture", NULL, "AINA" },
+       { "Capture", NULL, "AINB" },
+
+       { "AOUTA+", NULL, "Playback" },
+       { "AOUTA-", NULL, "Playback" },
+       { "AOUTB+", NULL, "Playback" },
+       { "AOUTB-", NULL, "Playback" },
+};
+
 /*
  * @freq is the desired MCLK rate
  * MCLK rate should (c) be the sample rate, multiplied by one of the
@@ -576,8 +596,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
                                   CS4271_MODE2_MUTECAEQUB,
                                   CS4271_MODE2_MUTECAEQUB);
 
-       return snd_soc_add_codec_controls(codec, cs4271_snd_controls,
-               ARRAY_SIZE(cs4271_snd_controls));
+       return 0;
 }
 
 static int cs4271_remove(struct snd_soc_codec *codec)
@@ -596,6 +615,13 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
        .remove                 = cs4271_remove,
        .suspend                = cs4271_soc_suspend,
        .resume                 = cs4271_soc_resume,
+
+       .controls               = cs4271_snd_controls,
+       .num_controls           = ARRAY_SIZE(cs4271_snd_controls),
+       .dapm_widgets           = cs4271_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(cs4271_dapm_widgets),
+       .dapm_routes            = cs4271_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(cs4271_dapm_routes),
 };
 
 #if defined(CONFIG_SPI_MASTER)
index 987f728..be2ba1b 100644 (file)
@@ -195,6 +195,8 @@ static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0);
 
 static DECLARE_TLV_DB_SCALE(mix_tlv, -50, 50, 0);
 
+static DECLARE_TLV_DB_SCALE(beep_tlv, -56, 200, 0);
+
 static const unsigned int limiter_tlv[] = {
        TLV_DB_RANGE_HEAD(2),
        0, 2, TLV_DB_SCALE_ITEM(-3000, 600, 0),
@@ -451,7 +453,8 @@ static const struct snd_kcontrol_new cs42l52_snd_controls[] = {
        SOC_ENUM("Beep Pitch", beep_pitch_enum),
        SOC_ENUM("Beep on Time", beep_ontime_enum),
        SOC_ENUM("Beep off Time", beep_offtime_enum),
-       SOC_SINGLE_TLV("Beep Volume", CS42L52_BEEP_VOL, 0, 0x1f, 0x07, hl_tlv),
+       SOC_SINGLE_SX_TLV("Beep Volume", CS42L52_BEEP_VOL,
+                       0, 0x07, 0x1f, beep_tlv),
        SOC_SINGLE("Beep Mixer Switch", CS42L52_BEEP_TONE_CTL, 5, 1, 1),
        SOC_ENUM("Beep Treble Corner Freq", beep_treble_enum),
        SOC_ENUM("Beep Bass Corner Freq", beep_bass_enum),
index 2bcae2b..68342b1 100644 (file)
 
 #define DRV_NAME "hdmi-audio-codec"
 
-static struct snd_soc_codec_driver hdmi_codec;
+static const struct snd_soc_dapm_widget hdmi_widgets[] = {
+       SND_SOC_DAPM_INPUT("RX"),
+       SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route hdmi_routes[] = {
+       { "Capture", NULL, "RX" },
+       { "TX", NULL, "Playback" },
+};
 
 static struct snd_soc_dai_driver hdmi_codec_dai = {
        .name = "hdmi-hifi",
        .playback = {
+               .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 8,
                .rates = SNDRV_PCM_RATE_32000 |
@@ -37,6 +46,25 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE |
                        SNDRV_PCM_FMTBIT_S24_LE,
        },
+       .capture = {
+               .stream_name = "Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_32000 |
+                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+                       SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                       SNDRV_PCM_FMTBIT_S24_LE,
+       },
+
+};
+
+static struct snd_soc_codec_driver hdmi_codec = {
+       .dapm_widgets = hdmi_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
+       .dapm_routes = hdmi_routes,
+       .num_dapm_routes = ARRAY_SIZE(hdmi_routes),
 };
 
 static int hdmi_codec_probe(struct platform_device *pdev)
index 9f9f595..0e5743e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 
 #include <sound/core.h>
 #include <sound/tlv.h>
 
 struct lm4857 {
-       struct i2c_client *i2c;
+       struct regmap *regmap;
        uint8_t mode;
 };
 
-static const uint8_t lm4857_default_regs[] = {
-       0x00, 0x00, 0x00, 0x00,
+static const struct reg_default lm4857_default_regs[] = {
+       { 0x0, 0x00 },
+       { 0x1, 0x00 },
+       { 0x2, 0x00 },
+       { 0x3, 0x00 },
 };
 
 /* The register offsets in the cache array */
@@ -42,39 +46,6 @@ static const uint8_t lm4857_default_regs[] = {
 #define LM4857_WAKEUP 5
 #define LM4857_EPGAIN 4
 
-static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg,
-               unsigned int value)
-{
-       uint8_t data;
-       int ret;
-
-       ret = snd_soc_cache_write(codec, reg, value);
-       if (ret < 0)
-               return ret;
-
-       data = (reg << 6) | value;
-       ret = i2c_master_send(codec->control_data, &data, 1);
-       if (ret != 1) {
-               dev_err(codec->dev, "Failed to write register: %d\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-static unsigned int lm4857_read(struct snd_soc_codec *codec,
-               unsigned int reg)
-{
-       unsigned int val;
-       int ret;
-
-       ret = snd_soc_cache_read(codec, reg, &val);
-       if (ret)
-               return -1;
-
-       return val;
-}
-
 static int lm4857_get_mode(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -96,7 +67,7 @@ static int lm4857_set_mode(struct snd_kcontrol *kcontrol,
        lm4857->mode = value;
 
        if (codec->dapm.bias_level == SND_SOC_BIAS_ON)
-               snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6);
+               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, value + 6);
 
        return 1;
 }
@@ -108,10 +79,11 @@ static int lm4857_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6);
+               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F,
+                       lm4857->mode + 6);
                break;
        case SND_SOC_BIAS_STANDBY:
-               snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0);
+               regmap_update_bits(lm4857->regmap, LM4857_CTRL, 0x0F, 0);
                break;
        default:
                break;
@@ -171,49 +143,32 @@ static const struct snd_soc_dapm_route lm4857_routes[] = {
        {"EP", NULL, "IN"},
 };
 
-static int lm4857_probe(struct snd_soc_codec *codec)
-{
-       struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec);
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
-
-       codec->control_data = lm4857->i2c;
-
-       ret = snd_soc_add_codec_controls(codec, lm4857_controls,
-                       ARRAY_SIZE(lm4857_controls));
-       if (ret)
-               return ret;
-
-       ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets,
-                       ARRAY_SIZE(lm4857_dapm_widgets));
-       if (ret)
-               return ret;
+static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
+       .set_bias_level = lm4857_set_bias_level,
 
-       ret = snd_soc_dapm_add_routes(dapm, lm4857_routes,
-                       ARRAY_SIZE(lm4857_routes));
-       if (ret)
-               return ret;
+       .controls = lm4857_controls,
+       .num_controls = ARRAY_SIZE(lm4857_controls),
+       .dapm_widgets = lm4857_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(lm4857_dapm_widgets),
+       .dapm_routes = lm4857_routes,
+       .num_dapm_routes = ARRAY_SIZE(lm4857_routes),
+};
 
-       snd_soc_dapm_new_widgets(dapm);
+static const struct regmap_config lm4857_regmap_config = {
+       .val_bits = 6,
+       .reg_bits = 2,
 
-       return 0;
-}
+       .max_register = LM4857_CTRL,
 
-static struct snd_soc_codec_driver soc_codec_dev_lm4857 = {
-       .write = lm4857_write,
-       .read = lm4857_read,
-       .probe = lm4857_probe,
-       .reg_cache_size = ARRAY_SIZE(lm4857_default_regs),
-       .reg_word_size = sizeof(uint8_t),
-       .reg_cache_default = lm4857_default_regs,
-       .set_bias_level = lm4857_set_bias_level,
+       .cache_type = REGCACHE_FLAT,
+       .reg_defaults = lm4857_default_regs,
+       .num_reg_defaults = ARRAY_SIZE(lm4857_default_regs),
 };
 
 static int lm4857_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct lm4857 *lm4857;
-       int ret;
 
        lm4857 = devm_kzalloc(&i2c->dev, sizeof(*lm4857), GFP_KERNEL);
        if (!lm4857)
@@ -221,11 +176,11 @@ static int lm4857_i2c_probe(struct i2c_client *i2c,
 
        i2c_set_clientdata(i2c, lm4857);
 
-       lm4857->i2c = i2c;
-
-       ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
+       lm4857->regmap = devm_regmap_init_i2c(i2c, &lm4857_regmap_config);
+       if (IS_ERR(lm4857->regmap))
+               return PTR_ERR(lm4857->regmap);
 
-       return ret;
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0);
 }
 
 static int lm4857_i2c_remove(struct i2c_client *i2c)
index a6ac231..31f9156 100644 (file)
@@ -118,6 +118,18 @@ static const struct snd_kcontrol_new max9768_mute[] = {
        SOC_SINGLE_BOOL_EXT("Playback Switch", 0, max9768_get_gpio, max9768_set_gpio),
 };
 
+static const struct snd_soc_dapm_widget max9768_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("IN"),
+
+SND_SOC_DAPM_OUTPUT("OUT+"),
+SND_SOC_DAPM_OUTPUT("OUT-"),
+};
+
+static const struct snd_soc_dapm_route max9768_dapm_routes[] = {
+       { "OUT+", NULL, "IN" },
+       { "OUT-", NULL, "IN" },
+};
+
 static int max9768_probe(struct snd_soc_codec *codec)
 {
        struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec);
@@ -148,6 +160,10 @@ static struct snd_soc_codec_driver max9768_codec_driver = {
        .probe = max9768_probe,
        .controls = max9768_volume,
        .num_controls = ARRAY_SIZE(max9768_volume),
+       .dapm_widgets = max9768_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max9768_dapm_widgets),
+       .dapm_routes = max9768_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(max9768_dapm_routes),
 };
 
 static const struct regmap_config max9768_i2c_regmap_config = {
index ad5313f..0569a4c 100644 (file)
@@ -2084,8 +2084,9 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
 
                pm_wakeup_event(codec->dev, 100);
 
-               schedule_delayed_work(&max98090->jack_work,
-                       msecs_to_jiffies(100));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &max98090->jack_work,
+                                  msecs_to_jiffies(100));
        }
 
        if (active & M98090_DRCACT_MASK)
@@ -2132,8 +2133,9 @@ int max98090_mic_detect(struct snd_soc_codec *codec,
        snd_soc_jack_report(max98090->jack, 0,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
 
-       schedule_delayed_work(&max98090->jack_work,
-               msecs_to_jiffies(100));
+       queue_delayed_work(system_power_efficient_wq,
+                          &max98090->jack_work,
+                          msecs_to_jiffies(100));
 
        return 0;
 }
index 6b6c74c..29549cd 100644 (file)
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/i2c.h>
+#include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 
 #include "max9877.h"
 
-static struct i2c_client *i2c;
+static struct regmap *regmap;
 
-static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 };
-
-static void max9877_write_regs(void)
-{
-       unsigned int i;
-       u8 data[6];
-
-       data[0] = MAX9877_INPUT_MODE;
-       for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
-               data[i + 1] = max9877_regs[i];
-
-       if (i2c_master_send(i2c, data, 6) != 6)
-               dev_err(&i2c->dev, "i2c write failed\n");
-}
-
-static int max9877_get_reg(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
-       unsigned int shift = mc->shift;
-       unsigned int mask = mc->max;
-       unsigned int invert = mc->invert;
-
-       ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
-
-       if (invert)
-               ucontrol->value.integer.value[0] =
-                       mask - ucontrol->value.integer.value[0];
-
-       return 0;
-}
-
-static int max9877_set_reg(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
-       unsigned int shift = mc->shift;
-       unsigned int mask = mc->max;
-       unsigned int invert = mc->invert;
-       unsigned int val = (ucontrol->value.integer.value[0] & mask);
-
-       if (invert)
-               val = mask - val;
-
-       if (((max9877_regs[reg] >> shift) & mask) == val)
-               return 0;
-
-       max9877_regs[reg] &= ~(mask << shift);
-       max9877_regs[reg] |= val << shift;
-       max9877_write_regs();
-
-       return 1;
-}
-
-static int max9877_get_2reg(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
-       unsigned int reg2 = mc->rreg;
-       unsigned int shift = mc->shift;
-       unsigned int mask = mc->max;
-
-       ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask;
-       ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask;
-
-       return 0;
-}
-
-static int max9877_set_2reg(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       unsigned int reg = mc->reg;
-       unsigned int reg2 = mc->rreg;
-       unsigned int shift = mc->shift;
-       unsigned int mask = mc->max;
-       unsigned int val = (ucontrol->value.integer.value[0] & mask);
-       unsigned int val2 = (ucontrol->value.integer.value[1] & mask);
-       unsigned int change = 0;
-
-       if (((max9877_regs[reg] >> shift) & mask) != val)
-               change = 1;
-
-       if (((max9877_regs[reg2] >> shift) & mask) != val2)
-               change = 1;
-
-       if (change) {
-               max9877_regs[reg] &= ~(mask << shift);
-               max9877_regs[reg] |= val << shift;
-               max9877_regs[reg2] &= ~(mask << shift);
-               max9877_regs[reg2] |= val2 << shift;
-               max9877_write_regs();
-       }
-
-       return change;
-}
-
-static int max9877_get_out_mode(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK;
-
-       if (value)
-               value -= 1;
-
-       ucontrol->value.integer.value[0] = value;
-       return 0;
-}
-
-static int max9877_set_out_mode(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       u8 value = ucontrol->value.integer.value[0];
-
-       value += 1;
-
-       if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value)
-               return 0;
-
-       max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK;
-       max9877_regs[MAX9877_OUTPUT_MODE] |= value;
-       max9877_write_regs();
-       return 1;
-}
-
-static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK);
-
-       value = value >> MAX9877_OSC_OFFSET;
-
-       ucontrol->value.integer.value[0] = value;
-       return 0;
-}
-
-static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       u8 value = ucontrol->value.integer.value[0];
-
-       value = value << MAX9877_OSC_OFFSET;
-       if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value)
-               return 0;
-
-       max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK;
-       max9877_regs[MAX9877_OUTPUT_MODE] |= value;
-       max9877_write_regs();
-       return 1;
-}
+static struct reg_default max9877_regs[] = {
+       { 0, 0x40 },
+       { 1, 0x00 },
+       { 2, 0x00 },
+       { 3, 0x00 },
+       { 4, 0x49 },
+};
 
 static const unsigned int max9877_pgain_tlv[] = {
        TLV_DB_RANGE_HEAD(2),
@@ -212,65 +63,104 @@ static const char *max9877_osc_mode[] = {
 };
 
 static const struct soc_enum max9877_enum[] = {
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode),
-       SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
+       SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode),
+                       max9877_out_mode),
+       SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET,
+                       ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode),
 };
 
 static const struct snd_kcontrol_new max9877_controls[] = {
-       SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume",
-                       MAX9877_INPUT_MODE, 0, 2, 0,
-                       max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
-       SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume",
-                       MAX9877_INPUT_MODE, 2, 2, 0,
-                       max9877_get_reg, max9877_set_reg, max9877_pgain_tlv),
-       SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume",
-                       MAX9877_SPK_VOLUME, 0, 31, 0,
-                       max9877_get_reg, max9877_set_reg, max9877_output_tlv),
-       SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume",
-                       MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
-                       max9877_get_2reg, max9877_set_2reg, max9877_output_tlv),
-       SOC_SINGLE_EXT("MAX9877 INB Stereo Switch",
-                       MAX9877_INPUT_MODE, 4, 1, 1,
-                       max9877_get_reg, max9877_set_reg),
-       SOC_SINGLE_EXT("MAX9877 INA Stereo Switch",
-                       MAX9877_INPUT_MODE, 5, 1, 1,
-                       max9877_get_reg, max9877_set_reg),
-       SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch",
-                       MAX9877_INPUT_MODE, 6, 1, 0,
-                       max9877_get_reg, max9877_set_reg),
-       SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch",
-                       MAX9877_OUTPUT_MODE, 6, 1, 0,
-                       max9877_get_reg, max9877_set_reg),
-       SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch",
-                       MAX9877_OUTPUT_MODE, 7, 1, 1,
-                       max9877_get_reg, max9877_set_reg),
-       SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0],
-                       max9877_get_out_mode, max9877_set_out_mode),
-       SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1],
-                       max9877_get_osc_mode, max9877_set_osc_mode),
+       SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume",
+                      MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv),
+       SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume",
+                      MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv),
+       SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume",
+                      MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv),
+       SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume",
+                        MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0,
+                        max9877_output_tlv),
+       SOC_SINGLE("MAX9877 INB Stereo Switch",
+                  MAX9877_INPUT_MODE, 4, 1, 1),
+       SOC_SINGLE("MAX9877 INA Stereo Switch",
+                  MAX9877_INPUT_MODE, 5, 1, 1),
+       SOC_SINGLE("MAX9877 Zero-crossing detection Switch",
+                  MAX9877_INPUT_MODE, 6, 1, 0),
+       SOC_SINGLE("MAX9877 Bypass Mode Switch",
+                  MAX9877_OUTPUT_MODE, 6, 1, 0),
+       SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]),
+       SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]),
 };
 
-/* This function is called from ASoC machine driver */
-int max9877_add_controls(struct snd_soc_codec *codec)
-{
-       return snd_soc_add_codec_controls(codec, max9877_controls,
-                       ARRAY_SIZE(max9877_controls));
-}
-EXPORT_SYMBOL_GPL(max9877_add_controls);
+static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("INA1"),
+SND_SOC_DAPM_INPUT("INA2"),
+SND_SOC_DAPM_INPUT("INB1"),
+SND_SOC_DAPM_INPUT("INB2"),
+SND_SOC_DAPM_INPUT("RXIN+"),
+SND_SOC_DAPM_INPUT("RXIN-"),
+
+SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0),
+
+SND_SOC_DAPM_OUTPUT("OUT+"),
+SND_SOC_DAPM_OUTPUT("OUT-"),
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route max9877_dapm_routes[] = {
+       { "SHDN", NULL, "INA1" },
+       { "SHDN", NULL, "INA2" },
+       { "SHDN", NULL, "INB1" },
+       { "SHDN", NULL, "INB2" },
+
+       { "OUT+", NULL, "RXIN+" },
+       { "OUT+", NULL, "SHDN" },
+
+       { "OUT-", NULL, "SHDN" },
+       { "OUT-", NULL, "RXIN-" },
+
+       { "HPL", NULL, "SHDN" },
+       { "HPR", NULL, "SHDN" },
+};
+
+static const struct snd_soc_codec_driver max9877_codec = {
+       .controls = max9877_controls,
+       .num_controls = ARRAY_SIZE(max9877_controls),
+
+       .dapm_widgets = max9877_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets),
+       .dapm_routes = max9877_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes),
+};
+
+static const struct regmap_config max9877_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .reg_defaults = max9877_regs,
+       .num_reg_defaults = ARRAY_SIZE(max9877_regs),
+       .cache_type = REGCACHE_RBTREE,
+};
 
 static int max9877_i2c_probe(struct i2c_client *client,
                             const struct i2c_device_id *id)
 {
-       i2c = client;
+       int i;
 
-       max9877_write_regs();
+       regmap = devm_regmap_init_i2c(client, &max9877_regmap);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
 
-       return 0;
+       /* Ensure the device is in reset state */
+       for (i = 0; i < ARRAY_SIZE(max9877_regs); i++)
+               regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def);
+
+       return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0);
 }
 
 static int max9877_i2c_remove(struct i2c_client *client)
 {
-       i2c = NULL;
+       snd_soc_unregister_codec(&client->dev);
 
        return 0;
 }
index 5402dfb..4d3c8fd 100644 (file)
@@ -94,7 +94,6 @@
 #define AUDIO_DAC_CFS_DLY_B            (1 << 10)
 
 struct mc13783_priv {
-       struct snd_soc_codec codec;
        struct mc13xxx *mc13xxx;
 
        enum mc13783_ssi_port adc_ssi_port;
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c
new file mode 100644 (file)
index 0000000..651ce09
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * PCM1681 ASoC codec driver
+ *
+ * Copyright (c) StreamUnlimited GmbH 2013
+ *     Marek Belisko <marek.belisko@streamunlimited.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
+#define PCM1681_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |                \
+                            SNDRV_PCM_FMTBIT_S24_LE)
+
+#define PCM1681_PCM_RATES   (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
+                            SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  | \
+                            SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  | \
+                            SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define PCM1681_SOFT_MUTE_ALL          0xff
+#define PCM1681_DEEMPH_RATE_MASK       0x18
+#define PCM1681_DEEMPH_MASK            0x01
+
+#define PCM1681_ATT_CONTROL(X) (X <= 6 ? X : X + 9) /* Attenuation level */
+#define PCM1681_SOFT_MUTE      0x07    /* Soft mute control register */
+#define PCM1681_DAC_CONTROL    0x08    /* DAC operation control */
+#define PCM1681_FMT_CONTROL    0x09    /* Audio interface data format */
+#define PCM1681_DEEMPH_CONTROL 0x0a    /* De-emphasis control */
+#define PCM1681_ZERO_DETECT_STATUS     0x0e    /* Zero detect status reg */
+
+static const struct reg_default pcm1681_reg_defaults[] = {
+       { 0x01, 0xff },
+       { 0x02, 0xff },
+       { 0x03, 0xff },
+       { 0x04, 0xff },
+       { 0x05, 0xff },
+       { 0x06, 0xff },
+       { 0x07, 0x00 },
+       { 0x08, 0x00 },
+       { 0x09, 0x06 },
+       { 0x0A, 0x00 },
+       { 0x0B, 0xff },
+       { 0x0C, 0x0f },
+       { 0x0D, 0x00 },
+       { 0x10, 0xff },
+       { 0x11, 0xff },
+       { 0x12, 0x00 },
+       { 0x13, 0x00 },
+};
+
+static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg)
+{
+       return !((reg == 0x00) || (reg == 0x0f));
+}
+
+static bool pcm1681_writeable_reg(struct device *dev, unsigned register reg)
+{
+       return pcm1681_accessible_reg(dev, reg) &&
+               (reg != PCM1681_ZERO_DETECT_STATUS);
+}
+
+struct pcm1681_private {
+       struct regmap *regmap;
+       unsigned int format;
+       /* Current deemphasis status */
+       unsigned int deemph;
+       /* Current rate for deemphasis control */
+       unsigned int rate;
+};
+
+static const int pcm1681_deemph[] = { 44100, 48000, 32000 };
+
+static int pcm1681_set_deemph(struct snd_soc_codec *codec)
+{
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+       int i = 0, val = -1, enable = 0;
+
+       if (priv->deemph)
+               for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++)
+                       if (pcm1681_deemph[i] == priv->rate)
+                               val = i;
+
+       if (val != -1) {
+               regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+                                       PCM1681_DEEMPH_RATE_MASK, val);
+               enable = 1;
+       } else
+               enable = 0;
+
+       /* enable/disable deemphasis functionality */
+       return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL,
+                                       PCM1681_DEEMPH_MASK, enable);
+}
+
+static int pcm1681_get_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = priv->deemph;
+
+       return 0;
+}
+
+static int pcm1681_put_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->deemph = ucontrol->value.enumerated.item[0];
+
+       return pcm1681_set_deemph(codec);
+}
+
+static int pcm1681_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       /* The PCM1681 can only be slave to all clocks */
+       if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
+               dev_err(codec->dev, "Invalid clocking mode\n");
+               return -EINVAL;
+       }
+
+       priv->format = format;
+
+       return 0;
+}
+
+static int pcm1681_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val;
+
+       if (mute)
+               val = PCM1681_SOFT_MUTE_ALL;
+       else
+               val = 0;
+
+       return regmap_write(priv->regmap, PCM1681_SOFT_MUTE, val);
+}
+
+static int pcm1681_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val = 0, ret;
+       int pcm_format = params_format(params);
+
+       priv->rate = params_rate(params);
+
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE)
+                       val = 0x00;
+               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+                       val = 0x03;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val = 0x04;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = 0x05;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->regmap, PCM1681_FMT_CONTROL, 0x0f, val);
+       if (ret < 0)
+               return ret;
+
+       return pcm1681_set_deemph(codec);
+}
+
+static const struct snd_soc_dai_ops pcm1681_dai_ops = {
+       .set_fmt        = pcm1681_set_dai_fmt,
+       .hw_params      = pcm1681_hw_params,
+       .digital_mute   = pcm1681_digital_mute,
+};
+
+static const struct snd_soc_dapm_widget pcm1681_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("VOUT1"),
+SND_SOC_DAPM_OUTPUT("VOUT2"),
+SND_SOC_DAPM_OUTPUT("VOUT3"),
+SND_SOC_DAPM_OUTPUT("VOUT4"),
+SND_SOC_DAPM_OUTPUT("VOUT5"),
+SND_SOC_DAPM_OUTPUT("VOUT6"),
+SND_SOC_DAPM_OUTPUT("VOUT7"),
+SND_SOC_DAPM_OUTPUT("VOUT8"),
+};
+
+static const struct snd_soc_dapm_route pcm1681_dapm_routes[] = {
+       { "VOUT1", NULL, "Playback" },
+       { "VOUT2", NULL, "Playback" },
+       { "VOUT3", NULL, "Playback" },
+       { "VOUT4", NULL, "Playback" },
+       { "VOUT5", NULL, "Playback" },
+       { "VOUT6", NULL, "Playback" },
+       { "VOUT7", NULL, "Playback" },
+       { "VOUT8", NULL, "Playback" },
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1681_dac_tlv, -6350, 50, 1);
+
+static const struct snd_kcontrol_new pcm1681_controls[] = {
+       SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+                       PCM1681_ATT_CONTROL(1), PCM1681_ATT_CONTROL(2), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+                       PCM1681_ATT_CONTROL(3), PCM1681_ATT_CONTROL(4), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+                       PCM1681_ATT_CONTROL(5), PCM1681_ATT_CONTROL(6), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 7/8 Playback Volume",
+                       PCM1681_ATT_CONTROL(7), PCM1681_ATT_CONTROL(8), 0,
+                       0x7f, 0, pcm1681_dac_tlv),
+       SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+                           pcm1681_get_deemph, pcm1681_put_deemph),
+};
+
+static struct snd_soc_dai_driver pcm1681_dai = {
+       .name = "pcm1681-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 8,
+               .rates = PCM1681_PCM_RATES,
+               .formats = PCM1681_PCM_FORMATS,
+       },
+       .ops = &pcm1681_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pcm1681_dt_ids[] = {
+       { .compatible = "ti,pcm1681", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm1681_dt_ids);
+#endif
+
+static const struct regmap_config pcm1681_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = ARRAY_SIZE(pcm1681_reg_defaults) + 1,
+       .reg_defaults           = pcm1681_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(pcm1681_reg_defaults),
+       .writeable_reg          = pcm1681_writeable_reg,
+       .readable_reg           = pcm1681_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1681 = {
+       .controls               = pcm1681_controls,
+       .num_controls           = ARRAY_SIZE(pcm1681_controls),
+       .dapm_widgets           = pcm1681_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(pcm1681_dapm_widgets),
+       .dapm_routes            = pcm1681_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(pcm1681_dapm_routes),
+};
+
+static const struct i2c_device_id pcm1681_i2c_id[] = {
+       {"pcm1681", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, pcm1681_i2c_id);
+
+static int pcm1681_i2c_probe(struct i2c_client *client,
+                             const struct i2c_device_id *id)
+{
+       int ret;
+       struct pcm1681_private *priv;
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = devm_regmap_init_i2c(client, &pcm1681_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&client->dev, "Failed to create regmap: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, priv);
+
+       return snd_soc_register_codec(&client->dev, &soc_codec_dev_pcm1681,
+               &pcm1681_dai, 1);
+}
+
+static int pcm1681_i2c_remove(struct i2c_client *client)
+{
+       snd_soc_unregister_codec(&client->dev);
+       return 0;
+}
+
+static struct i2c_driver pcm1681_i2c_driver = {
+       .driver = {
+               .name   = "pcm1681",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pcm1681_dt_ids),
+       },
+       .id_table       = pcm1681_i2c_id,
+       .probe          = pcm1681_i2c_probe,
+       .remove         = pcm1681_i2c_remove,
+};
+
+module_i2c_driver(pcm1681_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments PCM1681 ALSA SoC Codec Driver");
+MODULE_AUTHOR("Marek Belisko <marek.belisko@streamunlimited.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c
new file mode 100644 (file)
index 0000000..2a8eccf
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * PCM1792A ASoC codec driver
+ *
+ * Copyright (c) Amarula Solutions B.V. 2013
+ *
+ *     Michael Trimarchi <michael@amarulasolutions.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <linux/of_device.h>
+
+#include "pcm1792a.h"
+
+#define PCM1792A_DAC_VOL_LEFT  0x10
+#define PCM1792A_DAC_VOL_RIGHT 0x11
+#define PCM1792A_FMT_CONTROL   0x12
+#define PCM1792A_SOFT_MUTE     PCM1792A_FMT_CONTROL
+
+#define PCM1792A_FMT_MASK      0x70
+#define PCM1792A_FMT_SHIFT     4
+#define PCM1792A_MUTE_MASK     0x01
+#define PCM1792A_MUTE_SHIFT    0
+#define PCM1792A_ATLD_ENABLE   (1 << 7)
+
+static const struct reg_default pcm1792a_reg_defaults[] = {
+       { 0x10, 0xff },
+       { 0x11, 0xff },
+       { 0x12, 0x50 },
+       { 0x13, 0x00 },
+       { 0x14, 0x00 },
+       { 0x15, 0x01 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+};
+
+static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg)
+{
+       return reg >= 0x10 && reg <= 0x17;
+}
+
+static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg)
+{
+       bool accessible;
+
+       accessible = pcm1792a_accessible_reg(dev, reg);
+
+       return accessible && reg != 0x16 && reg != 0x17;
+}
+
+struct pcm1792a_private {
+       struct regmap *regmap;
+       unsigned int format;
+       unsigned int rate;
+};
+
+static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->format = format;
+
+       return 0;
+}
+
+static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE,
+                                PCM1792A_MUTE_MASK, !!mute);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int pcm1792a_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val = 0, ret;
+       int pcm_format = params_format(params);
+
+       priv->rate = params_rate(params);
+
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
+                   pcm_format == SNDRV_PCM_FORMAT_S32_LE)
+                       val = 0x02;
+               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+                       val = 0x00;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               if (pcm_format == SNDRV_PCM_FORMAT_S24_LE ||
+                   pcm_format == SNDRV_PCM_FORMAT_S32_LE)
+                       val = 0x05;
+               else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE)
+                       val = 0x04;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE;
+
+       ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL,
+                                PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops pcm1792a_dai_ops = {
+       .set_fmt        = pcm1792a_set_dai_fmt,
+       .hw_params      = pcm1792a_hw_params,
+       .digital_mute   = pcm1792a_digital_mute,
+};
+
+static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1);
+
+static const struct snd_kcontrol_new pcm1792a_controls[] = {
+       SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT,
+                        PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0,
+                        pcm1792a_dac_tlv),
+};
+
+static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("IOUTL+"),
+SND_SOC_DAPM_OUTPUT("IOUTL-"),
+SND_SOC_DAPM_OUTPUT("IOUTR+"),
+SND_SOC_DAPM_OUTPUT("IOUTR-"),
+};
+
+static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = {
+       { "IOUTL+", NULL, "Playback" },
+       { "IOUTL-", NULL, "Playback" },
+       { "IOUTR+", NULL, "Playback" },
+       { "IOUTR-", NULL, "Playback" },
+};
+
+static struct snd_soc_dai_driver pcm1792a_dai = {
+       .name = "pcm1792a-hifi",
+       .playback = {
+               .stream_name = "Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = PCM1792A_RATES,
+               .formats = PCM1792A_FORMATS, },
+       .ops = &pcm1792a_dai_ops,
+};
+
+static const struct of_device_id pcm1792a_of_match[] = {
+       { .compatible = "ti,pcm1792a", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pcm1792a_of_match);
+
+static const struct regmap_config pcm1792a_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = 24,
+       .reg_defaults           = pcm1792a_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(pcm1792a_reg_defaults),
+       .writeable_reg          = pcm1792a_writeable_reg,
+       .readable_reg           = pcm1792a_accessible_reg,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = {
+       .controls               = pcm1792a_controls,
+       .num_controls           = ARRAY_SIZE(pcm1792a_controls),
+       .dapm_widgets           = pcm1792a_dapm_widgets,
+       .num_dapm_widgets       = ARRAY_SIZE(pcm1792a_dapm_widgets),
+       .dapm_routes            = pcm1792a_dapm_routes,
+       .num_dapm_routes        = ARRAY_SIZE(pcm1792a_dapm_routes),
+};
+
+static int pcm1792a_spi_probe(struct spi_device *spi)
+{
+       struct pcm1792a_private *pcm1792a;
+       int ret;
+
+       pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private),
+                               GFP_KERNEL);
+       if (!pcm1792a)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, pcm1792a);
+
+       pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap);
+       if (IS_ERR(pcm1792a->regmap)) {
+               ret = PTR_ERR(pcm1792a->regmap);
+               dev_err(&spi->dev, "Failed to register regmap: %d\n", ret);
+               return ret;
+       }
+
+       return snd_soc_register_codec(&spi->dev,
+                       &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1);
+}
+
+static int pcm1792a_spi_remove(struct spi_device *spi)
+{
+       snd_soc_unregister_codec(&spi->dev);
+       return 0;
+}
+
+static const struct spi_device_id pcm1792a_spi_ids[] = {
+       { "pcm1792a", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids);
+
+static struct spi_driver pcm1792a_codec_driver = {
+       .driver = {
+               .name = "pcm1792a",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(pcm1792a_of_match),
+       },
+       .id_table = pcm1792a_spi_ids,
+       .probe = pcm1792a_spi_probe,
+       .remove = pcm1792a_spi_remove,
+};
+
+module_spi_driver(pcm1792a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM1792A driver");
+MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm1792a.h
new file mode 100644 (file)
index 0000000..7a83d1f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * definitions for PCM1792A
+ *
+ * Copyright 2013 Amarula Solutions
+ *
+  * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __PCM1792A_H__
+#define __PCM1792A_H__
+
+#define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \
+                       SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define PCM1792A_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | \
+                         SNDRV_PCM_FMTBIT_S16_LE)
+
+#endif
index f2a6282..b6618c4 100644 (file)
 
 #include "pcm3008.h"
 
-#define PCM3008_VERSION "0.2"
+static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
+
+       gpio_set_value_cansleep(setup->pdda_pin,
+                               SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
+                         struct snd_kcontrol *kcontrol,
+                         int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct pcm3008_setup_data *setup = codec->dev->platform_data;
+
+       gpio_set_value_cansleep(setup->pdad_pin,
+                               SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static const struct snd_soc_dapm_widget pcm3008_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("VINL"),
+SND_SOC_DAPM_INPUT("VINR"),
+
+SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_dac_ev,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, pcm3008_adc_ev,
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+SND_SOC_DAPM_OUTPUT("VOUTL"),
+SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route pcm3008_dapm_routes[] = {
+       { "PCM3008 Capture", NULL, "ADC" },
+       { "ADC", NULL, "VINL" },
+       { "ADC", NULL, "VINR" },
+
+       { "DAC", NULL, "PCM3008 Playback" },
+       { "VOUTL", NULL, "DAC" },
+       { "VOUTR", NULL, "DAC" },
+};
 
 #define PCM3008_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |   \
                       SNDRV_PCM_RATE_48000)
@@ -51,20 +98,20 @@ static struct snd_soc_dai_driver pcm3008_dai = {
        },
 };
 
-static void pcm3008_gpio_free(struct pcm3008_setup_data *setup)
-{
-       gpio_free(setup->dem0_pin);
-       gpio_free(setup->dem1_pin);
-       gpio_free(setup->pdad_pin);
-       gpio_free(setup->pdda_pin);
-}
+static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
+       .dapm_widgets = pcm3008_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(pcm3008_dapm_widgets),
+       .dapm_routes = pcm3008_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(pcm3008_dapm_routes),
+};
 
-static int pcm3008_soc_probe(struct snd_soc_codec *codec)
+static int pcm3008_codec_probe(struct platform_device *pdev)
 {
-       struct pcm3008_setup_data *setup = codec->dev->platform_data;
-       int ret = 0;
+       struct pcm3008_setup_data *setup = pdev->dev.platform_data;
+       int ret;
 
-       printk(KERN_INFO "PCM3008 SoC Audio Codec %s\n", PCM3008_VERSION);
+       if (!setup)
+               return -EINVAL;
 
        /* DEM1  DEM0  DE-EMPHASIS_MODE
         * Low   Low   De-emphasis 44.1 kHz ON
@@ -74,83 +121,29 @@ static int pcm3008_soc_probe(struct snd_soc_codec *codec)
         */
 
        /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */
-       ret = gpio_request(setup->dem0_pin, "codec_dem0");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->dem0_pin, 1);
+       ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin,
+                                   GPIOF_OUT_INIT_HIGH, "codec_dem0");
        if (ret != 0)
-               goto gpio_err;
+               return ret;
 
        /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */
-       ret = gpio_request(setup->dem1_pin, "codec_dem1");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->dem1_pin, 0);
+       ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin,
+                                   GPIOF_OUT_INIT_LOW, "codec_dem1");
        if (ret != 0)
-               goto gpio_err;
+               return ret;
 
        /* Configure PDAD GPIO. */
-       ret = gpio_request(setup->pdad_pin, "codec_pdad");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->pdad_pin, 1);
+       ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin,
+                                   GPIOF_OUT_INIT_LOW, "codec_pdad");
        if (ret != 0)
-               goto gpio_err;
+               return ret;
 
        /* Configure PDDA GPIO. */
-       ret = gpio_request(setup->pdda_pin, "codec_pdda");
-       if (ret == 0)
-               ret = gpio_direction_output(setup->pdda_pin, 1);
+       ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin,
+                                   GPIOF_OUT_INIT_LOW, "codec_pdda");
        if (ret != 0)
-               goto gpio_err;
-
-       return ret;
-
-gpio_err:
-       pcm3008_gpio_free(setup);
+               return ret;
 
-       return ret;
-}
-
-static int pcm3008_soc_remove(struct snd_soc_codec *codec)
-{
-       struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-       pcm3008_gpio_free(setup);
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int pcm3008_soc_suspend(struct snd_soc_codec *codec)
-{
-       struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-       gpio_set_value(setup->pdad_pin, 0);
-       gpio_set_value(setup->pdda_pin, 0);
-
-       return 0;
-}
-
-static int pcm3008_soc_resume(struct snd_soc_codec *codec)
-{
-       struct pcm3008_setup_data *setup = codec->dev->platform_data;
-
-       gpio_set_value(setup->pdad_pin, 1);
-       gpio_set_value(setup->pdda_pin, 1);
-
-       return 0;
-}
-#else
-#define pcm3008_soc_suspend NULL
-#define pcm3008_soc_resume NULL
-#endif
-
-static struct snd_soc_codec_driver soc_codec_dev_pcm3008 = {
-       .probe =        pcm3008_soc_probe,
-       .remove =       pcm3008_soc_remove,
-       .suspend =      pcm3008_soc_suspend,
-       .resume =       pcm3008_soc_resume,
-};
-
-static int pcm3008_codec_probe(struct platform_device *pdev)
-{
        return snd_soc_register_codec(&pdev->dev,
                        &soc_codec_dev_pcm3008, &pcm3008_dai, 1);
 }
@@ -158,6 +151,7 @@ static int pcm3008_codec_probe(struct platform_device *pdev)
 static int pcm3008_codec_remove(struct platform_device *pdev)
 {
        snd_soc_unregister_codec(&pdev->dev);
+
        return 0;
 }
 
index ce585e3..4db7314 100644 (file)
@@ -737,29 +737,6 @@ static const struct snd_kcontrol_new rt5640_mono_mix[] = {
                        RT5640_M_BST1_MM_SFT, 1, 1),
 };
 
-/* INL/R source */
-static const char * const rt5640_inl_src[] = {
-       "IN2P", "MONOP"
-};
-
-static const SOC_ENUM_SINGLE_DECL(
-       rt5640_inl_enum, RT5640_INL_INR_VOL,
-       RT5640_INL_SEL_SFT, rt5640_inl_src);
-
-static const struct snd_kcontrol_new rt5640_inl_mux =
-       SOC_DAPM_ENUM("INL source", rt5640_inl_enum);
-
-static const char * const rt5640_inr_src[] = {
-       "IN2N", "MONON"
-};
-
-static const SOC_ENUM_SINGLE_DECL(
-       rt5640_inr_enum, RT5640_INL_INR_VOL,
-       RT5640_INR_SEL_SFT, rt5640_inr_src);
-
-static const struct snd_kcontrol_new rt5640_inr_mux =
-       SOC_DAPM_ENUM("INR source", rt5640_inr_enum);
-
 /* Stereo ADC source */
 static const char * const rt5640_stereo_adc1_src[] = {
        "DIG MIX", "ADC"
@@ -1005,9 +982,6 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
                RT5640_PWR_IN_L_BIT, 0, NULL, 0),
        SND_SOC_DAPM_PGA("INR VOL", RT5640_PWR_VOL,
                RT5640_PWR_IN_R_BIT, 0, NULL, 0),
-       /* IN Mux */
-       SND_SOC_DAPM_MUX("INL Mux", SND_SOC_NOPM, 0, 0, &rt5640_inl_mux),
-       SND_SOC_DAPM_MUX("INR Mux", SND_SOC_NOPM, 0, 0, &rt5640_inr_mux),
        /* REC Mixer */
        SND_SOC_DAPM_MIXER("RECMIXL", RT5640_PWR_MIXER, RT5640_PWR_RM_L_BIT, 0,
                        rt5640_rec_l_mix, ARRAY_SIZE(rt5640_rec_l_mix)),
index 6c8a9e7..1f4093f 100644 (file)
@@ -153,6 +153,8 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
 static int power_vag_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
@@ -160,9 +162,17 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
-                       SGTL5000_VAG_POWERUP, 0);
-               msleep(400);
+               /*
+                * Don't clear VAG_POWERUP, when both DAC and ADC are
+                * operational to prevent inadvertently starving the
+                * other one of them.
+                */
+               if ((snd_soc_read(w->codec, SGTL5000_CHIP_ANA_POWER) &
+                               mask) != mask) {
+                       snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+                               SGTL5000_VAG_POWERUP, 0);
+                       msleep(400);
+               }
                break;
        default:
                break;
@@ -388,7 +398,7 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
        SOC_DOUBLE("Capture Volume", SGTL5000_CHIP_ANA_ADC_CTRL, 0, 4, 0xf, 0),
        SOC_SINGLE_TLV("Capture Attenuate Switch (-6dB)",
                        SGTL5000_CHIP_ANA_ADC_CTRL,
-                       8, 2, 0, capture_6db_attenuate),
+                       8, 1, 0, capture_6db_attenuate),
        SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0),
 
        SOC_DOUBLE_TLV("Headphone Playback Volume",
@@ -644,16 +654,19 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
                snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
                        SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP);
+
+               /* if using pll, clk_ctrl must be set after pll power up */
+               snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
        } else {
+               /* otherwise, clk_ctrl must be set before pll power down */
+               snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
+
                /* power down pll */
                snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP,
                        0);
        }
 
-       /* if using pll, clk_ctrl must be set after pll power up */
-       snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
-
        return 0;
 }
 
@@ -1470,6 +1483,7 @@ static struct snd_soc_codec_driver sgtl5000_driver = {
 static const struct regmap_config sgtl5000_regmap = {
        .reg_bits = 16,
        .val_bits = 16,
+       .reg_stride = 2,
 
        .max_register = SGTL5000_MAX_REG_OFFSET,
        .volatile_reg = sgtl5000_volatile,
index 73e205c..38f3b10 100644 (file)
@@ -102,6 +102,16 @@ static int si476x_codec_write(struct snd_soc_codec *codec,
        return err;
 }
 
+static const struct snd_soc_dapm_widget si476x_dapm_widgets[] = {
+SND_SOC_DAPM_OUTPUT("LOUT"),
+SND_SOC_DAPM_OUTPUT("ROUT"),
+};
+
+static const struct snd_soc_dapm_route si476x_dapm_routes[] = {
+       { "Capture", NULL, "LOUT" },
+       { "Capture", NULL, "ROUT" },
+};
+
 static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
                                    unsigned int fmt)
 {
@@ -260,6 +270,10 @@ static struct snd_soc_codec_driver soc_codec_dev_si476x = {
        .probe  = si476x_codec_probe,
        .read   = si476x_codec_read,
        .write  = si476x_codec_write,
+       .dapm_widgets = si476x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(si476x_dapm_widgets),
+       .dapm_routes = si476x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(si476x_dapm_routes),
 };
 
 static int si476x_platform_probe(struct platform_device *pdev)
index e9d7881..e3501f4 100644 (file)
 #include <sound/initval.h>
 #include <linux/of.h>
 
+static const struct snd_soc_dapm_widget dir_widgets[] = {
+       SND_SOC_DAPM_INPUT("spdif-in"),
+};
+
+static const struct snd_soc_dapm_route dir_routes[] = {
+       { "Capture", NULL, "spdif-in" },
+};
+
 #define STUB_RATES     SNDRV_PCM_RATE_8000_192000
 #define STUB_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE | \
                        SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
 
-static struct snd_soc_codec_driver soc_codec_spdif_dir;
+static struct snd_soc_codec_driver soc_codec_spdif_dir = {
+       .dapm_widgets = dir_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(dir_widgets),
+       .dapm_routes = dir_routes,
+       .num_dapm_routes = ARRAY_SIZE(dir_routes),
+};
 
 static struct snd_soc_dai_driver dir_stub_dai = {
        .name           = "dir-hifi",
index 1828049..a078aa3 100644 (file)
 #define DRV_NAME "spdif-dit"
 
 #define STUB_RATES     SNDRV_PCM_RATE_8000_96000
-#define STUB_FORMATS   SNDRV_PCM_FMTBIT_S16_LE
+#define STUB_FORMATS   (SNDRV_PCM_FMTBIT_S16_LE | \
+                       SNDRV_PCM_FMTBIT_S20_3LE | \
+                       SNDRV_PCM_FMTBIT_S24_LE)
 
+static const struct snd_soc_dapm_widget dit_widgets[] = {
+       SND_SOC_DAPM_OUTPUT("spdif-out"),
+};
+
+static const struct snd_soc_dapm_route dit_routes[] = {
+       { "spdif-out", NULL, "Playback" },
+};
 
-static struct snd_soc_codec_driver soc_codec_spdif_dit;
+static struct snd_soc_codec_driver soc_codec_spdif_dit = {
+       .dapm_widgets = dit_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(dit_widgets),
+       .dapm_routes = dit_routes,
+       .num_dapm_routes = ARRAY_SIZE(dit_routes),
+};
 
 static struct snd_soc_dai_driver dit_stub_dai = {
        .name           = "dit-hifi",
index cfb55fe..06edb39 100644 (file)
@@ -363,16 +363,18 @@ static void sta32x_watchdog(struct work_struct *work)
        }
 
        if (!sta32x->shutdown)
-               schedule_delayed_work(&sta32x->watchdog_work,
-                                     round_jiffies_relative(HZ));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &sta32x->watchdog_work,
+                                  round_jiffies_relative(HZ));
 }
 
 static void sta32x_watchdog_start(struct sta32x_priv *sta32x)
 {
        if (sta32x->pdata->needs_esd_watchdog) {
                sta32x->shutdown = 0;
-               schedule_delayed_work(&sta32x->watchdog_work,
-                                     round_jiffies_relative(HZ));
+               queue_delayed_work(system_power_efficient_wq,
+                                  &sta32x->watchdog_work,
+                                  round_jiffies_relative(HZ));
        }
 }
 
index b1f6982..7b8f3d9 100644 (file)
@@ -29,7 +29,7 @@ MODULE_LICENSE("GPL");
 /* AIC26 driver private data */
 struct aic26 {
        struct spi_device *spi;
-       struct snd_soc_codec codec;
+       struct snd_soc_codec *codec;
        int master;
        int datfm;
        int mclk;
@@ -119,6 +119,22 @@ static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
        return 0;
 }
 
+static const struct snd_soc_dapm_widget tlv320aic26_dapm_widgets[] = {
+SND_SOC_DAPM_INPUT("MICIN"),
+SND_SOC_DAPM_INPUT("AUX"),
+
+SND_SOC_DAPM_OUTPUT("HPL"),
+SND_SOC_DAPM_OUTPUT("HPR"),
+};
+
+static const struct snd_soc_dapm_route tlv320aic26_dapm_routes[] = {
+       { "Capture", NULL, "MICIN" },
+       { "Capture", NULL, "AUX" },
+
+       { "HPL", NULL, "Playback" },
+       { "HPR", NULL, "Playback" },
+};
+
 /* ---------------------------------------------------------------------
  * Digital Audio Interface Operations
  */
@@ -174,9 +190,9 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(&aic26->spi->dev, "Setting PLLM to %d.%04d\n", jval, dval);
        qval = 0;
        reg = 0x8000 | qval << 11 | pval << 8 | jval << 2;
-       aic26_reg_write(codec, AIC26_REG_PLL_PROG1, reg);
+       snd_soc_write(codec, AIC26_REG_PLL_PROG1, reg);
        reg = dval << 2;
-       aic26_reg_write(codec, AIC26_REG_PLL_PROG2, reg);
+       snd_soc_write(codec, AIC26_REG_PLL_PROG2, reg);
 
        /* Audio Control 3 (master mode, fsref rate) */
        reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL3);
@@ -185,13 +201,13 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
                reg |= 0x0800;
        if (fsref == 48000)
                reg |= 0x2000;
-       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+       snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
        /* Audio Control 1 (FSref divisor) */
        reg = aic26_reg_read_cache(codec, AIC26_REG_AUDIO_CTRL1);
        reg &= ~0x0fff;
        reg |= wlen | aic26->datfm | (divisor << 3) | divisor;
-       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
+       snd_soc_write(codec, AIC26_REG_AUDIO_CTRL1, reg);
 
        return 0;
 }
@@ -212,7 +228,7 @@ static int aic26_mute(struct snd_soc_dai *dai, int mute)
                reg |= 0x8080;
        else
                reg &= ~0x8080;
-       aic26_reg_write(codec, AIC26_REG_DAC_GAIN, reg);
+       snd_soc_write(codec, AIC26_REG_DAC_GAIN, reg);
 
        return 0;
 }
@@ -330,7 +346,7 @@ static ssize_t aic26_keyclick_show(struct device *dev,
        struct aic26 *aic26 = dev_get_drvdata(dev);
        int val, amp, freq, len;
 
-       val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+       val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
        amp = (val >> 12) & 0x7;
        freq = (125 << ((val >> 8) & 0x7)) >> 1;
        len = 2 * (1 + ((val >> 4) & 0xf));
@@ -346,9 +362,9 @@ static ssize_t aic26_keyclick_set(struct device *dev,
        struct aic26 *aic26 = dev_get_drvdata(dev);
        int val;
 
-       val = aic26_reg_read_cache(&aic26->codec, AIC26_REG_AUDIO_CTRL2);
+       val = aic26_reg_read_cache(aic26->codec, AIC26_REG_AUDIO_CTRL2);
        val |= 0x8000;
-       aic26_reg_write(&aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
+       snd_soc_write(aic26->codec, AIC26_REG_AUDIO_CTRL2, val);
 
        return count;
 }
@@ -360,25 +376,26 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
  */
 static int aic26_probe(struct snd_soc_codec *codec)
 {
+       struct aic26 *aic26 = dev_get_drvdata(codec->dev);
        int ret, err, i, reg;
 
-       dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
+       aic26->codec = codec;
 
        /* Reset the codec to power on defaults */
-       aic26_reg_write(codec, AIC26_REG_RESET, 0xBB00);
+       snd_soc_write(codec, AIC26_REG_RESET, 0xBB00);
 
        /* Power up CODEC */
-       aic26_reg_write(codec, AIC26_REG_POWER_CTRL, 0);
+       snd_soc_write(codec, AIC26_REG_POWER_CTRL, 0);
 
        /* Audio Control 3 (master mode, fsref rate) */
-       reg = aic26_reg_read(codec, AIC26_REG_AUDIO_CTRL3);
+       reg = snd_soc_read(codec, AIC26_REG_AUDIO_CTRL3);
        reg &= ~0xf800;
        reg |= 0x0800; /* set master mode */
-       aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
+       snd_soc_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
 
        /* Fill register cache */
        for (i = 0; i < codec->driver->reg_cache_size; i++)
-               aic26_reg_read(codec, i);
+               snd_soc_read(codec, i);
 
        /* Register the sysfs files for debugging */
        /* Create SysFS files */
@@ -401,6 +418,10 @@ static struct snd_soc_codec_driver aic26_soc_codec_dev = {
        .write = aic26_reg_write,
        .reg_cache_size = AIC26_NUM_REGS,
        .reg_word_size = sizeof(u16),
+       .dapm_widgets = tlv320aic26_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tlv320aic26_dapm_widgets),
+       .dapm_routes = tlv320aic26_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(tlv320aic26_dapm_routes),
 };
 
 /* ---------------------------------------------------------------------
index e5b9268..6e3f269 100644 (file)
@@ -138,8 +138,7 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = {
 static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
                                        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -147,10 +146,9 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
-       unsigned short val, val_mask;
-       int ret;
-       struct snd_soc_dapm_path *path;
-       int found = 0;
+       unsigned short val;
+       struct snd_soc_dapm_update update;
+       int connect, change;
 
        val = (ucontrol->value.integer.value[0] & mask);
 
@@ -158,42 +156,26 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
        if (val)
                val = mask;
 
+       connect = !!val;
+
        if (invert)
                val = mask - val;
-       val_mask = mask << shift;
-       val = val << shift;
-
-       mutex_lock(&widget->codec->mutex);
 
-       if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
-               /* find dapm widget path assoc with kcontrol */
-               list_for_each_entry(path, &widget->dapm->card->paths, list) {
-                       if (path->kcontrol != kcontrol)
-                               continue;
+       mask <<= shift;
+       val <<= shift;
 
-                       /* found, now check type */
-                       found = 1;
-                       if (val)
-                               /* new connection */
-                               path->connect = invert ? 0 : 1;
-                       else
-                               /* old connection must be powered down */
-                               path->connect = invert ? 1 : 0;
+       change = snd_soc_test_bits(codec, val, mask, reg);
+       if (change) {
+               update.kcontrol = kcontrol;
+               update.reg = reg;
+               update.mask = mask;
+               update.val = val;
 
-                       dapm_mark_dirty(path->source, "tlv320aic3x source");
-                       dapm_mark_dirty(path->sink, "tlv320aic3x sink");
-
-                       break;
-               }
+               snd_soc_dapm_mixer_update_power(&codec->dapm, kcontrol, connect,
+                       &update);
        }
 
-       mutex_unlock(&widget->codec->mutex);
-
-       if (found)
-               snd_soc_dapm_sync(widget->dapm);
-
-       ret = snd_soc_update_bits_locked(widget->codec, reg, val_mask, val);
-       return ret;
+       return change;
 }
 
 /*
@@ -1492,6 +1474,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
        { "tlv320aic3x", AIC3X_MODEL_3X },
        { "tlv320aic33", AIC3X_MODEL_33 },
        { "tlv320aic3007", AIC3X_MODEL_3007 },
+       { "tlv320aic3106", AIC3X_MODEL_3X },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1582,6 +1565,9 @@ static int aic3x_i2c_remove(struct i2c_client *client)
 #if defined(CONFIG_OF)
 static const struct of_device_id tlv320aic3x_of_match[] = {
        { .compatible = "ti,tlv320aic3x", },
+       { .compatible = "ti,tlv320aic33" },
+       { .compatible = "ti,tlv320aic3007" },
+       { .compatible = "ti,tlv320aic3106" },
        {},
 };
 MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
index 8e6e5b0..1e3884d 100644 (file)
@@ -137,8 +137,6 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
 
 /* codec private data */
 struct twl4030_priv {
-       struct snd_soc_codec codec;
-
        unsigned int codec_powered;
 
        /* reference counts of AIF/APLL users */
index 44621dd..3c79dbb 100644 (file)
@@ -429,7 +429,8 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
        struct snd_soc_codec *codec = data;
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
 
-       schedule_delayed_work(&priv->hs_jack.work, msecs_to_jiffies(200));
+       queue_delayed_work(system_power_efficient_wq,
+                          &priv->hs_jack.work, msecs_to_jiffies(200));
 
        return IRQ_HANDLED;
 }
@@ -437,9 +438,7 @@ static irqreturn_t twl6040_audio_handler(int irq, void *data)
 static int twl6040_soc_dapm_put_vibra_enum(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val;
 
index 6d0aa44..c94d4c1 100644 (file)
@@ -325,7 +325,6 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
-       u8 reg;
        struct uda134x_platform_data *pd = codec->control_data;
        int i;
        u8 *cache = codec->reg_cache;
@@ -334,23 +333,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
 
        switch (level) {
        case SND_SOC_BIAS_ON:
-               /* ADC, DAC on */
-               switch (pd->model) {
-               case UDA134X_UDA1340:
-               case UDA134X_UDA1344:
-               case UDA134X_UDA1345:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
-                       uda134x_write(codec, UDA134X_DATA011, reg | 0x03);
-                       break;
-               case UDA134X_UDA1341:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
-                       uda134x_write(codec, UDA134X_STATUS1, reg | 0x03);
-                       break;
-               default:
-                       printk(KERN_ERR "UDA134X SoC codec: "
-                              "unsupported model %d\n", pd->model);
-                       return -EINVAL;
-               }
                break;
        case SND_SOC_BIAS_PREPARE:
                /* power on */
@@ -362,23 +344,6 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
                }
                break;
        case SND_SOC_BIAS_STANDBY:
-               /* ADC, DAC power off */
-               switch (pd->model) {
-               case UDA134X_UDA1340:
-               case UDA134X_UDA1344:
-               case UDA134X_UDA1345:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_DATA011);
-                       uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03));
-                       break;
-               case UDA134X_UDA1341:
-                       reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1);
-                       uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03));
-                       break;
-               default:
-                       printk(KERN_ERR "UDA134X SoC codec: "
-                              "unsupported model %d\n", pd->model);
-                       return -EINVAL;
-               }
                break;
        case SND_SOC_BIAS_OFF:
                /* power off */
@@ -450,6 +415,37 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
 SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
 };
 
+/* UDA1341 has the DAC/ADC power down in STATUS1 */
+static const struct snd_soc_dapm_widget uda1341_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_STATUS1, 0, 0),
+       SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_STATUS1, 1, 0),
+};
+
+/* UDA1340/4/5 has the DAC/ADC pwoer down in DATA0 11 */
+static const struct snd_soc_dapm_widget uda1340_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("DAC", "Playback", UDA134X_DATA011, 0, 0),
+       SND_SOC_DAPM_ADC("ADC", "Capture", UDA134X_DATA011, 1, 0),
+};
+
+/* Common DAPM widgets */
+static const struct snd_soc_dapm_widget uda134x_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("VINL1"),
+       SND_SOC_DAPM_INPUT("VINR1"),
+       SND_SOC_DAPM_INPUT("VINL2"),
+       SND_SOC_DAPM_INPUT("VINR2"),
+       SND_SOC_DAPM_OUTPUT("VOUTL"),
+       SND_SOC_DAPM_OUTPUT("VOUTR"),
+};
+
+static const struct snd_soc_dapm_route uda134x_dapm_routes[] = {
+       { "ADC", NULL, "VINL1" },
+       { "ADC", NULL, "VINR1" },
+       { "ADC", NULL, "VINL2" },
+       { "ADC", NULL, "VINR2" },
+       { "VOUTL", NULL, "DAC" },
+       { "VOUTR", NULL, "DAC" },
+};
+
 static const struct snd_soc_dai_ops uda134x_dai_ops = {
        .startup        = uda134x_startup,
        .shutdown       = uda134x_shutdown,
@@ -485,6 +481,8 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
 {
        struct uda134x_priv *uda134x;
        struct uda134x_platform_data *pd = codec->card->dev->platform_data;
+       const struct snd_soc_dapm_widget *widgets;
+       unsigned num_widgets;
 
        int ret;
 
@@ -526,6 +524,22 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
        else
                uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
+       if (pd->model == UDA134X_UDA1341) {
+               widgets = uda1341_dapm_widgets;
+               num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
+       } else {
+               widgets = uda1340_dapm_widgets;
+               num_widgets = ARRAY_SIZE(uda1340_dapm_widgets);
+       }
+
+       ret = snd_soc_dapm_new_controls(&codec->dapm, widgets, num_widgets);
+       if (ret) {
+               printk(KERN_ERR "%s failed to register dapm controls: %d",
+                       __func__, ret);
+               kfree(uda134x);
+               return ret;
+       }
+
        switch (pd->model) {
        case UDA134X_UDA1340:
        case UDA134X_UDA1344:
@@ -599,6 +613,10 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
        .read = uda134x_read_reg_cache,
        .write = uda134x_write,
        .set_bias_level = uda134x_set_bias_level,
+       .dapm_widgets = uda134x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
+       .dapm_routes = uda134x_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes),
 };
 
 static int uda134x_codec_probe(struct platform_device *pdev)
index 54cd3da..b7ab2ef 100644 (file)
@@ -290,6 +290,18 @@ static const struct snd_kcontrol_new wl1273_controls[] = {
                       snd_wl1273_fm_volume_get, snd_wl1273_fm_volume_put),
 };
 
+static const struct snd_soc_dapm_widget wl1273_dapm_widgets[] = {
+       SND_SOC_DAPM_INPUT("RX"),
+
+       SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route wl1273_dapm_routes[] = {
+       { "Capture", NULL, "RX" },
+
+       { "TX", NULL, "Playback" },
+};
+
 static int wl1273_startup(struct snd_pcm_substream *substream,
                          struct snd_soc_dai *dai)
 {
@@ -483,6 +495,11 @@ static int wl1273_remove(struct snd_soc_codec *codec)
 static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
        .probe = wl1273_probe,
        .remove = wl1273_remove,
+
+       .dapm_widgets = wl1273_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets),
+       .dapm_routes = wl1273_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wl1273_dapm_routes),
 };
 
 static int wl1273_platform_probe(struct platform_device *pdev)
index 282fd23..8bbddc1 100644 (file)
@@ -998,6 +998,8 @@ SND_SOC_DAPM_INPUT("IN2R"),
 SND_SOC_DAPM_INPUT("IN3L"),
 SND_SOC_DAPM_INPUT("IN3R"),
 
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
@@ -1421,9 +1423,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "Tone Generator 1", NULL, "TONE" },
        { "Tone Generator 2", NULL, "TONE" },
 
-       { "Mic Mute Mixer", NULL, "Noise Mixer" },
-       { "Mic Mute Mixer", NULL, "Mic Mixer" },
-
        { "AIF1 Capture", NULL, "AIF1TX1" },
        { "AIF1 Capture", NULL, "AIF1TX2" },
        { "AIF1 Capture", NULL, "AIF1TX3" },
@@ -1499,23 +1498,6 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "IN3L PGA", NULL, "IN3L" },
        { "IN3R PGA", NULL, "IN3R" },
 
-       { "ASRC1L", NULL, "ASRC1L Input" },
-       { "ASRC1R", NULL, "ASRC1R Input" },
-       { "ASRC2L", NULL, "ASRC2L Input" },
-       { "ASRC2R", NULL, "ASRC2R Input" },
-
-       { "ISRC1DEC1", NULL, "ISRC1DEC1 Input" },
-       { "ISRC1DEC2", NULL, "ISRC1DEC2 Input" },
-
-       { "ISRC1INT1", NULL, "ISRC1INT1 Input" },
-       { "ISRC1INT2", NULL, "ISRC1INT2 Input" },
-
-       { "ISRC2DEC1", NULL, "ISRC2DEC1 Input" },
-       { "ISRC2DEC2", NULL, "ISRC2DEC2 Input" },
-
-       { "ISRC2INT1", NULL, "ISRC2INT1 Input" },
-       { "ISRC2INT2", NULL, "ISRC2INT2 Input" },
-
        ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
        ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
        ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
@@ -1567,22 +1549,25 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
        ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
 
-       ARIZONA_MUX_ROUTES("ASRC1L"),
-       ARIZONA_MUX_ROUTES("ASRC1R"),
-       ARIZONA_MUX_ROUTES("ASRC2L"),
-       ARIZONA_MUX_ROUTES("ASRC2R"),
+       ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+       ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
 
-       ARIZONA_MUX_ROUTES("ISRC1INT1"),
-       ARIZONA_MUX_ROUTES("ISRC1INT2"),
+       ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+       ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+       ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+       ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
 
-       ARIZONA_MUX_ROUTES("ISRC1DEC1"),
-       ARIZONA_MUX_ROUTES("ISRC1DEC2"),
+       ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+       ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"),
 
-       ARIZONA_MUX_ROUTES("ISRC2INT1"),
-       ARIZONA_MUX_ROUTES("ISRC2INT2"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
 
-       ARIZONA_MUX_ROUTES("ISRC2DEC1"),
-       ARIZONA_MUX_ROUTES("ISRC2DEC2"),
+       ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+       ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+       ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
 
        ARIZONA_DSP_ROUTES("DSP1"),
 
@@ -1614,6 +1599,9 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "SPKDAT1R", NULL, "OUT5R" },
 
        { "MICSUPP", NULL, "SYSCLK" },
+
+       { "DRC1 Signal Activity", NULL, "DRC1L" },
+       { "DRC1 Signal Activity", NULL, "DRC1R" },
 };
 
 static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
@@ -1781,6 +1769,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
                return ret;
 
        arizona_init_spk(codec);
+       arizona_init_gpio(codec);
 
        snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
index 2e7cb4b..bbd6438 100644 (file)
@@ -58,14 +58,10 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
        SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
 
 static const struct snd_kcontrol_new wm5110_snd_controls[] = {
-SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
-          ARIZONA_IN1_OSR_SHIFT, 1, 0),
-SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
-          ARIZONA_IN2_OSR_SHIFT, 1, 0),
-SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL,
-          ARIZONA_IN3_OSR_SHIFT, 1, 0),
-SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL,
-          ARIZONA_IN4_OSR_SHIFT, 1, 0),
+SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
+SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
+SOC_ENUM("IN3 OSR", arizona_in_dmic_osr[2]),
+SOC_ENUM("IN4 OSR", arizona_in_dmic_osr[3]),
 
 SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
                     ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
@@ -432,6 +428,9 @@ SND_SOC_DAPM_INPUT("IN3R"),
 SND_SOC_DAPM_INPUT("IN4L"),
 SND_SOC_DAPM_INPUT("IN4R"),
 
+SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"),
+SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"),
+
 SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
@@ -842,9 +841,6 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "Tone Generator 1", NULL, "TONE" },
        { "Tone Generator 2", NULL, "TONE" },
 
-       { "Mic Mute Mixer", NULL, "Noise Mixer" },
-       { "Mic Mute Mixer", NULL, "Mic Mixer" },
-
        { "AIF1 Capture", NULL, "AIF1TX1" },
        { "AIF1 Capture", NULL, "AIF1TX2" },
        { "AIF1 Capture", NULL, "AIF1TX3" },
@@ -979,10 +975,13 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
        ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
 
-       ARIZONA_MUX_ROUTES("ASRC1L"),
-       ARIZONA_MUX_ROUTES("ASRC1R"),
-       ARIZONA_MUX_ROUTES("ASRC2L"),
-       ARIZONA_MUX_ROUTES("ASRC2R"),
+       ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+       ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+       ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"),
+       ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"),
+       ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"),
+       ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"),
 
        { "HPOUT1L", NULL, "OUT1L" },
        { "HPOUT1R", NULL, "OUT1R" },
@@ -1006,6 +1005,11 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "SPKDAT2R", NULL, "OUT6R" },
 
        { "MICSUPP", NULL, "SYSCLK" },
+
+       { "DRC1 Signal Activity", NULL, "DRC1L" },
+       { "DRC1 Signal Activity", NULL, "DRC1R" },
+       { "DRC2 Signal Activity", NULL, "DRC2L" },
+       { "DRC2 Signal Activity", NULL, "DRC2R" },
 };
 
 static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
@@ -1170,6 +1174,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
                return ret;
 
        arizona_init_spk(codec);
+       arizona_init_gpio(codec);
 
        snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
index fa24ced..eebcb1d 100644 (file)
@@ -364,9 +364,7 @@ static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
        u16 reg;
        int ret;
index 0a4ffdd..5e5af89 100644 (file)
@@ -857,9 +857,9 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
        if (pll_div.k) {
                reg |= 0x20;
 
-               snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f);
-               snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff);
-               snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff);
+               snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 16) & 0xff);
+               snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 8) & 0xff);
+               snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0xff);
        }
        snd_soc_write(codec, WM8960_PLL1, reg);
 
index ba832b7..eee2a01 100644 (file)
@@ -1437,9 +1437,7 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING,
 static int wm8994_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *w = wlist->widgets[0];
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
index 90a65c4..da2899e 100644 (file)
@@ -549,12 +549,9 @@ static int check_clk_sys(struct snd_soc_dapm_widget *source,
 static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *w = wlist->widgets[0];
-       struct snd_soc_codec *codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
-       codec = w->codec;
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
        wm8995_update_class_w(codec);
        return ret;
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c
new file mode 100644 (file)
index 0000000..6ec3de3
--- /dev/null
@@ -0,0 +1,1175 @@
+/*
+ * wm8997.c  --  WM8997 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/mfd/arizona/core.h>
+#include <linux/mfd/arizona/registers.h>
+
+#include "arizona.h"
+#include "wm8997.h"
+
+struct wm8997_priv {
+       struct arizona_priv core;
+       struct arizona_fll fll[2];
+};
+
+static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
+static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
+static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0);
+static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0);
+static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
+
+static const struct reg_default wm8997_sysclk_reva_patch[] = {
+       { 0x301D, 0x7B15 },
+       { 0x301B, 0x0050 },
+       { 0x305D, 0x7B17 },
+       { 0x305B, 0x0050 },
+       { 0x3001, 0x08FE },
+       { 0x3003, 0x00F4 },
+       { 0x3041, 0x08FF },
+       { 0x3043, 0x0005 },
+       { 0x3020, 0x0225 },
+       { 0x3021, 0x0A00 },
+       { 0x3022, 0xE24D },
+       { 0x3023, 0x0800 },
+       { 0x3024, 0xE24D },
+       { 0x3025, 0xF000 },
+       { 0x3060, 0x0226 },
+       { 0x3061, 0x0A00 },
+       { 0x3062, 0xE252 },
+       { 0x3063, 0x0800 },
+       { 0x3064, 0xE252 },
+       { 0x3065, 0xF000 },
+       { 0x3116, 0x022B },
+       { 0x3117, 0xFA00 },
+       { 0x3110, 0x246C },
+       { 0x3111, 0x0A03 },
+       { 0x3112, 0x246E },
+       { 0x3113, 0x0A03 },
+       { 0x3114, 0x2470 },
+       { 0x3115, 0x0A03 },
+       { 0x3126, 0x246C },
+       { 0x3127, 0x0A02 },
+       { 0x3128, 0x246E },
+       { 0x3129, 0x0A02 },
+       { 0x312A, 0x2470 },
+       { 0x312B, 0xFA02 },
+       { 0x3125, 0x0800 },
+};
+
+static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
+                           struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
+       struct regmap *regmap = codec->control_data;
+       const struct reg_default *patch = NULL;
+       int i, patch_size;
+
+       switch (arizona->rev) {
+       case 0:
+               patch = wm8997_sysclk_reva_patch;
+               patch_size = ARRAY_SIZE(wm8997_sysclk_reva_patch);
+               break;
+       default:
+               break;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               if (patch)
+                       for (i = 0; i < patch_size; i++)
+                               regmap_write(regmap, patch[i].reg,
+                                            patch[i].def);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static const char *wm8997_osr_text[] = {
+       "Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm8997_osr_val[] = {
+       0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm8997_hpout_osr[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+                             ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+                             wm8997_osr_text, wm8997_osr_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+                             ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+                             wm8997_osr_text, wm8997_osr_val),
+};
+
+#define WM8997_NG_SRC(name, base) \
+       SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
+       SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
+       SOC_SINGLE(name " NG EPOUT Switch",    base, 4, 1, 0), \
+       SOC_SINGLE(name " NG SPKOUT Switch",   base, 6, 1, 0), \
+       SOC_SINGLE(name " NG SPKDAT1L Switch", base, 8, 1, 0), \
+       SOC_SINGLE(name " NG SPKDAT1R Switch", base, 9, 1, 0)
+
+static const struct snd_kcontrol_new wm8997_snd_controls[] = {
+SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL,
+          ARIZONA_IN1_OSR_SHIFT, 1, 0),
+SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL,
+          ARIZONA_IN2_OSR_SHIFT, 1, 0),
+
+SOC_SINGLE_RANGE_TLV("IN1L Volume", ARIZONA_IN1L_CONTROL,
+                    ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN1R Volume", ARIZONA_IN1R_CONTROL,
+                    ARIZONA_IN1R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2L Volume", ARIZONA_IN2L_CONTROL,
+                    ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+SOC_SINGLE_RANGE_TLV("IN2R Volume", ARIZONA_IN2R_CONTROL,
+                    ARIZONA_IN2R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv),
+
+SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L,
+              ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R,
+              ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L,
+              ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R,
+              ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv),
+
+SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
+SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+
+ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("EQ1 Coefficeints", ARIZONA_EQ1_1, 21,
+                  ARIZONA_EQ1_ENA_MASK),
+SND_SOC_BYTES_MASK("EQ2 Coefficeints", ARIZONA_EQ2_1, 21,
+                  ARIZONA_EQ2_ENA_MASK),
+SND_SOC_BYTES_MASK("EQ3 Coefficeints", ARIZONA_EQ3_1, 21,
+                  ARIZONA_EQ3_ENA_MASK),
+SND_SOC_BYTES_MASK("EQ4 Coefficeints", ARIZONA_EQ4_1, 21,
+                  ARIZONA_EQ4_ENA_MASK),
+
+SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT,
+              24, 0, eq_tlv),
+SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT,
+              24, 0, eq_tlv),
+
+ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE),
+
+SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5,
+                  ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA),
+
+ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE),
+
+SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode),
+SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
+SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
+SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
+
+SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1),
+SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1),
+SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1),
+SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1),
+
+SOC_VALUE_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]),
+SOC_VALUE_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]),
+
+ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR,
+              ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv),
+
+ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE),
+
+SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L,
+          ARIZONA_OUT4_OSR_SHIFT, 1, 0),
+SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L,
+          ARIZONA_OUT5_OSR_SHIFT, 1, 0),
+
+SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+            ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+          ARIZONA_OUT3L_MUTE_SHIFT, 1, 1),
+SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+          ARIZONA_OUT4L_MUTE_SHIFT, 1, 1),
+SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+            ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1),
+
+SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L,
+                ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L,
+              ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L,
+              ARIZONA_OUT4L_VOL_SHIFT, 0xbf, 0, digital_tlv),
+SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L,
+                ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT,
+                0xbf, 0, digital_tlv),
+
+SOC_VALUE_ENUM("HPOUT1 OSR", wm8997_hpout_osr[0]),
+SOC_VALUE_ENUM("EPOUT OSR", wm8997_hpout_osr[1]),
+
+SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
+SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
+
+SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT,
+          ARIZONA_SPK1R_MUTE_SHIFT, 1, 1),
+
+SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL,
+          ARIZONA_NGATE_ENA_SHIFT, 1, 0),
+SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL,
+              ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv),
+SOC_ENUM("Noise Gate Hold", arizona_ng_hold),
+
+WM8997_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L),
+WM8997_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R),
+WM8997_NG_SRC("EPOUT", ARIZONA_NOISE_GATE_SELECT_3L),
+WM8997_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L),
+WM8997_NG_SRC("SPKDAT1L", ARIZONA_NOISE_GATE_SELECT_5L),
+WM8997_NG_SRC("SPKDAT1R", ARIZONA_NOISE_GATE_SELECT_5R),
+
+ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE),
+
+ARIZONA_MIXER_CONTROLS("SLIMTX1", ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX2", ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX3", ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX4", ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX5", ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX6", ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX7", ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE),
+ARIZONA_MIXER_CONTROLS("SLIMTX8", ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE),
+};
+
+ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MIXER_ENUMS(SLIMTX1, ARIZONA_SLIMTX1MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX2, ARIZONA_SLIMTX2MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX3, ARIZONA_SLIMTX3MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX4, ARIZONA_SLIMTX4MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX5, ARIZONA_SLIMTX5MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX6, ARIZONA_SLIMTX6MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX7, ARIZONA_SLIMTX7MIX_INPUT_1_SOURCE);
+ARIZONA_MIXER_ENUMS(SLIMTX8, ARIZONA_SLIMTX8MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE);
+
+ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE);
+ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE);
+
+static const char *wm8997_aec_loopback_texts[] = {
+       "HPOUT1L", "HPOUT1R", "EPOUT", "SPKOUT", "SPKDAT1L", "SPKDAT1R",
+};
+
+static const unsigned int wm8997_aec_loopback_values[] = {
+       0, 1, 4, 6, 8, 9,
+};
+
+static const struct soc_enum wm8997_aec_loopback =
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1,
+                             ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf,
+                             ARRAY_SIZE(wm8997_aec_loopback_texts),
+                             wm8997_aec_loopback_texts,
+                             wm8997_aec_loopback_values);
+
+static const struct snd_kcontrol_new wm8997_aec_loopback_mux =
+       SOC_DAPM_VALUE_ENUM("AEC Loopback", wm8997_aec_loopback);
+
+static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = {
+SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
+                   0, wm8997_sysclk_ev, SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
+                   ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
+SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
+SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0),
+
+SND_SOC_DAPM_SIGGEN("TONE"),
+SND_SOC_DAPM_SIGGEN("NOISE"),
+SND_SOC_DAPM_SIGGEN("HAPTICS"),
+
+SND_SOC_DAPM_INPUT("IN1L"),
+SND_SOC_DAPM_INPUT("IN1R"),
+SND_SOC_DAPM_INPUT("IN2L"),
+SND_SOC_DAPM_INPUT("IN2R"),
+
+SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT,
+                  0, NULL, 0, arizona_in_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
+
+SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1,
+                   ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2,
+                   ARIZONA_MICB2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3,
+                   ARIZONA_MICB3_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR,
+                ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1,
+                ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1,
+                ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1,
+                ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0,
+                NULL, 0),
+SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0,
+                NULL, 0),
+
+SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT,
+                0, NULL, 0),
+SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT,
+                0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3,
+                ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3,
+                ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0,
+                    ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0,
+                   ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0,
+                    ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0,
+                   ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_OUT("SLIMTX1", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX2", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX3", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX4", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX5", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX6", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX7", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_OUT("SLIMTX8", NULL, 0,
+                    ARIZONA_SLIMBUS_TX_CHANNEL_ENABLE,
+                    ARIZONA_SLIMTX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX1_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX2", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX2_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX3", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX3_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX4", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX4_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX5", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX5_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX6", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX6_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX7", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX7_ENA_SHIFT, 0),
+SND_SOC_DAPM_AIF_IN("SLIMRX8", NULL, 0,
+                   ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE,
+                   ARIZONA_SLIMRX8_ENA_SHIFT, 0),
+
+SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
+                      ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
+                      &wm8997_aec_loopback_mux),
+
+SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
+                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
+                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1,
+                  ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+
+ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"),
+ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"),
+ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"),
+ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"),
+
+ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"),
+ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"),
+
+ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"),
+ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"),
+ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"),
+ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"),
+
+ARIZONA_MIXER_WIDGETS(Mic, "Mic"),
+ARIZONA_MIXER_WIDGETS(Noise, "Noise"),
+
+ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"),
+ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"),
+
+ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"),
+ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"),
+ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"),
+ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"),
+ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"),
+
+ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"),
+ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"),
+ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"),
+ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"),
+ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"),
+ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"),
+ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"),
+ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"),
+
+ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"),
+ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"),
+
+ARIZONA_MIXER_WIDGETS(SLIMTX1, "SLIMTX1"),
+ARIZONA_MIXER_WIDGETS(SLIMTX2, "SLIMTX2"),
+ARIZONA_MIXER_WIDGETS(SLIMTX3, "SLIMTX3"),
+ARIZONA_MIXER_WIDGETS(SLIMTX4, "SLIMTX4"),
+ARIZONA_MIXER_WIDGETS(SLIMTX5, "SLIMTX5"),
+ARIZONA_MIXER_WIDGETS(SLIMTX6, "SLIMTX6"),
+ARIZONA_MIXER_WIDGETS(SLIMTX7, "SLIMTX7"),
+ARIZONA_MIXER_WIDGETS(SLIMTX8, "SLIMTX8"),
+
+ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"),
+ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"),
+ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"),
+
+ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"),
+ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"),
+
+SND_SOC_DAPM_OUTPUT("HPOUT1L"),
+SND_SOC_DAPM_OUTPUT("HPOUT1R"),
+SND_SOC_DAPM_OUTPUT("EPOUTN"),
+SND_SOC_DAPM_OUTPUT("EPOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKOUTN"),
+SND_SOC_DAPM_OUTPUT("SPKOUTP"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1L"),
+SND_SOC_DAPM_OUTPUT("SPKDAT1R"),
+
+SND_SOC_DAPM_OUTPUT("MICSUPP"),
+};
+
+#define ARIZONA_MIXER_INPUT_ROUTES(name)       \
+       { name, "Noise Generator", "Noise Generator" }, \
+       { name, "Tone Generator 1", "Tone Generator 1" }, \
+       { name, "Tone Generator 2", "Tone Generator 2" }, \
+       { name, "Haptics", "HAPTICS" }, \
+       { name, "AEC", "AEC Loopback" }, \
+       { name, "IN1L", "IN1L PGA" }, \
+       { name, "IN1R", "IN1R PGA" }, \
+       { name, "IN2L", "IN2L PGA" }, \
+       { name, "IN2R", "IN2R PGA" }, \
+       { name, "Mic Mute Mixer", "Mic Mute Mixer" }, \
+       { name, "AIF1RX1", "AIF1RX1" }, \
+       { name, "AIF1RX2", "AIF1RX2" }, \
+       { name, "AIF1RX3", "AIF1RX3" }, \
+       { name, "AIF1RX4", "AIF1RX4" }, \
+       { name, "AIF1RX5", "AIF1RX5" }, \
+       { name, "AIF1RX6", "AIF1RX6" }, \
+       { name, "AIF1RX7", "AIF1RX7" }, \
+       { name, "AIF1RX8", "AIF1RX8" }, \
+       { name, "AIF2RX1", "AIF2RX1" }, \
+       { name, "AIF2RX2", "AIF2RX2" }, \
+       { name, "SLIMRX1", "SLIMRX1" }, \
+       { name, "SLIMRX2", "SLIMRX2" }, \
+       { name, "SLIMRX3", "SLIMRX3" }, \
+       { name, "SLIMRX4", "SLIMRX4" }, \
+       { name, "SLIMRX5", "SLIMRX5" }, \
+       { name, "SLIMRX6", "SLIMRX6" }, \
+       { name, "SLIMRX7", "SLIMRX7" }, \
+       { name, "SLIMRX8", "SLIMRX8" }, \
+       { name, "EQ1", "EQ1" }, \
+       { name, "EQ2", "EQ2" }, \
+       { name, "EQ3", "EQ3" }, \
+       { name, "EQ4", "EQ4" }, \
+       { name, "DRC1L", "DRC1L" }, \
+       { name, "DRC1R", "DRC1R" }, \
+       { name, "LHPF1", "LHPF1" }, \
+       { name, "LHPF2", "LHPF2" }, \
+       { name, "LHPF3", "LHPF3" }, \
+       { name, "LHPF4", "LHPF4" }, \
+       { name, "ISRC1DEC1", "ISRC1DEC1" }, \
+       { name, "ISRC1DEC2", "ISRC1DEC2" }, \
+       { name, "ISRC1INT1", "ISRC1INT1" }, \
+       { name, "ISRC1INT2", "ISRC1INT2" }, \
+       { name, "ISRC2DEC1", "ISRC2DEC1" }, \
+       { name, "ISRC2DEC2", "ISRC2DEC2" }, \
+       { name, "ISRC2INT1", "ISRC2INT1" }, \
+       { name, "ISRC2INT2", "ISRC2INT2" }
+
+static const struct snd_soc_dapm_route wm8997_dapm_routes[] = {
+       { "AIF2 Capture", NULL, "DBVDD2" },
+       { "AIF2 Playback", NULL, "DBVDD2" },
+
+       { "OUT1L", NULL, "CPVDD" },
+       { "OUT1R", NULL, "CPVDD" },
+       { "OUT3L", NULL, "CPVDD" },
+
+       { "OUT4L", NULL, "SPKVDD" },
+
+       { "OUT1L", NULL, "SYSCLK" },
+       { "OUT1R", NULL, "SYSCLK" },
+       { "OUT3L", NULL, "SYSCLK" },
+       { "OUT4L", NULL, "SYSCLK" },
+
+       { "IN1L", NULL, "SYSCLK" },
+       { "IN1R", NULL, "SYSCLK" },
+       { "IN2L", NULL, "SYSCLK" },
+       { "IN2R", NULL, "SYSCLK" },
+
+       { "MICBIAS1", NULL, "MICVDD" },
+       { "MICBIAS2", NULL, "MICVDD" },
+       { "MICBIAS3", NULL, "MICVDD" },
+
+       { "Noise Generator", NULL, "SYSCLK" },
+       { "Tone Generator 1", NULL, "SYSCLK" },
+       { "Tone Generator 2", NULL, "SYSCLK" },
+
+       { "Noise Generator", NULL, "NOISE" },
+       { "Tone Generator 1", NULL, "TONE" },
+       { "Tone Generator 2", NULL, "TONE" },
+
+       { "AIF1 Capture", NULL, "AIF1TX1" },
+       { "AIF1 Capture", NULL, "AIF1TX2" },
+       { "AIF1 Capture", NULL, "AIF1TX3" },
+       { "AIF1 Capture", NULL, "AIF1TX4" },
+       { "AIF1 Capture", NULL, "AIF1TX5" },
+       { "AIF1 Capture", NULL, "AIF1TX6" },
+       { "AIF1 Capture", NULL, "AIF1TX7" },
+       { "AIF1 Capture", NULL, "AIF1TX8" },
+
+       { "AIF1RX1", NULL, "AIF1 Playback" },
+       { "AIF1RX2", NULL, "AIF1 Playback" },
+       { "AIF1RX3", NULL, "AIF1 Playback" },
+       { "AIF1RX4", NULL, "AIF1 Playback" },
+       { "AIF1RX5", NULL, "AIF1 Playback" },
+       { "AIF1RX6", NULL, "AIF1 Playback" },
+       { "AIF1RX7", NULL, "AIF1 Playback" },
+       { "AIF1RX8", NULL, "AIF1 Playback" },
+
+       { "AIF2 Capture", NULL, "AIF2TX1" },
+       { "AIF2 Capture", NULL, "AIF2TX2" },
+
+       { "AIF2RX1", NULL, "AIF2 Playback" },
+       { "AIF2RX2", NULL, "AIF2 Playback" },
+
+       { "Slim1 Capture", NULL, "SLIMTX1" },
+       { "Slim1 Capture", NULL, "SLIMTX2" },
+       { "Slim1 Capture", NULL, "SLIMTX3" },
+       { "Slim1 Capture", NULL, "SLIMTX4" },
+
+       { "SLIMRX1", NULL, "Slim1 Playback" },
+       { "SLIMRX2", NULL, "Slim1 Playback" },
+       { "SLIMRX3", NULL, "Slim1 Playback" },
+       { "SLIMRX4", NULL, "Slim1 Playback" },
+
+       { "Slim2 Capture", NULL, "SLIMTX5" },
+       { "Slim2 Capture", NULL, "SLIMTX6" },
+
+       { "SLIMRX5", NULL, "Slim2 Playback" },
+       { "SLIMRX6", NULL, "Slim2 Playback" },
+
+       { "Slim3 Capture", NULL, "SLIMTX7" },
+       { "Slim3 Capture", NULL, "SLIMTX8" },
+
+       { "SLIMRX7", NULL, "Slim3 Playback" },
+       { "SLIMRX8", NULL, "Slim3 Playback" },
+
+       { "AIF1 Playback", NULL, "SYSCLK" },
+       { "AIF2 Playback", NULL, "SYSCLK" },
+       { "Slim1 Playback", NULL, "SYSCLK" },
+       { "Slim2 Playback", NULL, "SYSCLK" },
+       { "Slim3 Playback", NULL, "SYSCLK" },
+
+       { "AIF1 Capture", NULL, "SYSCLK" },
+       { "AIF2 Capture", NULL, "SYSCLK" },
+       { "Slim1 Capture", NULL, "SYSCLK" },
+       { "Slim2 Capture", NULL, "SYSCLK" },
+       { "Slim3 Capture", NULL, "SYSCLK" },
+
+       { "IN1L PGA", NULL, "IN1L" },
+       { "IN1R PGA", NULL, "IN1R" },
+
+       { "IN2L PGA", NULL, "IN2L" },
+       { "IN2R PGA", NULL, "IN2R" },
+
+       ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
+       ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
+       ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"),
+
+       ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"),
+       ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"),
+       ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"),
+
+       ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"),
+       ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"),
+
+       ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"),
+       ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"),
+       ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"),
+       ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"),
+       ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"),
+       ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"),
+       ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"),
+       ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"),
+
+       ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"),
+       ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"),
+
+       ARIZONA_MIXER_ROUTES("SLIMTX1", "SLIMTX1"),
+       ARIZONA_MIXER_ROUTES("SLIMTX2", "SLIMTX2"),
+       ARIZONA_MIXER_ROUTES("SLIMTX3", "SLIMTX3"),
+       ARIZONA_MIXER_ROUTES("SLIMTX4", "SLIMTX4"),
+       ARIZONA_MIXER_ROUTES("SLIMTX5", "SLIMTX5"),
+       ARIZONA_MIXER_ROUTES("SLIMTX6", "SLIMTX6"),
+       ARIZONA_MIXER_ROUTES("SLIMTX7", "SLIMTX7"),
+       ARIZONA_MIXER_ROUTES("SLIMTX8", "SLIMTX8"),
+
+       ARIZONA_MIXER_ROUTES("EQ1", "EQ1"),
+       ARIZONA_MIXER_ROUTES("EQ2", "EQ2"),
+       ARIZONA_MIXER_ROUTES("EQ3", "EQ3"),
+       ARIZONA_MIXER_ROUTES("EQ4", "EQ4"),
+
+       ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"),
+       ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"),
+
+       ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"),
+       ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"),
+       ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"),
+       ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"),
+
+       ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Noise"),
+       ARIZONA_MIXER_ROUTES("Mic Mute Mixer", "Mic"),
+
+       ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"),
+       ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC2INT2"),
+
+       ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"),
+
+       ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"),
+       ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"),
+
+       ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"),
+       ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"),
+
+       { "AEC Loopback", "HPOUT1L", "OUT1L" },
+       { "AEC Loopback", "HPOUT1R", "OUT1R" },
+       { "HPOUT1L", NULL, "OUT1L" },
+       { "HPOUT1R", NULL, "OUT1R" },
+
+       { "AEC Loopback", "EPOUT", "OUT3L" },
+       { "EPOUTN", NULL, "OUT3L" },
+       { "EPOUTP", NULL, "OUT3L" },
+
+       { "AEC Loopback", "SPKOUT", "OUT4L" },
+       { "SPKOUTN", NULL, "OUT4L" },
+       { "SPKOUTP", NULL, "OUT4L" },
+
+       { "AEC Loopback", "SPKDAT1L", "OUT5L" },
+       { "AEC Loopback", "SPKDAT1R", "OUT5R" },
+       { "SPKDAT1L", NULL, "OUT5L" },
+       { "SPKDAT1R", NULL, "OUT5R" },
+
+       { "MICSUPP", NULL, "SYSCLK" },
+};
+
+static int wm8997_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
+                         unsigned int Fref, unsigned int Fout)
+{
+       struct wm8997_priv *wm8997 = snd_soc_codec_get_drvdata(codec);
+
+       switch (fll_id) {
+       case WM8997_FLL1:
+               return arizona_set_fll(&wm8997->fll[0], source, Fref, Fout);
+       case WM8997_FLL2:
+               return arizona_set_fll(&wm8997->fll[1], source, Fref, Fout);
+       case WM8997_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&wm8997->fll[0], source, Fref,
+                                             Fout);
+       case WM8997_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&wm8997->fll[1], source, Fref,
+                                             Fout);
+       default:
+               return -EINVAL;
+       }
+}
+
+#define WM8997_RATES SNDRV_PCM_RATE_8000_192000
+
+#define WM8997_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
+                       SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver wm8997_dai[] = {
+       {
+               .name = "wm8997-aif1",
+               .id = 1,
+               .base = ARIZONA_AIF1_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 8,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF1 Capture",
+                        .channels_min = 1,
+                        .channels_max = 8,
+                        .rates = WM8997_RATES,
+                        .formats = WM8997_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+       },
+       {
+               .name = "wm8997-aif2",
+               .id = 2,
+               .base = ARIZONA_AIF2_BCLK_CTRL,
+               .playback = {
+                       .stream_name = "AIF2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .capture = {
+                        .stream_name = "AIF2 Capture",
+                        .channels_min = 1,
+                        .channels_max = 2,
+                        .rates = WM8997_RATES,
+                        .formats = WM8997_FORMATS,
+                },
+               .ops = &arizona_dai_ops,
+               .symmetric_rates = 1,
+       },
+       {
+               .name = "wm8997-slim1",
+               .id = 3,
+               .playback = {
+                       .stream_name = "Slim1 Playback",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Slim1 Capture",
+                       .channels_min = 1,
+                       .channels_max = 4,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm8997-slim2",
+               .id = 4,
+               .playback = {
+                       .stream_name = "Slim2 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Slim2 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .ops = &arizona_simple_dai_ops,
+       },
+       {
+               .name = "wm8997-slim3",
+               .id = 5,
+               .playback = {
+                       .stream_name = "Slim3 Playback",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .capture = {
+                       .stream_name = "Slim3 Capture",
+                       .channels_min = 1,
+                       .channels_max = 2,
+                       .rates = WM8997_RATES,
+                       .formats = WM8997_FORMATS,
+               },
+               .ops = &arizona_simple_dai_ops,
+       },
+};
+
+static int wm8997_codec_probe(struct snd_soc_codec *codec)
+{
+       struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
+       codec->control_data = priv->core.arizona->regmap;
+
+       ret = snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP);
+       if (ret != 0)
+               return ret;
+
+       arizona_init_spk(codec);
+
+       snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
+
+       priv->core.arizona->dapm = &codec->dapm;
+
+       return 0;
+}
+
+static int wm8997_codec_remove(struct snd_soc_codec *codec)
+{
+       struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->core.arizona->dapm = NULL;
+
+       return 0;
+}
+
+#define WM8997_DIG_VU 0x0200
+
+static unsigned int wm8997_digital_vu[] = {
+       ARIZONA_DAC_DIGITAL_VOLUME_1L,
+       ARIZONA_DAC_DIGITAL_VOLUME_1R,
+       ARIZONA_DAC_DIGITAL_VOLUME_3L,
+       ARIZONA_DAC_DIGITAL_VOLUME_4L,
+       ARIZONA_DAC_DIGITAL_VOLUME_5L,
+       ARIZONA_DAC_DIGITAL_VOLUME_5R,
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_wm8997 = {
+       .probe = wm8997_codec_probe,
+       .remove = wm8997_codec_remove,
+
+       .idle_bias_off = true,
+
+       .set_sysclk = arizona_set_sysclk,
+       .set_pll = wm8997_set_fll,
+
+       .controls = wm8997_snd_controls,
+       .num_controls = ARRAY_SIZE(wm8997_snd_controls),
+       .dapm_widgets = wm8997_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wm8997_dapm_widgets),
+       .dapm_routes = wm8997_dapm_routes,
+       .num_dapm_routes = ARRAY_SIZE(wm8997_dapm_routes),
+};
+
+static int wm8997_probe(struct platform_device *pdev)
+{
+       struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
+       struct wm8997_priv *wm8997;
+       int i;
+
+       wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv),
+                             GFP_KERNEL);
+       if (wm8997 == NULL)
+               return -ENOMEM;
+       platform_set_drvdata(pdev, wm8997);
+
+       wm8997->core.arizona = arizona;
+       wm8997->core.num_inputs = 4;
+
+       for (i = 0; i < ARRAY_SIZE(wm8997->fll); i++)
+               wm8997->fll[i].vco_mult = 1;
+
+       arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1,
+                        ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK,
+                        &wm8997->fll[0]);
+       arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1,
+                        ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
+                        &wm8997->fll[1]);
+
+       /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */
+       regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2,
+                          ARIZONA_SAMPLE_RATE_2_MASK, 0x11);
+       regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3,
+                          ARIZONA_SAMPLE_RATE_3_MASK, 0x12);
+
+       for (i = 0; i < ARRAY_SIZE(wm8997_dai); i++)
+               arizona_init_dai(&wm8997->core, i);
+
+       /* Latch volume update bits */
+       for (i = 0; i < ARRAY_SIZE(wm8997_digital_vu); i++)
+               regmap_update_bits(arizona->regmap, wm8997_digital_vu[i],
+                                  WM8997_DIG_VU, WM8997_DIG_VU);
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_idle(&pdev->dev);
+
+       return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997,
+                                     wm8997_dai, ARRAY_SIZE(wm8997_dai));
+}
+
+static int wm8997_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+}
+
+static struct platform_driver wm8997_codec_driver = {
+       .driver = {
+               .name = "wm8997-codec",
+               .owner = THIS_MODULE,
+       },
+       .probe = wm8997_probe,
+       .remove = wm8997_remove,
+};
+
+module_platform_driver(wm8997_codec_driver);
+
+MODULE_DESCRIPTION("ASoC WM8997 driver");
+MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8997-codec");
diff --git a/sound/soc/codecs/wm8997.h b/sound/soc/codecs/wm8997.h
new file mode 100644 (file)
index 0000000..5e91c6a
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * wm8997.h  --  WM8997 ALSA SoC Audio driver
+ *
+ * Copyright 2012 Wolfson Microelectronics plc
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8997_H
+#define _WM8997_H
+
+#include "arizona.h"
+
+#define WM8997_FLL1        1
+#define WM8997_FLL2        2
+#define WM8997_FLL1_REFCLK 3
+#define WM8997_FLL2_REFCLK 4
+
+#endif
index 05252ac..b38f350 100644 (file)
@@ -225,15 +225,8 @@ struct wm_coeff_ctl_ops {
                     struct snd_ctl_elem_info *uinfo);
 };
 
-struct wm_coeff {
-       struct device *dev;
-       struct list_head ctl_list;
-       struct regmap *regmap;
-};
-
 struct wm_coeff_ctl {
        const char *name;
-       struct snd_card *card;
        struct wm_adsp_alg_region region;
        struct wm_coeff_ctl_ops ops;
        struct wm_adsp *adsp;
@@ -378,7 +371,6 @@ static int wm_coeff_info(struct snd_kcontrol *kcontrol,
 static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
                                  const void *buf, size_t len)
 {
-       struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
        struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
        struct wm_adsp_alg_region *region = &ctl->region;
        const struct wm_adsp_region *mem;
@@ -401,7 +393,7 @@ static int wm_coeff_write_control(struct snd_kcontrol *kcontrol,
        if (!scratch)
                return -ENOMEM;
 
-       ret = regmap_raw_write(wm_coeff->regmap, reg, scratch,
+       ret = regmap_raw_write(adsp->regmap, reg, scratch,
                               ctl->len);
        if (ret) {
                adsp_err(adsp, "Failed to write %zu bytes to %x\n",
@@ -434,7 +426,6 @@ static int wm_coeff_put(struct snd_kcontrol *kcontrol,
 static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
                                 void *buf, size_t len)
 {
-       struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol);
        struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value;
        struct wm_adsp_alg_region *region = &ctl->region;
        const struct wm_adsp_region *mem;
@@ -457,7 +448,7 @@ static int wm_coeff_read_control(struct snd_kcontrol *kcontrol,
        if (!scratch)
                return -ENOMEM;
 
-       ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len);
+       ret = regmap_raw_read(adsp->regmap, reg, scratch, ctl->len);
        if (ret) {
                adsp_err(adsp, "Failed to read %zu bytes from %x\n",
                         ctl->len, reg);
@@ -481,37 +472,18 @@ static int wm_coeff_get(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff,
-                                struct wm_coeff_ctl *ctl,
-                                const struct snd_kcontrol_new *kctl)
-{
-       int ret;
-       struct snd_kcontrol *kcontrol;
-
-       kcontrol = snd_ctl_new1(kctl, wm_coeff);
-       ret = snd_ctl_add(ctl->card, kcontrol);
-       if (ret < 0) {
-               dev_err(wm_coeff->dev, "Failed to add %s: %d\n",
-                       kctl->name, ret);
-               return ret;
-       }
-       ctl->kcontrol = kcontrol;
-       return 0;
-}
-
 struct wmfw_ctl_work {
-       struct wm_coeff *wm_coeff;
+       struct wm_adsp *adsp;
        struct wm_coeff_ctl *ctl;
        struct work_struct work;
 };
 
-static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
-                       struct wm_coeff_ctl *ctl)
+static int wmfw_add_ctl(struct wm_adsp *adsp, struct wm_coeff_ctl *ctl)
 {
        struct snd_kcontrol_new *kcontrol;
        int ret;
 
-       if (!wm_coeff || !ctl || !ctl->name || !ctl->card)
+       if (!ctl || !ctl->name)
                return -EINVAL;
 
        kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL);
@@ -525,14 +497,17 @@ static int wmfw_add_ctl(struct wm_coeff *wm_coeff,
        kcontrol->put = wm_coeff_put;
        kcontrol->private_value = (unsigned long)ctl;
 
-       ret = wm_coeff_add_kcontrol(wm_coeff,
-                                   ctl, kcontrol);
+       ret = snd_soc_add_card_controls(adsp->card,
+                                       kcontrol, 1);
        if (ret < 0)
                goto err_kcontrol;
 
        kfree(kcontrol);
 
-       list_add(&ctl->list, &wm_coeff->ctl_list);
+       ctl->kcontrol = snd_soc_card_get_kcontrol(adsp->card,
+                                                 ctl->name);
+
+       list_add(&ctl->list, &adsp->ctl_list);
        return 0;
 
 err_kcontrol:
@@ -753,13 +728,12 @@ out:
        return ret;
 }
 
-static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
+static int wm_coeff_init_control_caches(struct wm_adsp *adsp)
 {
        struct wm_coeff_ctl *ctl;
        int ret;
 
-       list_for_each_entry(ctl, &wm_coeff->ctl_list,
-                           list) {
+       list_for_each_entry(ctl, &adsp->ctl_list, list) {
                if (!ctl->enabled || ctl->set)
                        continue;
                ret = wm_coeff_read_control(ctl->kcontrol,
@@ -772,13 +746,12 @@ static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff)
        return 0;
 }
 
-static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff)
+static int wm_coeff_sync_controls(struct wm_adsp *adsp)
 {
        struct wm_coeff_ctl *ctl;
        int ret;
 
-       list_for_each_entry(ctl, &wm_coeff->ctl_list,
-                           list) {
+       list_for_each_entry(ctl, &adsp->ctl_list, list) {
                if (!ctl->enabled)
                        continue;
                if (ctl->set) {
@@ -799,15 +772,14 @@ static void wm_adsp_ctl_work(struct work_struct *work)
                                                      struct wmfw_ctl_work,
                                                      work);
 
-       wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl);
+       wmfw_add_ctl(ctl_work->adsp, ctl_work->ctl);
        kfree(ctl_work);
 }
 
-static int wm_adsp_create_control(struct snd_soc_codec *codec,
+static int wm_adsp_create_control(struct wm_adsp *dsp,
                                  const struct wm_adsp_alg_region *region)
 
 {
-       struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec);
        struct wm_coeff_ctl *ctl;
        struct wmfw_ctl_work *ctl_work;
        char *name;
@@ -842,7 +814,7 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec,
        snprintf(name, PAGE_SIZE, "DSP%d %s %x",
                 dsp->num, region_name, region->alg);
 
-       list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
+       list_for_each_entry(ctl, &dsp->ctl_list,
                            list) {
                if (!strcmp(ctl->name, name)) {
                        if (!ctl->enabled)
@@ -866,7 +838,6 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec,
        ctl->set = 0;
        ctl->ops.xget = wm_coeff_get;
        ctl->ops.xput = wm_coeff_put;
-       ctl->card = codec->card->snd_card;
        ctl->adsp = dsp;
 
        ctl->len = region->len;
@@ -882,7 +853,7 @@ static int wm_adsp_create_control(struct snd_soc_codec *codec,
                goto err_ctl_cache;
        }
 
-       ctl_work->wm_coeff = dsp->wm_coeff;
+       ctl_work->adsp = dsp;
        ctl_work->ctl = ctl;
        INIT_WORK(&ctl_work->work, wm_adsp_ctl_work);
        schedule_work(&ctl_work->work);
@@ -903,7 +874,7 @@ err_name:
        return ret;
 }
 
-static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
+static int wm_adsp_setup_algs(struct wm_adsp *dsp)
 {
        struct regmap *regmap = dsp->regmap;
        struct wmfw_adsp1_id_hdr adsp1_id;
@@ -1091,7 +1062,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp1_alg[i + 1].dm);
                                region->len -= be32_to_cpu(adsp1_alg[i].dm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region DM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1108,7 +1079,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp1_alg[i + 1].zm);
                                region->len -= be32_to_cpu(adsp1_alg[i].zm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp1_alg[i].alg.id));
@@ -1137,7 +1108,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp2_alg[i + 1].xm);
                                region->len -= be32_to_cpu(adsp2_alg[i].xm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region XM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1154,7 +1125,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp2_alg[i + 1].ym);
                                region->len -= be32_to_cpu(adsp2_alg[i].ym);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region YM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1171,7 +1142,7 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec)
                        if (i + 1 < algs) {
                                region->len = be32_to_cpu(adsp2_alg[i + 1].zm);
                                region->len -= be32_to_cpu(adsp2_alg[i].zm);
-                               wm_adsp_create_control(codec, region);
+                               wm_adsp_create_control(dsp, region);
                        } else {
                                adsp_warn(dsp, "Missing length info for region ZM with ID %x\n",
                                          be32_to_cpu(adsp2_alg[i].alg.id));
@@ -1391,6 +1362,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
        int ret;
        int val;
 
+       dsp->card = codec->card;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
@@ -1425,7 +1398,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp, codec);
+               ret = wm_adsp_setup_algs(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1434,12 +1407,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                        goto err;
 
                /* Initialize caches for enabled and unset controls */
-               ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+               ret = wm_coeff_init_control_caches(dsp);
                if (ret != 0)
                        goto err;
 
                /* Sync set controls */
-               ret = wm_coeff_sync_controls(dsp->wm_coeff);
+               ret = wm_coeff_sync_controls(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1460,10 +1433,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30,
                                   ADSP1_SYS_ENA, 0);
 
-               list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
-                                   list) {
+               list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
-               }
                break;
 
        default:
@@ -1520,6 +1491,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
        unsigned int val;
        int ret;
 
+       dsp->card = codec->card;
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /*
@@ -1582,7 +1555,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                if (ret != 0)
                        goto err;
 
-               ret = wm_adsp_setup_algs(dsp, codec);
+               ret = wm_adsp_setup_algs(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1591,12 +1564,12 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                        goto err;
 
                /* Initialize caches for enabled and unset controls */
-               ret = wm_coeff_init_control_caches(dsp->wm_coeff);
+               ret = wm_coeff_init_control_caches(dsp);
                if (ret != 0)
                        goto err;
 
                /* Sync set controls */
-               ret = wm_coeff_sync_controls(dsp->wm_coeff);
+               ret = wm_coeff_sync_controls(dsp);
                if (ret != 0)
                        goto err;
 
@@ -1637,10 +1610,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                                        ret);
                }
 
-               list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list,
-                                   list) {
+               list_for_each_entry(ctl, &dsp->ctl_list, list)
                        ctl->enabled = 0;
-               }
 
                while (!list_empty(&dsp->alg_regions)) {
                        alg_region = list_first_entry(&dsp->alg_regions,
@@ -1679,49 +1650,38 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs)
        }
 
        INIT_LIST_HEAD(&adsp->alg_regions);
-
-       adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff),
-                                GFP_KERNEL);
-       if (!adsp->wm_coeff)
-               return -ENOMEM;
-       adsp->wm_coeff->regmap = adsp->regmap;
-       adsp->wm_coeff->dev = adsp->dev;
-       INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list);
+       INIT_LIST_HEAD(&adsp->ctl_list);
 
        if (dvfs) {
                adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD");
                if (IS_ERR(adsp->dvfs)) {
                        ret = PTR_ERR(adsp->dvfs);
                        dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret);
-                       goto out_coeff;
+                       return ret;
                }
 
                ret = regulator_enable(adsp->dvfs);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to enable DCVDD: %d\n",
                                ret);
-                       goto out_coeff;
+                       return ret;
                }
 
                ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to initialise DVFS: %d\n",
                                ret);
-                       goto out_coeff;
+                       return ret;
                }
 
                ret = regulator_disable(adsp->dvfs);
                if (ret != 0) {
                        dev_err(adsp->dev, "Failed to disable DCVDD: %d\n",
                                ret);
-                       goto out_coeff;
+                       return ret;
                }
        }
 
        return 0;
-
-out_coeff:
-       kfree(adsp->wm_coeff);
-       return ret;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_init);
index 9f922c8..d018dea 100644 (file)
@@ -39,6 +39,7 @@ struct wm_adsp {
        int type;
        struct device *dev;
        struct regmap *regmap;
+       struct snd_soc_card *card;
 
        int base;
        int sysclk_reg;
@@ -57,7 +58,7 @@ struct wm_adsp {
 
        struct regulator *dvfs;
 
-       struct wm_coeff *wm_coeff;
+       struct list_head ctl_list;
 };
 
 #define WM_ADSP1(wname, num) \
index 2d9e099..8b50e59 100644 (file)
@@ -699,9 +699,7 @@ EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
 static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
        ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
@@ -721,9 +719,7 @@ static int class_w_put_volsw(struct snd_kcontrol *kcontrol,
 static int class_w_put_double(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        int ret;
 
        ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
index aa43854..cd088cc 100644 (file)
@@ -1,6 +1,9 @@
 config SND_SOC_FSL_SSI
        tristate
 
+config SND_SOC_FSL_SPDIF
+       tristate
+
 config SND_SOC_FSL_UTILS
        tristate
 
@@ -98,7 +101,7 @@ endif # SND_POWERPC_SOC
 
 menuconfig SND_IMX_SOC
        tristate "SoC Audio for Freescale i.MX CPUs"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        help
          Say Y or M if you want to add support for codecs attached to
          the i.MX CPUs.
@@ -109,11 +112,11 @@ config SND_SOC_IMX_SSI
        tristate
 
 config SND_SOC_IMX_PCM_FIQ
-       bool
+       tristate
        select FIQ
 
 config SND_SOC_IMX_PCM_DMA
-       bool
+       tristate
        select SND_SOC_GENERIC_DMAENGINE_PCM
 
 config SND_SOC_IMX_AUDMUX
@@ -175,7 +178,6 @@ config SND_SOC_IMX_WM8962
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_FSL_SSI
-       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add support for SoC audio on an i.MX board with
          a wm8962 codec.
@@ -187,14 +189,13 @@ config SND_SOC_IMX_SGTL5000
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_FSL_SSI
-       select SND_SOC_FSL_UTILS
        help
          Say Y if you want to add support for SoC audio on an i.MX board with
          a sgtl5000 codec.
 
 config SND_SOC_IMX_MC13783
        tristate "SoC Audio support for I.MX boards with mc13783"
-       depends on MFD_MC13783
+       depends on MFD_MC13783 && ARM
        select SND_SOC_IMX_SSI
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_MC13783
index d4b4aa8..4b5970e 100644 (file)
@@ -12,9 +12,11 @@ obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o
 
 # Freescale PowerPC SSI/DMA Platform Support
 snd-soc-fsl-ssi-objs := fsl_ssi.o
+snd-soc-fsl-spdif-objs := fsl_spdif.o
 snd-soc-fsl-utils-objs := fsl_utils.o
 snd-soc-fsl-dma-objs := fsl_dma.o
 obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
+obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
 obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
 obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o
 
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c
new file mode 100644 (file)
index 0000000..42a4382
--- /dev/null
@@ -0,0 +1,1236 @@
+/*
+ * Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Based on stmp3xxx_spdif_dai.c
+ * Vladimir Barinov <vbarinov@embeddedalley.com>
+ * Copyright 2008 SigmaTel, Inc
+ * Copyright 2008 Embedded Alley Solutions, Inc
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program  is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/clk-private.h>
+#include <linux/bitrev.h>
+#include <linux/regmap.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+
+#include <sound/asoundef.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#include "fsl_spdif.h"
+#include "imx-pcm.h"
+
+#define FSL_SPDIF_TXFIFO_WML   0x8
+#define FSL_SPDIF_RXFIFO_WML   0x8
+
+#define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC)
+#define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL | INT_URX_OV|\
+               INT_QRX_FUL | INT_QRX_OV | INT_UQ_SYNC | INT_UQ_ERR |\
+               INT_RXFIFO_RESYNC | INT_LOSS_LOCK | INT_DPLL_LOCKED)
+
+/* Index list for the values that has if (DPLL Locked) condition */
+static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
+#define SRPC_NODPLL_START1     0x5
+#define SRPC_NODPLL_START2     0xc
+
+#define DEFAULT_RXCLK_SRC      1
+
+/*
+ * SPDIF control structure
+ * Defines channel status, subcode and Q sub
+ */
+struct spdif_mixer_control {
+       /* spinlock to access control data */
+       spinlock_t ctl_lock;
+
+       /* IEC958 channel tx status bit */
+       unsigned char ch_status[4];
+
+       /* User bits */
+       unsigned char subcode[2 * SPDIF_UBITS_SIZE];
+
+       /* Q subcode part of user bits */
+       unsigned char qsub[2 * SPDIF_QSUB_SIZE];
+
+       /* Buffer offset for U/Q */
+       u32 upos;
+       u32 qpos;
+
+       /* Ready buffer index of the two buffers */
+       u32 ready_buf;
+};
+
+struct fsl_spdif_priv {
+       struct spdif_mixer_control fsl_spdif_control;
+       struct snd_soc_dai_driver cpu_dai_drv;
+       struct platform_device *pdev;
+       struct regmap *regmap;
+       bool dpll_locked;
+       u8 txclk_div[SPDIF_TXRATE_MAX];
+       u8 txclk_src[SPDIF_TXRATE_MAX];
+       u8 rxclk_src;
+       struct clk *txclk[SPDIF_TXRATE_MAX];
+       struct clk *rxclk;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+
+       /* The name space will be allocated dynamically */
+       char name[0];
+};
+
+
+/* DPLL locked and lock loss interrupt handler */
+static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
+{
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u32 locked;
+
+       regmap_read(regmap, REG_SPDIF_SRPC, &locked);
+       locked &= SRPC_DPLL_LOCKED;
+
+       dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
+                       locked ? "locked" : "loss lock");
+
+       spdif_priv->dpll_locked = locked ? true : false;
+}
+
+/* Receiver found illegal symbol interrupt handler */
+static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv)
+{
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+
+       dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n");
+
+       if (!spdif_priv->dpll_locked) {
+               /* DPLL unlocked seems no audio stream */
+               regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0);
+       }
+}
+
+/* U/Q Channel receive register full */
+static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name)
+{
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u32 *pos, size, val, reg;
+
+       switch (name) {
+       case 'U':
+               pos = &ctrl->upos;
+               size = SPDIF_UBITS_SIZE;
+               reg = REG_SPDIF_SRU;
+               break;
+       case 'Q':
+               pos = &ctrl->qpos;
+               size = SPDIF_QSUB_SIZE;
+               reg = REG_SPDIF_SRQ;
+               break;
+       default:
+               dev_err(&pdev->dev, "unsupported channel name\n");
+               return;
+       }
+
+       dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name);
+
+       if (*pos >= size * 2) {
+               *pos = 0;
+       } else if (unlikely((*pos % size) + 3 > size)) {
+               dev_err(&pdev->dev, "User bit receivce buffer overflow\n");
+               return;
+       }
+
+       regmap_read(regmap, reg, &val);
+       ctrl->subcode[*pos++] = val >> 16;
+       ctrl->subcode[*pos++] = val >> 8;
+       ctrl->subcode[*pos++] = val;
+}
+
+/* U/Q Channel sync found */
+static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv)
+{
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       struct platform_device *pdev = spdif_priv->pdev;
+
+       dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n");
+
+       /* U/Q buffer reset */
+       if (ctrl->qpos == 0)
+               return;
+
+       /* Set ready to this buffer */
+       ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1;
+}
+
+/* U/Q Channel framing error */
+static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv)
+{
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u32 val;
+
+       dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n");
+
+       /* Read U/Q data to clear the irq and do buffer reset */
+       regmap_read(regmap, REG_SPDIF_SRU, &val);
+       regmap_read(regmap, REG_SPDIF_SRQ, &val);
+
+       /* Drop this U/Q buffer */
+       ctrl->ready_buf = 0;
+       ctrl->upos = 0;
+       ctrl->qpos = 0;
+}
+
+/* Get spdif interrupt status and clear the interrupt */
+static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv)
+{
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val, val2;
+
+       regmap_read(regmap, REG_SPDIF_SIS, &val);
+       regmap_read(regmap, REG_SPDIF_SIE, &val2);
+
+       regmap_write(regmap, REG_SPDIF_SIC, val & val2);
+
+       return val;
+}
+
+static irqreturn_t spdif_isr(int irq, void *devid)
+{
+       struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u32 sis;
+
+       sis = spdif_intr_status_clear(spdif_priv);
+
+       if (sis & INT_DPLL_LOCKED)
+               spdif_irq_dpll_lock(spdif_priv);
+
+       if (sis & INT_TXFIFO_UNOV)
+               dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n");
+
+       if (sis & INT_TXFIFO_RESYNC)
+               dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n");
+
+       if (sis & INT_CNEW)
+               dev_dbg(&pdev->dev, "isr: cstatus new\n");
+
+       if (sis & INT_VAL_NOGOOD)
+               dev_dbg(&pdev->dev, "isr: validity flag no good\n");
+
+       if (sis & INT_SYM_ERR)
+               spdif_irq_sym_error(spdif_priv);
+
+       if (sis & INT_BIT_ERR)
+               dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n");
+
+       if (sis & INT_URX_FUL)
+               spdif_irq_uqrx_full(spdif_priv, 'U');
+
+       if (sis & INT_URX_OV)
+               dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n");
+
+       if (sis & INT_QRX_FUL)
+               spdif_irq_uqrx_full(spdif_priv, 'Q');
+
+       if (sis & INT_QRX_OV)
+               dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n");
+
+       if (sis & INT_UQ_SYNC)
+               spdif_irq_uq_sync(spdif_priv);
+
+       if (sis & INT_UQ_ERR)
+               spdif_irq_uq_err(spdif_priv);
+
+       if (sis & INT_RXFIFO_UNOV)
+               dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n");
+
+       if (sis & INT_RXFIFO_RESYNC)
+               dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n");
+
+       if (sis & INT_LOSS_LOCK)
+               spdif_irq_dpll_lock(spdif_priv);
+
+       /* FIXME: Write Tx FIFO to clear TxEm */
+       if (sis & INT_TX_EM)
+               dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n");
+
+       /* FIXME: Read Rx FIFO to clear RxFIFOFul */
+       if (sis & INT_RXFIFO_FUL)
+               dev_dbg(&pdev->dev, "isr: Rx FIFO full\n");
+
+       return IRQ_HANDLED;
+}
+
+static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
+{
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val, cycle = 1000;
+
+       regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
+
+       /*
+        * RESET bit would be cleared after finishing its reset procedure,
+        * which typically lasts 8 cycles. 1000 cycles will keep it safe.
+        */
+       do {
+               regmap_read(regmap, REG_SPDIF_SCR, &val);
+       } while ((val & SCR_SOFT_RESET) && cycle--);
+
+       if (cycle)
+               return 0;
+       else
+               return -EBUSY;
+}
+
+static void spdif_set_cstatus(struct spdif_mixer_control *ctrl,
+                               u8 mask, u8 cstatus)
+{
+       ctrl->ch_status[3] &= ~mask;
+       ctrl->ch_status[3] |= cstatus & mask;
+}
+
+static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv)
+{
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u32 ch_status;
+
+       ch_status = (bitrev8(ctrl->ch_status[0]) << 16) |
+               (bitrev8(ctrl->ch_status[1]) << 8) |
+               bitrev8(ctrl->ch_status[2]);
+       regmap_write(regmap, REG_SPDIF_STCSCH, ch_status);
+
+       dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status);
+
+       ch_status = bitrev8(ctrl->ch_status[3]) << 16;
+       regmap_write(regmap, REG_SPDIF_STCSCL, ch_status);
+
+       dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status);
+}
+
+/* Set SPDIF PhaseConfig register for rx clock */
+static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
+                               enum spdif_gainsel gainsel, int dpll_locked)
+{
+       struct regmap *regmap = spdif_priv->regmap;
+       u8 clksrc = spdif_priv->rxclk_src;
+
+       if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX)
+               return -EINVAL;
+
+       regmap_update_bits(regmap, REG_SPDIF_SRPC,
+                       SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
+                       SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));
+
+       return 0;
+}
+
+static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
+                               int sample_rate)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+       unsigned long csfs = 0;
+       u32 stc, mask, rate;
+       u8 clk, div;
+       int ret;
+
+       switch (sample_rate) {
+       case 32000:
+               rate = SPDIF_TXRATE_32000;
+               csfs = IEC958_AES3_CON_FS_32000;
+               break;
+       case 44100:
+               rate = SPDIF_TXRATE_44100;
+               csfs = IEC958_AES3_CON_FS_44100;
+               break;
+       case 48000:
+               rate = SPDIF_TXRATE_48000;
+               csfs = IEC958_AES3_CON_FS_48000;
+               break;
+       default:
+               dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate);
+               return -EINVAL;
+       }
+
+       clk = spdif_priv->txclk_src[rate];
+       if (clk >= STC_TXCLK_SRC_MAX) {
+               dev_err(&pdev->dev, "tx clock source is out of range\n");
+               return -EINVAL;
+       }
+
+       div = spdif_priv->txclk_div[rate];
+       if (div == 0) {
+               dev_err(&pdev->dev, "the divisor can't be zero\n");
+               return -EINVAL;
+       }
+
+       /*
+        * The S/PDIF block needs a clock of 64 * fs * div.  The S/PDIF block
+        * will divide by (div).  So request 64 * fs * (div+1) which will
+        * get rounded.
+        */
+       ret = clk_set_rate(spdif_priv->txclk[rate], 64 * sample_rate * (div + 1));
+       if (ret) {
+               dev_err(&pdev->dev, "failed to set tx clock rate\n");
+               return ret;
+       }
+
+       dev_dbg(&pdev->dev, "expected clock rate = %d\n",
+                       (64 * sample_rate * div));
+       dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
+                       clk_get_rate(spdif_priv->txclk[rate]));
+
+       /* set fs field in consumer channel status */
+       spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);
+
+       /* select clock source and divisor */
+       stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | STC_TXCLK_DIV(div);
+       mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | STC_TXCLK_DIV_MASK;
+       regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
+
+       dev_dbg(&pdev->dev, "set sample rate to %d\n", sample_rate);
+
+       return 0;
+}
+
+int fsl_spdif_startup(struct snd_pcm_substream *substream,
+                       struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct platform_device *pdev = spdif_priv->pdev;
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 scr, mask, i;
+       int ret;
+
+       /* Reset module and interrupts only for first initialization */
+       if (!cpu_dai->active) {
+               ret = spdif_softreset(spdif_priv);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to soft reset\n");
+                       return ret;
+               }
+
+               /* Disable all the interrupts */
+               regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0);
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL |
+                       SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP |
+                       SCR_TXFIFO_FSEL_IF8;
+               mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
+                       SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
+                       SCR_TXFIFO_FSEL_MASK;
+               for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+                       clk_prepare_enable(spdif_priv->txclk[i]);
+       } else {
+               scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
+               mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
+                       SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
+               clk_prepare_enable(spdif_priv->rxclk);
+       }
+       regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
+
+       /* Power up SPDIF module */
+       regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
+
+       return 0;
+}
+
+static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *cpu_dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 scr, mask, i;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               scr = 0;
+               mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
+                       SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
+                       SCR_TXFIFO_FSEL_MASK;
+               for (i = 0; i < SPDIF_TXRATE_MAX; i++)
+                       clk_disable_unprepare(spdif_priv->txclk[i]);
+       } else {
+               scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
+               mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
+                       SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
+               clk_disable_unprepare(spdif_priv->rxclk);
+       }
+       regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
+
+       /* Power down SPDIF module only if tx&rx are both inactive */
+       if (!cpu_dai->active) {
+               spdif_intr_status_clear(spdif_priv);
+               regmap_update_bits(regmap, REG_SPDIF_SCR,
+                               SCR_LOW_POWER, SCR_LOW_POWER);
+       }
+}
+
+static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u32 sample_rate = params_rate(params);
+       int ret = 0;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               ret  = spdif_set_sample_rate(substream, sample_rate);
+               if (ret) {
+                       dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
+                                       __func__, sample_rate);
+                       return ret;
+               }
+               spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK,
+                               IEC958_AES3_CON_CLOCK_1000PPM);
+               spdif_write_channel_status(spdif_priv);
+       } else {
+               /* Setup rx clock source */
+               ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1);
+       }
+
+       return ret;
+}
+
+static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
+                               int cmd, struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       int is_playack = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+       u32 intr = is_playack ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE;
+       u32 dmaen = is_playack ? SCR_DMA_TX_EN : SCR_DMA_RX_EN;;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr);
+               regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0);
+               regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+struct snd_soc_dai_ops fsl_spdif_dai_ops = {
+       .startup = fsl_spdif_startup,
+       .hw_params = fsl_spdif_hw_params,
+       .trigger = fsl_spdif_trigger,
+       .shutdown = fsl_spdif_shutdown,
+};
+
+
+/*
+ * ============================================
+ * FSL SPDIF IEC958 controller(mixer) functions
+ *
+ *     Channel status get/put control
+ *     User bit value get/put control
+ *     Valid bit value get control
+ *     DPLL lock status get control
+ *     User bit sync mode selection control
+ * ============================================
+ */
+
+static int fsl_spdif_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+
+       return 0;
+}
+
+static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *uvalue)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+
+       uvalue->value.iec958.status[0] = ctrl->ch_status[0];
+       uvalue->value.iec958.status[1] = ctrl->ch_status[1];
+       uvalue->value.iec958.status[2] = ctrl->ch_status[2];
+       uvalue->value.iec958.status[3] = ctrl->ch_status[3];
+
+       return 0;
+}
+
+static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *uvalue)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+
+       ctrl->ch_status[0] = uvalue->value.iec958.status[0];
+       ctrl->ch_status[1] = uvalue->value.iec958.status[1];
+       ctrl->ch_status[2] = uvalue->value.iec958.status[2];
+       ctrl->ch_status[3] = uvalue->value.iec958.status[3];
+
+       spdif_write_channel_status(spdif_priv);
+
+       return 0;
+}
+
+/* Get channel status from SPDIF_RX_CCHAN register */
+static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 cstatus, val;
+
+       regmap_read(regmap, REG_SPDIF_SIS, &val);
+       if (!(val & INT_CNEW)) {
+               return -EAGAIN;
+       }
+
+       regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus);
+       ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF;
+       ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF;
+       ucontrol->value.iec958.status[2] = cstatus & 0xFF;
+
+       regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus);
+       ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF;
+       ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF;
+       ucontrol->value.iec958.status[5] = cstatus & 0xFF;
+
+       /* Clear intr */
+       regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW);
+
+       return 0;
+}
+
+/*
+ * Get User bits (subcode) from chip value which readed out
+ * in UChannel register.
+ */
+static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&ctrl->ctl_lock, flags);
+       if (ctrl->ready_buf) {
+               int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
+               memcpy(&ucontrol->value.iec958.subcode[0],
+                               &ctrl->subcode[idx], SPDIF_UBITS_SIZE);
+       } else {
+               ret = -EAGAIN;
+       }
+       spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
+
+       return ret;
+}
+
+/* Q-subcode infomation. The byte size is SPDIF_UBITS_SIZE/8 */
+static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = SPDIF_QSUB_SIZE;
+
+       return 0;
+}
+
+/* Get Q subcode from chip value which readed out in QChannel register */
+static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&ctrl->ctl_lock, flags);
+       if (ctrl->ready_buf) {
+               int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
+               memcpy(&ucontrol->value.bytes.data[0],
+                               &ctrl->qsub[idx], SPDIF_QSUB_SIZE);
+       } else {
+               ret = -EAGAIN;
+       }
+       spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
+
+       return ret;
+}
+
+/* Valid bit infomation */
+static int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+/* Get valid good bit from interrupt status register */
+static int fsl_spdif_vbit_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val;
+
+       val = regmap_read(regmap, REG_SPDIF_SIS, &val);
+       ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0;
+       regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD);
+
+       return 0;
+}
+
+/* DPLL lock infomation */
+static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 16000;
+       uinfo->value.integer.max = 96000;
+
+       return 0;
+}
+
+static u32 gainsel_multi[GAINSEL_MULTI_MAX] = {
+       24, 16, 12, 8, 6, 4, 3,
+};
+
+/* Get RX data clock rate given the SPDIF bus_clk */
+static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
+                               enum spdif_gainsel gainsel)
+{
+       struct regmap *regmap = spdif_priv->regmap;
+       struct platform_device *pdev = spdif_priv->pdev;
+       u64 tmpval64, busclk_freq = 0;
+       u32 freqmeas, phaseconf;
+       u8 clksrc;
+
+       regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas);
+       regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf);
+
+       clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
+       if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) {
+               /* Get bus clock from system */
+               busclk_freq = clk_get_rate(spdif_priv->rxclk);
+       }
+
+       /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
+       tmpval64 = (u64) busclk_freq * freqmeas;
+       do_div(tmpval64, gainsel_multi[gainsel] * 1024);
+       do_div(tmpval64, 128 * 1024);
+
+       dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas);
+       dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq);
+       dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64);
+
+       return (int)tmpval64;
+}
+
+/*
+ * Get DPLL lock or not info from stable interrupt status register.
+ * User application must use this control to get locked,
+ * then can do next PCM operation
+ */
+static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       int rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);
+
+       if (spdif_priv->dpll_locked)
+               ucontrol->value.integer.value[0] = rate;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       return 0;
+}
+
+/* User bit sync mode info */
+static int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+
+       return 0;
+}
+
+/*
+ * User bit sync mode:
+ * 1 CD User channel subcode
+ * 0 Non-CD data
+ */
+static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val;
+
+       regmap_read(regmap, REG_SPDIF_SRCD, &val);
+       ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0;
+
+       return 0;
+}
+
+/*
+ * User bit sync mode:
+ * 1 CD User channel subcode
+ * 0 Non-CD data
+ */
+static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
+       struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
+       struct regmap *regmap = spdif_priv->regmap;
+       u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET;
+
+       regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val);
+
+       return 0;
+}
+
+/* FSL SPDIF IEC958 controller defines */
+static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
+       /* Status cchanel controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_WRITE |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_info,
+               .get = fsl_spdif_pb_get,
+               .put = fsl_spdif_pb_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_info,
+               .get = fsl_spdif_capture_get,
+       },
+       /* User bits controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "IEC958 Subcode Capture Default",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_info,
+               .get = fsl_spdif_subcode_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "IEC958 Q-subcode Capture Default",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_qinfo,
+               .get = fsl_spdif_qget,
+       },
+       /* Valid bit error controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "IEC958 V-Bit Errors",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_vbit_info,
+               .get = fsl_spdif_vbit_get,
+       },
+       /* DPLL lock info get controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "RX Sample Rate",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_rxrate_info,
+               .get = fsl_spdif_rxrate_get,
+       },
+       /* User bit sync mode set/get controller */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "IEC958 USyncMode CDText",
+               .access = SNDRV_CTL_ELEM_ACCESS_READ |
+                       SNDRV_CTL_ELEM_ACCESS_WRITE |
+                       SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .info = fsl_spdif_usync_info,
+               .get = fsl_spdif_usync_get,
+               .put = fsl_spdif_usync_put,
+       },
+};
+
+static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
+{
+       struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
+
+       dai->playback_dma_data = &spdif_private->dma_params_tx;
+       dai->capture_dma_data = &spdif_private->dma_params_rx;
+
+       snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
+
+       return 0;
+}
+
+struct snd_soc_dai_driver fsl_spdif_dai = {
+       .probe = &fsl_spdif_dai_probe,
+       .playback = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = FSL_SPDIF_RATES_PLAYBACK,
+               .formats = FSL_SPDIF_FORMATS_PLAYBACK,
+       },
+       .capture = {
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = FSL_SPDIF_RATES_CAPTURE,
+               .formats = FSL_SPDIF_FORMATS_CAPTURE,
+       },
+       .ops = &fsl_spdif_dai_ops,
+};
+
+static const struct snd_soc_component_driver fsl_spdif_component = {
+       .name           = "fsl-spdif",
+};
+
+/*
+ * ================
+ * FSL SPDIF REGMAP
+ * ================
+ */
+
+static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case REG_SPDIF_SCR:
+       case REG_SPDIF_SRCD:
+       case REG_SPDIF_SRPC:
+       case REG_SPDIF_SIE:
+       case REG_SPDIF_SIS:
+       case REG_SPDIF_SRL:
+       case REG_SPDIF_SRR:
+       case REG_SPDIF_SRCSH:
+       case REG_SPDIF_SRCSL:
+       case REG_SPDIF_SRU:
+       case REG_SPDIF_SRQ:
+       case REG_SPDIF_STCSCH:
+       case REG_SPDIF_STCSCL:
+       case REG_SPDIF_SRFM:
+       case REG_SPDIF_STC:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case REG_SPDIF_SCR:
+       case REG_SPDIF_SRCD:
+       case REG_SPDIF_SRPC:
+       case REG_SPDIF_SIE:
+       case REG_SPDIF_SIC:
+       case REG_SPDIF_STL:
+       case REG_SPDIF_STR:
+       case REG_SPDIF_STCSCH:
+       case REG_SPDIF_STCSCL:
+       case REG_SPDIF_STC:
+               return true;
+       default:
+               return false;
+       };
+}
+
+static const struct regmap_config fsl_spdif_regmap_config = {
+       .reg_bits = 32,
+       .reg_stride = 4,
+       .val_bits = 32,
+
+       .max_register = REG_SPDIF_STC,
+       .readable_reg = fsl_spdif_readable_reg,
+       .writeable_reg = fsl_spdif_writeable_reg,
+};
+
+static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
+                               struct clk *clk, u64 savesub,
+                               enum spdif_txrate index)
+{
+       const u32 rate[] = { 32000, 44100, 48000 };
+       u64 rate_ideal, rate_actual, sub;
+       u32 div, arate;
+
+       for (div = 1; div <= 128; div++) {
+               rate_ideal = rate[index] * (div + 1) * 64;
+               rate_actual = clk_round_rate(clk, rate_ideal);
+
+               arate = rate_actual / 64;
+               arate /= div;
+
+               if (arate == rate[index]) {
+                       /* We are lucky */
+                       savesub = 0;
+                       spdif_priv->txclk_div[index] = div;
+                       break;
+               } else if (arate / rate[index] == 1) {
+                       /* A little bigger than expect */
+                       sub = (arate - rate[index]) * 100000;
+                       do_div(sub, rate[index]);
+                       if (sub < savesub) {
+                               savesub = sub;
+                               spdif_priv->txclk_div[index] = div;
+                       }
+               } else if (rate[index] / arate == 1) {
+                       /* A little smaller than expect */
+                       sub = (rate[index] - arate) * 100000;
+                       do_div(sub, rate[index]);
+                       if (sub < savesub) {
+                               savesub = sub;
+                               spdif_priv->txclk_div[index] = div;
+                       }
+               }
+       }
+
+       return savesub;
+}
+
+static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
+                               enum spdif_txrate index)
+{
+       const u32 rate[] = { 32000, 44100, 48000 };
+       struct platform_device *pdev = spdif_priv->pdev;
+       struct device *dev = &pdev->dev;
+       u64 savesub = 100000, ret;
+       struct clk *clk;
+       char tmp[16];
+       int i;
+
+       for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
+               sprintf(tmp, "rxtx%d", i);
+               clk = devm_clk_get(&pdev->dev, tmp);
+               if (IS_ERR(clk)) {
+                       dev_err(dev, "no rxtx%d clock in devicetree\n", i);
+                       return PTR_ERR(clk);
+               }
+               if (!clk_get_rate(clk))
+                       continue;
+
+               ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index);
+               if (savesub == ret)
+                       continue;
+
+               savesub = ret;
+               spdif_priv->txclk[index] = clk;
+               spdif_priv->txclk_src[index] = i;
+
+               /* To quick catch a divisor, we allow a 0.1% deviation */
+               if (savesub < 100)
+                       break;
+       }
+
+       dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate",
+                       spdif_priv->txclk_src[index], rate[index]);
+       dev_dbg(&pdev->dev, "use divisor %d for %dHz sample rate",
+                       spdif_priv->txclk_div[index], rate[index]);
+
+       return 0;
+}
+
+static int fsl_spdif_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct fsl_spdif_priv *spdif_priv;
+       struct spdif_mixer_control *ctrl;
+       struct resource *res;
+       void __iomem *regs;
+       int irq, ret, i;
+
+       if (!np)
+               return -ENODEV;
+
+       spdif_priv = devm_kzalloc(&pdev->dev,
+                       sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1,
+                       GFP_KERNEL);
+       if (!spdif_priv)
+               return -ENOMEM;
+
+       strcpy(spdif_priv->name, np->name);
+
+       spdif_priv->pdev = pdev;
+
+       /* Initialize this copy of the CPU DAI driver structure */
+       memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
+       spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+
+       /* Get the addresses and IRQ */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (IS_ERR(res)) {
+               dev_err(&pdev->dev, "could not determine device resources\n");
+               return PTR_ERR(res);
+       }
+
+       regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(regs)) {
+               dev_err(&pdev->dev, "could not map device resources\n");
+               return PTR_ERR(regs);
+       }
+
+       spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev,
+                       "core", regs, &fsl_spdif_regmap_config);
+       if (IS_ERR(spdif_priv->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               return PTR_ERR(spdif_priv->regmap);
+       }
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
+                       spdif_priv->name, spdif_priv);
+       if (ret) {
+               dev_err(&pdev->dev, "could not claim irq %u\n", irq);
+               return ret;
+       }
+
+       /* Select clock source for rx/tx clock */
+       spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1");
+       if (IS_ERR(spdif_priv->rxclk)) {
+               dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n");
+               return PTR_ERR(spdif_priv->rxclk);
+       }
+       spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
+
+       for (i = 0; i < SPDIF_TXRATE_MAX; i++) {
+               ret = fsl_spdif_probe_txclk(spdif_priv, i);
+               if (ret)
+                       return ret;
+       }
+
+       /* Initial spinlock for control data */
+       ctrl = &spdif_priv->fsl_spdif_control;
+       spin_lock_init(&ctrl->ctl_lock);
+
+       /* Init tx channel status default value */
+       ctrl->ch_status[0] =
+               IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_5015;
+       ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID;
+       ctrl->ch_status[2] = 0x00;
+       ctrl->ch_status[3] =
+               IEC958_AES3_CON_FS_44100 | IEC958_AES3_CON_CLOCK_1000PPM;
+
+       spdif_priv->dpll_locked = false;
+
+       spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML;
+       spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML;
+       spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
+       spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
+
+       /* Register with ASoC */
+       dev_set_drvdata(&pdev->dev, spdif_priv);
+
+       ret = snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
+                                        &spdif_priv->cpu_dai_drv, 1);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
+               goto error_dev;
+       }
+
+       ret = imx_pcm_dma_init(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret);
+               goto error_component;
+       }
+
+       return ret;
+
+error_component:
+       snd_soc_unregister_component(&pdev->dev);
+error_dev:
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return ret;
+}
+
+static int fsl_spdif_remove(struct platform_device *pdev)
+{
+       imx_pcm_dma_exit(pdev);
+       snd_soc_unregister_component(&pdev->dev);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
+}
+
+static const struct of_device_id fsl_spdif_dt_ids[] = {
+       { .compatible = "fsl,imx35-spdif", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
+
+static struct platform_driver fsl_spdif_driver = {
+       .driver = {
+               .name = "fsl-spdif-dai",
+               .owner = THIS_MODULE,
+               .of_match_table = fsl_spdif_dt_ids,
+       },
+       .probe = fsl_spdif_probe,
+       .remove = fsl_spdif_remove,
+};
+
+module_platform_driver(fsl_spdif_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:fsl-spdif-dai");
diff --git a/sound/soc/fsl/fsl_spdif.h b/sound/soc/fsl/fsl_spdif.h
new file mode 100644 (file)
index 0000000..b126679
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * fsl_spdif.h - ALSA S/PDIF interface for the Freescale i.MX SoC
+ *
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Nicolin Chen <b42378@freescale.com>
+ *
+ * Based on fsl_ssi.h
+ * Author: Timur Tabi <timur@freescale.com>
+ * Copyright 2007-2008 Freescale Semiconductor, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program  is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _FSL_SPDIF_DAI_H
+#define _FSL_SPDIF_DAI_H
+
+/* S/PDIF Register Map */
+#define REG_SPDIF_SCR                  0x0     /* SPDIF Configuration Register */
+#define REG_SPDIF_SRCD                 0x4     /* CDText Control Register */
+#define REG_SPDIF_SRPC                 0x8     /* PhaseConfig Register */
+#define REG_SPDIF_SIE                  0xc     /* InterruptEn Register */
+#define REG_SPDIF_SIS                  0x10    /* InterruptStat Register */
+#define REG_SPDIF_SIC                  0x10    /* InterruptClear Register */
+#define REG_SPDIF_SRL                  0x14    /* SPDIFRxLeft Register */
+#define REG_SPDIF_SRR                  0x18    /* SPDIFRxRight Register */
+#define REG_SPDIF_SRCSH                        0x1c    /* SPDIFRxCChannel_h Register */
+#define REG_SPDIF_SRCSL                        0x20    /* SPDIFRxCChannel_l Register */
+#define REG_SPDIF_SRU                  0x24    /* UchannelRx Register */
+#define REG_SPDIF_SRQ                  0x28    /* QchannelRx Register */
+#define REG_SPDIF_STL                  0x2C    /* SPDIFTxLeft Register */
+#define REG_SPDIF_STR                  0x30    /* SPDIFTxRight Register */
+#define REG_SPDIF_STCSCH               0x34    /* SPDIFTxCChannelCons_h Register */
+#define REG_SPDIF_STCSCL               0x38    /* SPDIFTxCChannelCons_l Register */
+#define REG_SPDIF_SRFM                 0x44    /* FreqMeas Register */
+#define REG_SPDIF_STC                  0x50    /* SPDIFTxClk Register */
+
+
+/* SPDIF Configuration register */
+#define SCR_RXFIFO_CTL_OFFSET          23
+#define SCR_RXFIFO_CTL_MASK            (1 << SCR_RXFIFO_CTL_OFFSET)
+#define SCR_RXFIFO_CTL_ZERO            (1 << SCR_RXFIFO_CTL_OFFSET)
+#define SCR_RXFIFO_OFF_OFFSET          22
+#define SCR_RXFIFO_OFF_MASK            (1 << SCR_RXFIFO_OFF_OFFSET)
+#define SCR_RXFIFO_OFF                 (1 << SCR_RXFIFO_OFF_OFFSET)
+#define SCR_RXFIFO_RST_OFFSET          21
+#define SCR_RXFIFO_RST_MASK            (1 << SCR_RXFIFO_RST_OFFSET)
+#define SCR_RXFIFO_RST                 (1 << SCR_RXFIFO_RST_OFFSET)
+#define SCR_RXFIFO_FSEL_OFFSET         19
+#define SCR_RXFIFO_FSEL_MASK           (0x3 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF0            (0x0 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF4            (0x1 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF8            (0x2 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_FSEL_IF12           (0x3 << SCR_RXFIFO_FSEL_OFFSET)
+#define SCR_RXFIFO_AUTOSYNC_OFFSET     18
+#define SCR_RXFIFO_AUTOSYNC_MASK       (1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
+#define SCR_RXFIFO_AUTOSYNC            (1 << SCR_RXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_AUTOSYNC_OFFSET     17
+#define SCR_TXFIFO_AUTOSYNC_MASK       (1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_AUTOSYNC            (1 << SCR_TXFIFO_AUTOSYNC_OFFSET)
+#define SCR_TXFIFO_FSEL_OFFSET         15
+#define SCR_TXFIFO_FSEL_MASK           (0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF0            (0x0 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF4            (0x1 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF8            (0x2 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_TXFIFO_FSEL_IF12           (0x3 << SCR_TXFIFO_FSEL_OFFSET)
+#define SCR_LOW_POWER                  (1 << 13)
+#define SCR_SOFT_RESET                 (1 << 12)
+#define SCR_TXFIFO_CTRL_OFFSET         10
+#define SCR_TXFIFO_CTRL_MASK           (0x3 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_ZERO           (0x0 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_NORMAL         (0x1 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_TXFIFO_CTRL_ONESAMPLE      (0x2 << SCR_TXFIFO_CTRL_OFFSET)
+#define SCR_DMA_RX_EN_OFFSET           9
+#define SCR_DMA_RX_EN_MASK             (1 << SCR_DMA_RX_EN_OFFSET)
+#define SCR_DMA_RX_EN                  (1 << SCR_DMA_RX_EN_OFFSET)
+#define SCR_DMA_TX_EN_OFFSET           8
+#define SCR_DMA_TX_EN_MASK             (1 << SCR_DMA_TX_EN_OFFSET)
+#define SCR_DMA_TX_EN                  (1 << SCR_DMA_TX_EN_OFFSET)
+#define SCR_VAL_OFFSET                 5
+#define SCR_VAL_MASK                   (1 << SCR_VAL_OFFSET)
+#define SCR_VAL_CLEAR                  (1 << SCR_VAL_OFFSET)
+#define SCR_TXSEL_OFFSET               2
+#define SCR_TXSEL_MASK                 (0x7 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_OFF                  (0 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_RX                   (1 << SCR_TXSEL_OFFSET)
+#define SCR_TXSEL_NORMAL               (0x5 << SCR_TXSEL_OFFSET)
+#define SCR_USRC_SEL_OFFSET            0x0
+#define SCR_USRC_SEL_MASK              (0x3 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_NONE              (0x0 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_RECV              (0x1 << SCR_USRC_SEL_OFFSET)
+#define SCR_USRC_SEL_CHIP              (0x3 << SCR_USRC_SEL_OFFSET)
+
+/* SPDIF CDText control */
+#define SRCD_CD_USER_OFFSET            1
+#define SRCD_CD_USER                   (1 << SRCD_CD_USER_OFFSET)
+
+/* SPDIF Phase Configuration register */
+#define SRPC_DPLL_LOCKED               (1 << 6)
+#define SRPC_CLKSRC_SEL_OFFSET         7
+#define SRPC_CLKSRC_SEL_MASK           (0xf << SRPC_CLKSRC_SEL_OFFSET)
+#define SRPC_CLKSRC_SEL_SET(x)         ((x << SRPC_CLKSRC_SEL_OFFSET) & SRPC_CLKSRC_SEL_MASK)
+#define SRPC_CLKSRC_SEL_LOCKED_OFFSET1 5
+#define SRPC_CLKSRC_SEL_LOCKED_OFFSET2 2
+#define SRPC_GAINSEL_OFFSET            3
+#define SRPC_GAINSEL_MASK              (0x7 << SRPC_GAINSEL_OFFSET)
+#define SRPC_GAINSEL_SET(x)            ((x << SRPC_GAINSEL_OFFSET) & SRPC_GAINSEL_MASK)
+
+#define SRPC_CLKSRC_MAX                        16
+
+enum spdif_gainsel {
+       GAINSEL_MULTI_24 = 0,
+       GAINSEL_MULTI_16,
+       GAINSEL_MULTI_12,
+       GAINSEL_MULTI_8,
+       GAINSEL_MULTI_6,
+       GAINSEL_MULTI_4,
+       GAINSEL_MULTI_3,
+};
+#define GAINSEL_MULTI_MAX              (GAINSEL_MULTI_3 + 1)
+#define SPDIF_DEFAULT_GAINSEL          GAINSEL_MULTI_8
+
+/* SPDIF interrupt mask define */
+#define INT_DPLL_LOCKED                        (1 << 20)
+#define INT_TXFIFO_UNOV                        (1 << 19)
+#define INT_TXFIFO_RESYNC              (1 << 18)
+#define INT_CNEW                       (1 << 17)
+#define INT_VAL_NOGOOD                 (1 << 16)
+#define INT_SYM_ERR                    (1 << 15)
+#define INT_BIT_ERR                    (1 << 14)
+#define INT_URX_FUL                    (1 << 10)
+#define INT_URX_OV                     (1 << 9)
+#define INT_QRX_FUL                    (1 << 8)
+#define INT_QRX_OV                     (1 << 7)
+#define INT_UQ_SYNC                    (1 << 6)
+#define INT_UQ_ERR                     (1 << 5)
+#define INT_RXFIFO_UNOV                        (1 << 4)
+#define INT_RXFIFO_RESYNC              (1 << 3)
+#define INT_LOSS_LOCK                  (1 << 2)
+#define INT_TX_EM                      (1 << 1)
+#define INT_RXFIFO_FUL                 (1 << 0)
+
+/* SPDIF Clock register */
+#define STC_SYSCLK_DIV_OFFSET          11
+#define STC_SYSCLK_DIV_MASK            (0x1ff << STC_TXCLK_SRC_OFFSET)
+#define STC_SYSCLK_DIV(x)              ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_SYSCLK_DIV_MASK)
+#define STC_TXCLK_SRC_OFFSET           8
+#define STC_TXCLK_SRC_MASK             (0x7 << STC_TXCLK_SRC_OFFSET)
+#define STC_TXCLK_SRC_SET(x)           ((x << STC_TXCLK_SRC_OFFSET) & STC_TXCLK_SRC_MASK)
+#define STC_TXCLK_ALL_EN_OFFSET                7
+#define STC_TXCLK_ALL_EN_MASK          (1 << STC_TXCLK_ALL_EN_OFFSET)
+#define STC_TXCLK_ALL_EN               (1 << STC_TXCLK_ALL_EN_OFFSET)
+#define STC_TXCLK_DIV_OFFSET           0
+#define STC_TXCLK_DIV_MASK             (0x7ff << STC_TXCLK_DIV_OFFSET)
+#define STC_TXCLK_DIV(x)               ((((x) - 1) << STC_TXCLK_DIV_OFFSET) & STC_TXCLK_DIV_MASK)
+#define STC_TXCLK_SRC_MAX              8
+
+/* SPDIF tx rate */
+enum spdif_txrate {
+       SPDIF_TXRATE_32000 = 0,
+       SPDIF_TXRATE_44100,
+       SPDIF_TXRATE_48000,
+};
+#define SPDIF_TXRATE_MAX               (SPDIF_TXRATE_48000 + 1)
+
+
+#define SPDIF_CSTATUS_BYTE             6
+#define SPDIF_UBITS_SIZE               96
+#define SPDIF_QSUB_SIZE                        (SPDIF_UBITS_SIZE / 8)
+
+
+#define FSL_SPDIF_RATES_PLAYBACK       (SNDRV_PCM_RATE_32000 | \
+                                        SNDRV_PCM_RATE_44100 | \
+                                        SNDRV_PCM_RATE_48000)
+
+#define FSL_SPDIF_RATES_CAPTURE                (SNDRV_PCM_RATE_16000 | \
+                                        SNDRV_PCM_RATE_32000 | \
+                                        SNDRV_PCM_RATE_44100 | \
+                                        SNDRV_PCM_RATE_48000 | \
+                                        SNDRV_PCM_RATE_64000 | \
+                                        SNDRV_PCM_RATE_96000)
+
+#define FSL_SPDIF_FORMATS_PLAYBACK     (SNDRV_PCM_FMTBIT_S16_LE | \
+                                        SNDRV_PCM_FMTBIT_S20_3LE | \
+                                        SNDRV_PCM_FMTBIT_S24_LE)
+
+#define FSL_SPDIF_FORMATS_CAPTURE      (SNDRV_PCM_FMTBIT_S24_LE)
+
+#endif /* _FSL_SPDIF_DAI_H */
index 2f2d837..5cf626c 100644 (file)
@@ -8,6 +8,26 @@
  * This file is licensed under the terms of the GNU General Public License
  * version 2.  This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
+ *
+ *
+ * Some notes why imx-pcm-fiq is used instead of DMA on some boards:
+ *
+ * The i.MX SSI core has some nasty limitations in AC97 mode. While most
+ * sane processor vendors have a FIFO per AC97 slot, the i.MX has only
+ * one FIFO which combines all valid receive slots. We cannot even select
+ * which slots we want to receive. The WM9712 with which this driver
+ * was developed with always sends GPIO status data in slot 12 which
+ * we receive in our (PCM-) data stream. The only chance we have is to
+ * manually skip this data in the FIQ handler. With sampling rates different
+ * from 48000Hz not every frame has valid receive data, so the ratio
+ * between pcm data and GPIO status data changes. Our FIQ handler is not
+ * able to handle this, hence this driver only works with 48000Hz sampling
+ * rate.
+ * Reading and writing AC97 registers is another challenge. The core
+ * provides us status bits when the read register is updated with *another*
+ * value. When we read the same register two times (and the register still
+ * contains the same value) these status bits are not set. We work
+ * around this by not polling these bits but only wait a fixed delay.
  */
 
 #include <linux/init.h>
@@ -36,7 +56,7 @@
 #define read_ssi(addr)                  in_be32(addr)
 #define write_ssi(val, addr)            out_be32(addr, val)
 #define write_ssi_mask(addr, clear, set) clrsetbits_be32(addr, clear, set)
-#elif defined ARM
+#else
 #define read_ssi(addr)                  readl(addr)
 #define write_ssi(val, addr)            writel(val, addr)
 /*
@@ -121,11 +141,14 @@ struct fsl_ssi_private {
 
        bool new_binding;
        bool ssi_on_imx;
+       bool imx_ac97;
+       bool use_dma;
        struct clk *clk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
        struct imx_dma_data filter_data_tx;
        struct imx_dma_data filter_data_rx;
+       struct imx_pcm_fiq_params fiq_params;
 
        struct {
                unsigned int rfrc;
@@ -298,6 +321,102 @@ static irqreturn_t fsl_ssi_isr(int irq, void *dev_id)
        return ret;
 }
 
+static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
+{
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       u8 i2s_mode;
+       u8 wm;
+       int synchronous = ssi_private->cpu_dai_drv.symmetric_rates;
+
+       if (ssi_private->imx_ac97)
+               i2s_mode = CCSR_SSI_SCR_I2S_MODE_NORMAL | CCSR_SSI_SCR_NET;
+       else
+               i2s_mode = CCSR_SSI_SCR_I2S_MODE_SLAVE;
+
+       /*
+        * Section 16.5 of the MPC8610 reference manual says that the SSI needs
+        * to be disabled before updating the registers we set here.
+        */
+       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
+
+       /*
+        * Program the SSI into I2S Slave Non-Network Synchronous mode. Also
+        * enable the transmit and receive FIFO.
+        *
+        * FIXME: Little-endian samples require a different shift dir
+        */
+       write_ssi_mask(&ssi->scr,
+               CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
+               CCSR_SSI_SCR_TFR_CLK_DIS |
+               i2s_mode |
+               (synchronous ? CCSR_SSI_SCR_SYN : 0));
+
+       write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
+                CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
+                CCSR_SSI_STCR_TSCKP, &ssi->stcr);
+
+       write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
+                CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
+                CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
+       /*
+        * The DC and PM bits are only used if the SSI is the clock master.
+        */
+
+       /*
+        * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
+        * use FIFO 1. We program the transmit water to signal a DMA transfer
+        * if there are only two (or fewer) elements left in the FIFO. Two
+        * elements equals one frame (left channel, right channel). This value,
+        * however, depends on the depth of the transmit buffer.
+        *
+        * We set the watermark on the same level as the DMA burstsize.  For
+        * fiq it is probably better to use the biggest possible watermark
+        * size.
+        */
+       if (ssi_private->use_dma)
+               wm = ssi_private->fifo_depth - 2;
+       else
+               wm = ssi_private->fifo_depth;
+
+       write_ssi(CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
+               CCSR_SSI_SFCSR_TFWM1(wm) | CCSR_SSI_SFCSR_RFWM1(wm),
+               &ssi->sfcsr);
+
+       /*
+        * For ac97 interrupts are enabled with the startup of the substream
+        * because it is also running without an active substream. Normally SSI
+        * is only enabled when there is a substream.
+        */
+       if (ssi_private->imx_ac97) {
+               /*
+                * Setup the clock control register
+                */
+               write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+                               &ssi->stccr);
+               write_ssi(CCSR_SSI_SxCCR_WL(17) | CCSR_SSI_SxCCR_DC(13),
+                               &ssi->srccr);
+
+               /*
+                * Enable AC97 mode and startup the SSI
+                */
+               write_ssi(CCSR_SSI_SACNT_AC97EN | CCSR_SSI_SACNT_FV,
+                               &ssi->sacnt);
+               write_ssi(0xff, &ssi->saccdis);
+               write_ssi(0x300, &ssi->saccen);
+
+               /*
+                * Enable SSI, Transmit and Receive
+                */
+               write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_SSIEN |
+                               CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE);
+
+               write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
+       }
+
+       return 0;
+}
+
+
 /**
  * fsl_ssi_startup: create a new substream
  *
@@ -319,70 +438,14 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
         * and initialize the SSI registers.
         */
        if (!ssi_private->first_stream) {
-               struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
                ssi_private->first_stream = substream;
 
                /*
-                * Section 16.5 of the MPC8610 reference manual says that the
-                * SSI needs to be disabled before updating the registers we set
-                * here.
-                */
-               write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-
-               /*
-                * Program the SSI into I2S Slave Non-Network Synchronous mode.
-                * Also enable the transmit and receive FIFO.
-                *
-                * FIXME: Little-endian samples require a different shift dir
-                */
-               write_ssi_mask(&ssi->scr,
-                       CCSR_SSI_SCR_I2S_MODE_MASK | CCSR_SSI_SCR_SYN,
-                       CCSR_SSI_SCR_TFR_CLK_DIS | CCSR_SSI_SCR_I2S_MODE_SLAVE
-                       | (synchronous ? CCSR_SSI_SCR_SYN : 0));
-
-               write_ssi(CCSR_SSI_STCR_TXBIT0 | CCSR_SSI_STCR_TFEN0 |
-                        CCSR_SSI_STCR_TFSI | CCSR_SSI_STCR_TEFS |
-                        CCSR_SSI_STCR_TSCKP, &ssi->stcr);
-
-               write_ssi(CCSR_SSI_SRCR_RXBIT0 | CCSR_SSI_SRCR_RFEN0 |
-                        CCSR_SSI_SRCR_RFSI | CCSR_SSI_SRCR_REFS |
-                        CCSR_SSI_SRCR_RSCKP, &ssi->srcr);
-
-               /*
-                * The DC and PM bits are only used if the SSI is the clock
-                * master.
-                */
-
-               /* Enable the interrupts and DMA requests */
-               write_ssi(SIER_FLAGS, &ssi->sier);
-
-               /*
-                * Set the watermark for transmit FIFI 0 and receive FIFO 0. We
-                * don't use FIFO 1.  We program the transmit water to signal a
-                * DMA transfer if there are only two (or fewer) elements left
-                * in the FIFO.  Two elements equals one frame (left channel,
-                * right channel).  This value, however, depends on the depth of
-                * the transmit buffer.
-                *
-                * We program the receive FIFO to notify us if at least two
-                * elements (one frame) have been written to the FIFO.  We could
-                * make this value larger (and maybe we should), but this way
-                * data will be written to memory as soon as it's available.
-                */
-               write_ssi(CCSR_SSI_SFCSR_TFWM0(ssi_private->fifo_depth - 2) |
-                       CCSR_SSI_SFCSR_RFWM0(ssi_private->fifo_depth - 2),
-                       &ssi->sfcsr);
-
-               /*
-                * We keep the SSI disabled because if we enable it, then the
-                * DMA controller will start.  It's not supposed to start until
-                * the SCR.TE (or SCR.RE) bit is set, but it does anyway.  The
-                * DMA controller will transfer one "BWC" of data (i.e. the
-                * amount of data that the MR.BWC bits are set to).  The reason
-                * this is bad is because at this point, the PCM driver has not
-                * finished initializing the DMA controller.
+                * fsl_ssi_setup was already called by ac97_init earlier if
+                * the driver is in ac97 mode.
                 */
+               if (!ssi_private->imx_ac97)
+                       fsl_ssi_setup(ssi_private);
        } else {
                if (synchronous) {
                        struct snd_pcm_runtime *first_runtime =
@@ -492,6 +555,27 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+       unsigned int sier_bits;
+
+       /*
+        *  Enable only the interrupts and DMA requests
+        *  that are needed for the channel. As the fiq
+        *  is polling for this bits, we have to ensure
+        *  that this are aligned with the preallocated
+        *  buffers
+        */
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (ssi_private->use_dma)
+                       sier_bits = SIER_FLAGS;
+               else
+                       sier_bits = CCSR_SSI_SIER_TIE | CCSR_SSI_SIER_TFE0_EN;
+       } else {
+               if (ssi_private->use_dma)
+                       sier_bits = SIER_FLAGS;
+               else
+                       sier_bits = CCSR_SSI_SIER_RIE | CCSR_SSI_SIER_RFF0_EN;
+       }
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -510,12 +594,18 @@ static int fsl_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                        write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_TE, 0);
                else
                        write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_RE, 0);
+
+               if (!ssi_private->imx_ac97 && (read_ssi(&ssi->scr) &
+                                       (CCSR_SSI_SCR_TE | CCSR_SSI_SCR_RE)) == 0)
+                       write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
                break;
 
        default:
                return -EINVAL;
        }
 
+       write_ssi(sier_bits, &ssi->sier);
+
        return 0;
 }
 
@@ -534,22 +624,13 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
                ssi_private->first_stream = ssi_private->second_stream;
 
        ssi_private->second_stream = NULL;
-
-       /*
-        * If this is the last active substream, disable the SSI.
-        */
-       if (!ssi_private->first_stream) {
-               struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
-
-               write_ssi_mask(&ssi->scr, CCSR_SSI_SCR_SSIEN, 0);
-       }
 }
 
 static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
 {
        struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
 
-       if (ssi_private->ssi_on_imx) {
+       if (ssi_private->ssi_on_imx && ssi_private->use_dma) {
                dai->playback_dma_data = &ssi_private->dma_params_tx;
                dai->capture_dma_data = &ssi_private->dma_params_rx;
        }
@@ -587,6 +668,133 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
        .name           = "fsl-ssi",
 };
 
+/**
+ * fsl_ssi_ac97_trigger: start and stop the AC97 receive/transmit.
+ *
+ * This function is called by ALSA to start, stop, pause, and resume the
+ * transfer of data.
+ */
+static int fsl_ssi_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
+                          struct snd_soc_dai *dai)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(
+                       rtd->cpu_dai);
+       struct ccsr_ssi __iomem *ssi = ssi_private->ssi;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_TIE |
+                                       CCSR_SSI_SIER_TFE0_EN);
+               else
+                       write_ssi_mask(&ssi->sier, 0, CCSR_SSI_SIER_RIE |
+                                       CCSR_SSI_SIER_RFF0_EN);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_TIE |
+                                       CCSR_SSI_SIER_TFE0_EN, 0);
+               else
+                       write_ssi_mask(&ssi->sier, CCSR_SSI_SIER_RIE |
+                                       CCSR_SSI_SIER_RFF0_EN, 0);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               write_ssi(CCSR_SSI_SOR_TX_CLR, &ssi->sor);
+       else
+               write_ssi(CCSR_SSI_SOR_RX_CLR, &ssi->sor);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops fsl_ssi_ac97_dai_ops = {
+       .startup        = fsl_ssi_startup,
+       .shutdown       = fsl_ssi_shutdown,
+       .trigger        = fsl_ssi_ac97_trigger,
+};
+
+static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
+       .ac97_control = 1,
+       .playback = {
+               .stream_name = "AC97 Playback",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_8000_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .capture = {
+               .stream_name = "AC97 Capture",
+               .channels_min = 2,
+               .channels_max = 2,
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       },
+       .ops = &fsl_ssi_ac97_dai_ops,
+};
+
+
+static struct fsl_ssi_private *fsl_ac97_data;
+
+static void fsl_ssi_ac97_init(void)
+{
+       fsl_ssi_setup(fsl_ac97_data);
+}
+
+void fsl_ssi_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+               unsigned short val)
+{
+       struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
+       unsigned int lreg;
+       unsigned int lval;
+
+       if (reg > 0x7f)
+               return;
+
+
+       lreg = reg <<  12;
+       write_ssi(lreg, &ssi->sacadd);
+
+       lval = val << 4;
+       write_ssi(lval , &ssi->sacdat);
+
+       write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK,
+                       CCSR_SSI_SACNT_WR);
+       udelay(100);
+}
+
+unsigned short fsl_ssi_ac97_read(struct snd_ac97 *ac97,
+               unsigned short reg)
+{
+       struct ccsr_ssi *ssi = fsl_ac97_data->ssi;
+
+       unsigned short val = -1;
+       unsigned int lreg;
+
+       lreg = (reg & 0x7f) <<  12;
+       write_ssi(lreg, &ssi->sacadd);
+       write_ssi_mask(&ssi->sacnt, CCSR_SSI_SACNT_RDWR_MASK,
+                       CCSR_SSI_SACNT_RD);
+
+       udelay(100);
+
+       val = (read_ssi(&ssi->sacdat) >> 4) & 0xffff;
+
+       return val;
+}
+
+static struct snd_ac97_bus_ops fsl_ssi_ac97_ops = {
+       .read           = fsl_ssi_ac97_read,
+       .write          = fsl_ssi_ac97_write,
+};
+
 /* Show the statistics of a flag only if its interrupt is enabled.  The
  * compiler will optimze this code to a no-op if the interrupt is not
  * enabled.
@@ -663,6 +871,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        struct resource res;
        char name[64];
        bool shared;
+       bool ac97 = false;
 
        /* SSIs that are not connected on the board should have a
         *      status = "disabled"
@@ -673,14 +882,20 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        /* We only support the SSI in "I2S Slave" mode */
        sprop = of_get_property(np, "fsl,mode", NULL);
-       if (!sprop || strcmp(sprop, "i2s-slave")) {
+       if (!sprop) {
+               dev_err(&pdev->dev, "fsl,mode property is necessary\n");
+               return -EINVAL;
+       }
+       if (!strcmp(sprop, "ac97-slave")) {
+               ac97 = true;
+       } else if (strcmp(sprop, "i2s-slave")) {
                dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
                return -ENODEV;
        }
 
        /* The DAI name is the last part of the full name of the node. */
        p = strrchr(np->full_name, '/') + 1;
-       ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
+       ssi_private = devm_kzalloc(&pdev->dev, sizeof(*ssi_private) + strlen(p),
                              GFP_KERNEL);
        if (!ssi_private) {
                dev_err(&pdev->dev, "could not allocate DAI object\n");
@@ -689,38 +904,41 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        strcpy(ssi_private->name, p);
 
-       /* Initialize this copy of the CPU DAI driver structure */
-       memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
-              sizeof(fsl_ssi_dai_template));
+       ssi_private->use_dma = !of_property_read_bool(np,
+                       "fsl,fiq-stream-filter");
+
+       if (ac97) {
+               memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_ac97_dai,
+                               sizeof(fsl_ssi_ac97_dai));
+
+               fsl_ac97_data = ssi_private;
+               ssi_private->imx_ac97 = true;
+
+               snd_soc_set_ac97_ops_of_reset(&fsl_ssi_ac97_ops, pdev);
+       } else {
+               /* Initialize this copy of the CPU DAI driver structure */
+               memcpy(&ssi_private->cpu_dai_drv, &fsl_ssi_dai_template,
+                      sizeof(fsl_ssi_dai_template));
+       }
        ssi_private->cpu_dai_drv.name = ssi_private->name;
 
        /* Get the addresses and IRQ */
        ret = of_address_to_resource(np, 0, &res);
        if (ret) {
                dev_err(&pdev->dev, "could not determine device resources\n");
-               goto error_kmalloc;
+               return ret;
        }
        ssi_private->ssi = of_iomap(np, 0);
        if (!ssi_private->ssi) {
                dev_err(&pdev->dev, "could not map device resources\n");
-               ret = -ENOMEM;
-               goto error_kmalloc;
+               return -ENOMEM;
        }
        ssi_private->ssi_phys = res.start;
 
        ssi_private->irq = irq_of_parse_and_map(np, 0);
        if (ssi_private->irq == NO_IRQ) {
                dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
-               ret = -ENXIO;
-               goto error_iomap;
-       }
-
-       /* The 'name' should not have any slashes in it. */
-       ret = request_irq(ssi_private->irq, fsl_ssi_isr, 0, ssi_private->name,
-                         ssi_private);
-       if (ret < 0) {
-               dev_err(&pdev->dev, "could not claim irq %u\n", ssi_private->irq);
-               goto error_irqmap;
+               return -ENXIO;
        }
 
        /* Are the RX and the TX clocks locked? */
@@ -739,13 +957,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                u32 dma_events[2];
                ssi_private->ssi_on_imx = true;
 
-               ssi_private->clk = clk_get(&pdev->dev, NULL);
+               ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
                if (IS_ERR(ssi_private->clk)) {
                        ret = PTR_ERR(ssi_private->clk);
                        dev_err(&pdev->dev, "could not get clock: %d\n", ret);
-                       goto error_irq;
+                       goto error_irqmap;
+               }
+               ret = clk_prepare_enable(ssi_private->clk);
+               if (ret) {
+                       dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n",
+                               ret);
+                       goto error_irqmap;
                }
-               clk_prepare_enable(ssi_private->clk);
 
                /*
                 * We have burstsize be "fifo_depth - 2" to match the SSI
@@ -763,24 +986,38 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                        &ssi_private->filter_data_tx;
                ssi_private->dma_params_rx.filter_data =
                        &ssi_private->filter_data_rx;
-               /*
-                * TODO: This is a temporary solution and should be changed
-                * to use generic DMA binding later when the helplers get in.
-                */
-               ret = of_property_read_u32_array(pdev->dev.of_node,
+               if (!of_property_read_bool(pdev->dev.of_node, "dmas") &&
+                               ssi_private->use_dma) {
+                       /*
+                        * FIXME: This is a temporary solution until all
+                        * necessary dma drivers support the generic dma
+                        * bindings.
+                        */
+                       ret = of_property_read_u32_array(pdev->dev.of_node,
                                        "fsl,ssi-dma-events", dma_events, 2);
-               if (ret) {
-                       dev_err(&pdev->dev, "could not get dma events\n");
-                       goto error_clk;
+                       if (ret && ssi_private->use_dma) {
+                               dev_err(&pdev->dev, "could not get dma events but fsl-ssi is configured to use DMA\n");
+                               goto error_clk;
+                       }
                }
 
                shared = of_device_is_compatible(of_get_parent(np),
                            "fsl,spba-bus");
 
                imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
-                       dma_events[0], shared);
+                       dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
                imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
-                       dma_events[1], shared);
+                       dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
+       } else if (ssi_private->use_dma) {
+               /* The 'name' should not have any slashes in it. */
+               ret = devm_request_irq(&pdev->dev, ssi_private->irq,
+                                       fsl_ssi_isr, 0, ssi_private->name,
+                                       ssi_private);
+               if (ret < 0) {
+                       dev_err(&pdev->dev, "could not claim irq %u\n",
+                                       ssi_private->irq);
+                       goto error_irqmap;
+               }
        }
 
        /* Initialize the the device_attribute structure */
@@ -794,7 +1031,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "could not create sysfs %s file\n",
                        ssi_private->dev_attr.attr.name);
-               goto error_irq;
+               goto error_clk;
        }
 
        /* Register with ASoC */
@@ -808,9 +1045,30 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
        if (ssi_private->ssi_on_imx) {
-               ret = imx_pcm_dma_init(pdev);
-               if (ret)
-                       goto error_dev;
+               if (!ssi_private->use_dma) {
+
+                       /*
+                        * Some boards use an incompatible codec. To get it
+                        * working, we are using imx-fiq-pcm-audio, that
+                        * can handle those codecs. DMA is not possible in this
+                        * situation.
+                        */
+
+                       ssi_private->fiq_params.irq = ssi_private->irq;
+                       ssi_private->fiq_params.base = ssi_private->ssi;
+                       ssi_private->fiq_params.dma_params_rx =
+                               &ssi_private->dma_params_rx;
+                       ssi_private->fiq_params.dma_params_tx =
+                               &ssi_private->dma_params_tx;
+
+                       ret = imx_pcm_fiq_init(pdev, &ssi_private->fiq_params);
+                       if (ret)
+                               goto error_dev;
+               } else {
+                       ret = imx_pcm_dma_init(pdev);
+                       if (ret)
+                               goto error_dev;
+               }
        }
 
        /*
@@ -845,6 +1103,9 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        }
 
 done:
+       if (ssi_private->imx_ac97)
+               fsl_ssi_ac97_init();
+
        return 0;
 
 error_dai:
@@ -857,23 +1118,12 @@ error_dev:
        device_remove_file(&pdev->dev, dev_attr);
 
 error_clk:
-       if (ssi_private->ssi_on_imx) {
+       if (ssi_private->ssi_on_imx)
                clk_disable_unprepare(ssi_private->clk);
-               clk_put(ssi_private->clk);
-       }
-
-error_irq:
-       free_irq(ssi_private->irq, ssi_private);
 
 error_irqmap:
        irq_dispose_mapping(ssi_private->irq);
 
-error_iomap:
-       iounmap(ssi_private->ssi);
-
-error_kmalloc:
-       kfree(ssi_private);
-
        return ret;
 }
 
@@ -883,20 +1133,15 @@ static int fsl_ssi_remove(struct platform_device *pdev)
 
        if (!ssi_private->new_binding)
                platform_device_unregister(ssi_private->pdev);
-       if (ssi_private->ssi_on_imx) {
+       if (ssi_private->ssi_on_imx)
                imx_pcm_dma_exit(pdev);
-               clk_disable_unprepare(ssi_private->clk);
-               clk_put(ssi_private->clk);
-       }
        snd_soc_unregister_component(&pdev->dev);
+       dev_set_drvdata(&pdev->dev, NULL);
        device_remove_file(&pdev->dev, &ssi_private->dev_attr);
-
-       free_irq(ssi_private->irq, ssi_private);
+       if (ssi_private->ssi_on_imx)
+               clk_disable_unprepare(ssi_private->clk);
        irq_dispose_mapping(ssi_private->irq);
 
-       kfree(ssi_private);
-       dev_set_drvdata(&pdev->dev, NULL);
-
        return 0;
 }
 
@@ -919,6 +1164,7 @@ static struct platform_driver fsl_ssi_driver = {
 
 module_platform_driver(fsl_ssi_driver);
 
+MODULE_ALIAS("platform:fsl-ssi-dai");
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale Synchronous Serial Interface (SSI) ASoC Driver");
 MODULE_LICENSE("GPL v2");
index e260f1f..ab17381 100644 (file)
@@ -73,8 +73,11 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       if (audmux_clk)
-               clk_prepare_enable(audmux_clk);
+       if (audmux_clk) {
+               ret = clk_prepare_enable(audmux_clk);
+               if (ret)
+                       return ret;
+       }
 
        ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port));
        pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port));
@@ -224,14 +227,19 @@ EXPORT_SYMBOL_GPL(imx_audmux_v1_configure_port);
 int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
                unsigned int pdcr)
 {
+       int ret;
+
        if (audmux_type != IMX31_AUDMUX)
                return -EINVAL;
 
        if (!audmux_base)
                return -ENOSYS;
 
-       if (audmux_clk)
-               clk_prepare_enable(audmux_clk);
+       if (audmux_clk) {
+               ret = clk_prepare_enable(audmux_clk);
+               if (ret)
+                       return ret;
+       }
 
        writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port));
        writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port));
@@ -243,6 +251,66 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
 }
 EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
 
+static int imx_audmux_parse_dt_defaults(struct platform_device *pdev,
+               struct device_node *of_node)
+{
+       struct device_node *child;
+
+       for_each_available_child_of_node(of_node, child) {
+               unsigned int port;
+               unsigned int ptcr = 0;
+               unsigned int pdcr = 0;
+               unsigned int pcr = 0;
+               unsigned int val;
+               int ret;
+               int i = 0;
+
+               ret = of_property_read_u32(child, "fsl,audmux-port", &port);
+               if (ret) {
+                       dev_warn(&pdev->dev, "Failed to get fsl,audmux-port of child node \"%s\"\n",
+                                       child->full_name);
+                       continue;
+               }
+               if (!of_property_read_bool(child, "fsl,port-config")) {
+                       dev_warn(&pdev->dev, "child node \"%s\" does not have property fsl,port-config\n",
+                                       child->full_name);
+                       continue;
+               }
+
+               for (i = 0; (ret = of_property_read_u32_index(child,
+                                       "fsl,port-config", i, &val)) == 0;
+                               ++i) {
+                       if (audmux_type == IMX31_AUDMUX) {
+                               if (i % 2)
+                                       pdcr |= val;
+                               else
+                                       ptcr |= val;
+                       } else {
+                               pcr |= val;
+                       }
+               }
+
+               if (ret != -EOVERFLOW) {
+                       dev_err(&pdev->dev, "Failed to read u32 at index %d of child %s\n",
+                                       i, child->full_name);
+                       continue;
+               }
+
+               if (audmux_type == IMX31_AUDMUX) {
+                       if (i % 2) {
+                               dev_err(&pdev->dev, "One pdcr value is missing in child node %s\n",
+                                               child->full_name);
+                               continue;
+                       }
+                       imx_audmux_v2_configure_port(port, ptcr, pdcr);
+               } else {
+                       imx_audmux_v1_configure_port(port, pcr);
+               }
+       }
+
+       return 0;
+}
+
 static int imx_audmux_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -267,6 +335,8 @@ static int imx_audmux_probe(struct platform_device *pdev)
        if (audmux_type == IMX31_AUDMUX)
                audmux_debugfs_init();
 
+       imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
+
        return 0;
 }
 
index b8ff44b..38a4209 100644 (file)
@@ -1,57 +1,7 @@
 #ifndef __IMX_AUDMUX_H
 #define __IMX_AUDMUX_H
 
-#define MX27_AUDMUX_HPCR1_SSI0         0
-#define MX27_AUDMUX_HPCR2_SSI1         1
-#define MX27_AUDMUX_HPCR3_SSI_PINS_4   2
-#define MX27_AUDMUX_PPCR1_SSI_PINS_1   3
-#define MX27_AUDMUX_PPCR2_SSI_PINS_2   4
-#define MX27_AUDMUX_PPCR3_SSI_PINS_3   5
-
-#define MX31_AUDMUX_PORT1_SSI0         0
-#define MX31_AUDMUX_PORT2_SSI1         1
-#define MX31_AUDMUX_PORT3_SSI_PINS_3   2
-#define MX31_AUDMUX_PORT4_SSI_PINS_4   3
-#define MX31_AUDMUX_PORT5_SSI_PINS_5   4
-#define MX31_AUDMUX_PORT6_SSI_PINS_6   5
-#define MX31_AUDMUX_PORT7_SSI_PINS_7   6
-
-#define MX51_AUDMUX_PORT1_SSI0         0
-#define MX51_AUDMUX_PORT2_SSI1         1
-#define MX51_AUDMUX_PORT3              2
-#define MX51_AUDMUX_PORT4              3
-#define MX51_AUDMUX_PORT5              4
-#define MX51_AUDMUX_PORT6              5
-#define MX51_AUDMUX_PORT7              6
-
-/* Register definitions for the i.MX21/27 Digital Audio Multiplexer */
-#define IMX_AUDMUX_V1_PCR_INMMASK(x)   ((x) & 0xff)
-#define IMX_AUDMUX_V1_PCR_INMEN                (1 << 8)
-#define IMX_AUDMUX_V1_PCR_TXRXEN       (1 << 10)
-#define IMX_AUDMUX_V1_PCR_SYN          (1 << 12)
-#define IMX_AUDMUX_V1_PCR_RXDSEL(x)    (((x) & 0x7) << 13)
-#define IMX_AUDMUX_V1_PCR_RFCSEL(x)    (((x) & 0xf) << 20)
-#define IMX_AUDMUX_V1_PCR_RCLKDIR      (1 << 24)
-#define IMX_AUDMUX_V1_PCR_RFSDIR       (1 << 25)
-#define IMX_AUDMUX_V1_PCR_TFCSEL(x)    (((x) & 0xf) << 26)
-#define IMX_AUDMUX_V1_PCR_TCLKDIR      (1 << 30)
-#define IMX_AUDMUX_V1_PCR_TFSDIR       (1 << 31)
-
-/* Register definitions for the i.MX25/31/35/51 Digital Audio Multiplexer */
-#define IMX_AUDMUX_V2_PTCR_TFSDIR      (1 << 31)
-#define IMX_AUDMUX_V2_PTCR_TFSEL(x)    (((x) & 0xf) << 27)
-#define IMX_AUDMUX_V2_PTCR_TCLKDIR     (1 << 26)
-#define IMX_AUDMUX_V2_PTCR_TCSEL(x)    (((x) & 0xf) << 22)
-#define IMX_AUDMUX_V2_PTCR_RFSDIR      (1 << 21)
-#define IMX_AUDMUX_V2_PTCR_RFSEL(x)    (((x) & 0xf) << 17)
-#define IMX_AUDMUX_V2_PTCR_RCLKDIR     (1 << 16)
-#define IMX_AUDMUX_V2_PTCR_RCSEL(x)    (((x) & 0xf) << 12)
-#define IMX_AUDMUX_V2_PTCR_SYN         (1 << 11)
-
-#define IMX_AUDMUX_V2_PDCR_RXDSEL(x)   (((x) & 0x7) << 13)
-#define IMX_AUDMUX_V2_PDCR_TXRXEN      (1 << 12)
-#define IMX_AUDMUX_V2_PDCR_MODE(x)     (((x) & 0x3) << 8)
-#define IMX_AUDMUX_V2_PDCR_INMMASK(x)  ((x) & 0xff)
+#include <dt-bindings/sound/fsl-imx-audmux.h>
 
 int imx_audmux_v1_configure_port(unsigned int port, unsigned int pcr);
 
index 9df173c..a3d60d4 100644 (file)
@@ -90,6 +90,7 @@ static const struct snd_soc_dapm_route imx_mc13783_routes[] = {
 
 static struct snd_soc_card imx_mc13783 = {
        .name           = "imx_mc13783",
+       .owner          = THIS_MODULE,
        .dai_link       = imx_mc13783_dai_mc13783,
        .num_links      = ARRAY_SIZE(imx_mc13783_dai_mc13783),
        .dapm_widgets   = imx_mc13783_widget,
index fde4d2e..4dc1296 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
 #include <linux/types.h>
+#include <linux/module.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -64,7 +65,6 @@ int imx_pcm_dma_init(struct platform_device *pdev)
 {
        return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
                SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
-               SND_DMAENGINE_PCM_FLAG_NO_DT |
                SND_DMAENGINE_PCM_FLAG_COMPAT);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_dma_init);
@@ -74,3 +74,5 @@ void imx_pcm_dma_exit(struct platform_device *pdev)
        snd_dmaengine_pcm_unregister(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_dma_exit);
+
+MODULE_LICENSE("GPL");
index 310d902..34043c5 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 
 #include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -32,6 +33,7 @@
 #include <linux/platform_data/asoc-imx-ssi.h>
 
 #include "imx-ssi.h"
+#include "imx-pcm.h"
 
 struct imx_pcm_runtime_data {
        unsigned int period;
@@ -366,9 +368,9 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = {
        .pcm_free       = imx_pcm_fiq_free,
 };
 
-int imx_pcm_fiq_init(struct platform_device *pdev)
+int imx_pcm_fiq_init(struct platform_device *pdev,
+               struct imx_pcm_fiq_params *params)
 {
-       struct imx_ssi *ssi = platform_get_drvdata(pdev);
        int ret;
 
        ret = claim_fiq(&fh);
@@ -377,15 +379,15 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
                return ret;
        }
 
-       mxc_set_irq_fiq(ssi->irq, 1);
-       ssi_irq = ssi->irq;
+       mxc_set_irq_fiq(params->irq, 1);
+       ssi_irq = params->irq;
 
-       imx_pcm_fiq = ssi->irq;
+       imx_pcm_fiq = params->irq;
 
-       imx_ssi_fiq_base = (unsigned long)ssi->base;
+       imx_ssi_fiq_base = (unsigned long)params->base;
 
-       ssi->dma_params_tx.maxburst = 4;
-       ssi->dma_params_rx.maxburst = 6;
+       params->dma_params_tx->maxburst = 4;
+       params->dma_params_rx->maxburst = 6;
 
        ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
        if (ret)
@@ -406,3 +408,5 @@ void imx_pcm_fiq_exit(struct platform_device *pdev)
        snd_soc_unregister_platform(&pdev->dev);
 }
 EXPORT_SYMBOL_GPL(imx_pcm_fiq_exit);
+
+MODULE_LICENSE("GPL");
index 67f656c..5d5b733 100644 (file)
 
 static inline void
 imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
-       int dma, bool shared)
+       int dma, enum sdma_peripheral_type peripheral_type)
 {
        dma_data->dma_request = dma;
        dma_data->priority = DMA_PRIO_HIGH;
-       if (shared)
-               dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
-       else
-               dma_data->peripheral_type = IMX_DMATYPE_SSI;
+       dma_data->peripheral_type = peripheral_type;
 }
 
-#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
+struct imx_pcm_fiq_params {
+       int irq;
+       void __iomem *base;
+
+       /* Pointer to original ssi driver to setup tx rx sizes */
+       struct snd_dmaengine_dai_dma_data *dma_params_rx;
+       struct snd_dmaengine_dai_dma_data *dma_params_tx;
+};
+
+#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)
 int imx_pcm_dma_init(struct platform_device *pdev);
 void imx_pcm_dma_exit(struct platform_device *pdev);
 #else
@@ -46,11 +52,13 @@ static inline void imx_pcm_dma_exit(struct platform_device *pdev)
 }
 #endif
 
-#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
-int imx_pcm_fiq_init(struct platform_device *pdev);
+#if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_FIQ)
+int imx_pcm_fiq_init(struct platform_device *pdev,
+               struct imx_pcm_fiq_params *params);
 void imx_pcm_fiq_exit(struct platform_device *pdev);
 #else
-static inline int imx_pcm_fiq_init(struct platform_device *pdev)
+static inline int imx_pcm_fiq_init(struct platform_device *pdev,
+               struct imx_pcm_fiq_params *params)
 {
        return -ENODEV;
 }
index 3f726e4..389cbfa 100644 (file)
@@ -129,8 +129,10 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        }
 
        data->codec_clk = devm_clk_get(&codec_dev->dev, NULL);
-       if (IS_ERR(data->codec_clk))
+       if (IS_ERR(data->codec_clk)) {
+               ret = PTR_ERR(data->codec_clk);
                goto fail;
+       }
 
        data->clk_frequency = clk_get_rate(data->codec_clk);
 
index 51be377..f58bcd8 100644 (file)
@@ -571,13 +571,13 @@ static int imx_ssi_probe(struct platform_device *pdev)
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
        if (res) {
                imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
-                       false);
+                       IMX_DMATYPE_SSI);
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
        if (res) {
                imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
-                       false);
+                       IMX_DMATYPE_SSI);
        }
 
        platform_set_drvdata(pdev, ssi);
@@ -595,7 +595,12 @@ static int imx_ssi_probe(struct platform_device *pdev)
                goto failed_register;
        }
 
-       ret = imx_pcm_fiq_init(pdev);
+       ssi->fiq_params.irq = ssi->irq;
+       ssi->fiq_params.base = ssi->base;
+       ssi->fiq_params.dma_params_rx = &ssi->dma_params_rx;
+       ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx;
+
+       ret = imx_pcm_fiq_init(pdev, &ssi->fiq_params);
        if (ret)
                goto failed_pcm_fiq;
 
index d5003ce..fb1616b 100644 (file)
@@ -209,6 +209,7 @@ struct imx_ssi {
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct imx_dma_data filter_data_tx;
        struct imx_dma_data filter_data_rx;
+       struct imx_pcm_fiq_params fiq_params;
 
        int enabled;
 };
index 52a36a9..1d70e27 100644 (file)
@@ -217,7 +217,8 @@ static int imx_wm8962_probe(struct platform_device *pdev)
        codec_dev = of_find_i2c_device_by_node(codec_np);
        if (!codec_dev || !codec_dev->driver) {
                dev_err(&pdev->dev, "failed to find codec platform device\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto fail;
        }
 
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
index c62d715..9e1970c 100644 (file)
@@ -1,19 +1,15 @@
 config SND_KIRKWOOD_SOC
        tristate "SoC Audio for the Marvell Kirkwood chip"
-       depends on ARCH_KIRKWOOD
+       depends on ARCH_KIRKWOOD || COMPILE_TEST
        help
          Say Y or M if you want to add support for codecs attached to
          the Kirkwood I2S interface. You will also need to select the
          audio interfaces to support below.
 
-config SND_KIRKWOOD_SOC_I2S
-       tristate
-
 config SND_KIRKWOOD_SOC_OPENRD
        tristate "SoC Audio support for Kirkwood Openrd Client"
-       depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE)
+       depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST)
        depends on I2C
-       select SND_KIRKWOOD_SOC_I2S
        select SND_SOC_CS42L51
        help
          Say Y if you want to add support for SoC audio on
@@ -21,8 +17,7 @@ config SND_KIRKWOOD_SOC_OPENRD
 
 config SND_KIRKWOOD_SOC_T5325
        tristate "SoC Audio support for HP t5325"
-       depends on SND_KIRKWOOD_SOC && MACH_T5325 && I2C
-       select SND_KIRKWOOD_SOC_I2S
+       depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C
        select SND_SOC_ALC5623
        help
          Say Y if you want to add support for SoC audio on
index 3e62ae9..9e78138 100644 (file)
@@ -1,8 +1,6 @@
-snd-soc-kirkwood-objs := kirkwood-dma.o
-snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+snd-soc-kirkwood-objs := kirkwood-dma.o kirkwood-i2s.o
 
 obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
-obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
 
 snd-soc-openrd-objs := kirkwood-openrd.o
 snd-soc-t5325-objs := kirkwood-t5325.o
index a9f1453..b238434 100644 (file)
         SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | \
         SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE)
 
-struct kirkwood_dma_priv {
-       struct snd_pcm_substream *play_stream;
-       struct snd_pcm_substream *rec_stream;
-       struct kirkwood_dma_data *data;
-};
+static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs)
+{
+       struct snd_soc_pcm_runtime *soc_runtime = subs->private_data;
+       return snd_soc_dai_get_drvdata(soc_runtime->cpu_dai);
+}
 
 static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED |
@@ -51,7 +51,7 @@ static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
        .rate_max               = 384000,
        .channels_min           = 1,
        .channels_max           = 8,
-       .buffer_bytes_max       = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+       .buffer_bytes_max       = KIRKWOOD_SND_MAX_BUFFER_BYTES,
        .period_bytes_min       = KIRKWOOD_SND_MIN_PERIOD_BYTES,
        .period_bytes_max       = KIRKWOOD_SND_MAX_PERIOD_BYTES,
        .periods_min            = KIRKWOOD_SND_MIN_PERIODS,
@@ -63,8 +63,7 @@ static u64 kirkwood_dma_dmamask = DMA_BIT_MASK(32);
 
 static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
 {
-       struct kirkwood_dma_priv *prdata = dev_id;
-       struct kirkwood_dma_data *priv = prdata->data;
+       struct kirkwood_dma_data *priv = dev_id;
        unsigned long mask, status, cause;
 
        mask = readl(priv->io + KIRKWOOD_INT_MASK);
@@ -89,10 +88,10 @@ static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
        writel(status, priv->io + KIRKWOOD_INT_CAUSE);
 
        if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
-               snd_pcm_period_elapsed(prdata->play_stream);
+               snd_pcm_period_elapsed(priv->substream_play);
 
        if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
-               snd_pcm_period_elapsed(prdata->rec_stream);
+               snd_pcm_period_elapsed(priv->substream_rec);
 
        return IRQ_HANDLED;
 }
@@ -126,15 +125,10 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
 {
        int err;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_platform *platform = soc_runtime->platform;
-       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-       struct kirkwood_dma_data *priv;
-       struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
+       struct kirkwood_dma_data *priv = kirkwood_priv(substream);
        const struct mbus_dram_target_info *dram;
        unsigned long addr;
 
-       priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
        snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
 
        /* Ensure that all constraints linked to dma burst are fulfilled */
@@ -157,21 +151,11 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
        if (err < 0)
                return err;
 
-       if (prdata == NULL) {
-               prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
-               if (prdata == NULL)
-                       return -ENOMEM;
-
-               prdata->data = priv;
-
+       if (!priv->substream_play && !priv->substream_rec) {
                err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
-                                 "kirkwood-i2s", prdata);
-               if (err) {
-                       kfree(prdata);
+                                 "kirkwood-i2s", priv);
+               if (err)
                        return -EBUSY;
-               }
-
-               snd_soc_platform_set_drvdata(platform, prdata);
 
                /*
                 * Enable Error interrupts. We're only ack'ing them but
@@ -183,11 +167,11 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
        dram = mv_mbus_dram_info();
        addr = substream->dma_buffer.addr;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               prdata->play_stream = substream;
+               priv->substream_play = substream;
                kirkwood_dma_conf_mbus_windows(priv->io,
                        KIRKWOOD_PLAYBACK_WIN, addr, dram);
        } else {
-               prdata->rec_stream = substream;
+               priv->substream_rec = substream;
                kirkwood_dma_conf_mbus_windows(priv->io,
                        KIRKWOOD_RECORD_WIN, addr, dram);
        }
@@ -197,27 +181,19 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream)
 
 static int kirkwood_dma_close(struct snd_pcm_substream *substream)
 {
-       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-       struct snd_soc_platform *platform = soc_runtime->platform;
-       struct kirkwood_dma_priv *prdata = snd_soc_platform_get_drvdata(platform);
-       struct kirkwood_dma_data *priv;
-
-       priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       struct kirkwood_dma_data *priv = kirkwood_priv(substream);
 
-       if (!prdata || !priv)
+       if (!priv)
                return 0;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               prdata->play_stream = NULL;
+               priv->substream_play = NULL;
        else
-               prdata->rec_stream = NULL;
+               priv->substream_rec = NULL;
 
-       if (!prdata->play_stream && !prdata->rec_stream) {
+       if (!priv->substream_play && !priv->substream_rec) {
                writel(0, priv->io + KIRKWOOD_ERR_MASK);
-               free_irq(priv->irq, prdata);
-               kfree(prdata);
-               snd_soc_platform_set_drvdata(platform, NULL);
+               free_irq(priv->irq, priv);
        }
 
        return 0;
@@ -243,13 +219,9 @@ static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
 static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-       struct kirkwood_dma_data *priv;
+       struct kirkwood_dma_data *priv = kirkwood_priv(substream);
        unsigned long size, count;
 
-       priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
-
        /* compute buffer size in term of "words" as requested in specs */
        size = frames_to_bytes(runtime, runtime->buffer_size);
        size = (size>>2)-1;
@@ -272,13 +244,9 @@ static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
 static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
                                                *substream)
 {
-       struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-       struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
-       struct kirkwood_dma_data *priv;
+       struct kirkwood_dma_data *priv = kirkwood_priv(substream);
        snd_pcm_uframes_t count;
 
-       priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
-
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                count = bytes_to_frames(substream->runtime,
                        readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
@@ -366,36 +334,8 @@ static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
        }
 }
 
-static struct snd_soc_platform_driver kirkwood_soc_platform = {
+struct snd_soc_platform_driver kirkwood_soc_platform = {
        .ops            = &kirkwood_dma_ops,
        .pcm_new        = kirkwood_dma_new,
        .pcm_free       = kirkwood_dma_free_dma_buffers,
 };
-
-static int kirkwood_soc_platform_probe(struct platform_device *pdev)
-{
-       return snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
-}
-
-static int kirkwood_soc_platform_remove(struct platform_device *pdev)
-{
-       snd_soc_unregister_platform(&pdev->dev);
-       return 0;
-}
-
-static struct platform_driver kirkwood_pcm_driver = {
-       .driver = {
-                       .name = "kirkwood-pcm-audio",
-                       .owner = THIS_MODULE,
-       },
-
-       .probe = kirkwood_soc_platform_probe,
-       .remove = kirkwood_soc_platform_remove,
-};
-
-module_platform_driver(kirkwood_pcm_driver);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
-MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:kirkwood-pcm-audio");
index 4c9dad3..e5f3f7a 100644 (file)
 #include <linux/platform_data/asoc-kirkwood.h>
 #include "kirkwood.h"
 
-#define DRV_NAME       "kirkwood-i2s"
+#define DRV_NAME       "mvebu-audio"
 
-#define KIRKWOOD_I2S_RATES \
-       (SNDRV_PCM_RATE_44100 | \
-        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
 #define KIRKWOOD_I2S_FORMATS \
        (SNDRV_PCM_FMTBIT_S16_LE | \
         SNDRV_PCM_FMTBIT_S24_LE | \
@@ -105,14 +102,16 @@ static void kirkwood_set_rate(struct snd_soc_dai *dai,
        uint32_t clks_ctrl;
 
        if (rate == 44100 || rate == 48000 || rate == 96000) {
-               /* use internal dco for supported rates */
+               /* use internal dco for the supported rates
+                * defined in kirkwood_i2s_dai */
                dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
                        __func__, rate);
                kirkwood_set_dco(priv->io, rate);
 
                clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
-       } else if (!IS_ERR(priv->extclk)) {
-               /* use optional external clk for other rates */
+       } else {
+               /* use the external clock for the other rates
+                * defined in kirkwood_i2s_dai_extclk */
                dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
                        __func__, rate, 256 * rate);
                clk_set_rate(priv->extclk, 256 * rate);
@@ -199,8 +198,7 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
                        ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
 
                priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
-                                   KIRKWOOD_PLAYCTL_I2S_EN |
-                                   KIRKWOOD_PLAYCTL_SPDIF_EN |
+                                   KIRKWOOD_PLAYCTL_ENABLE_MASK |
                                    KIRKWOOD_PLAYCTL_SIZE_MASK);
                priv->ctl_play |= ctl_play;
        } else {
@@ -244,8 +242,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_START:
                /* configure */
                ctl = priv->ctl_play;
-               value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN |
-                               KIRKWOOD_PLAYCTL_SPDIF_EN);
+               value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
                writel(value, priv->io + KIRKWOOD_PLAYCTL);
 
                /* enable interrupts */
@@ -267,7 +264,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
                writel(value, priv->io + KIRKWOOD_INT_MASK);
 
                /* disable all playbacks */
-               ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+               ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
                writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
                break;
 
@@ -387,7 +384,7 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
 
        /* disable playback/record */
        value = readl(priv->io + KIRKWOOD_PLAYCTL);
-       value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+       value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
        writel(value, priv->io + KIRKWOOD_PLAYCTL);
 
        value = readl(priv->io + KIRKWOOD_RECCTL);
@@ -398,11 +395,6 @@ static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
 
 }
 
-static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
-{
-       return 0;
-}
-
 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
        .startup        = kirkwood_i2s_startup,
        .trigger        = kirkwood_i2s_trigger,
@@ -413,17 +405,18 @@ static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai = {
        .probe = kirkwood_i2s_probe,
-       .remove = kirkwood_i2s_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
-               .rates = KIRKWOOD_I2S_RATES,
+               .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000,
                .formats = KIRKWOOD_I2S_FORMATS,
        },
        .capture = {
                .channels_min = 1,
                .channels_max = 2,
-               .rates = KIRKWOOD_I2S_RATES,
+               .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+                               SNDRV_PCM_RATE_96000,
                .formats = KIRKWOOD_I2S_FORMATS,
        },
        .ops = &kirkwood_i2s_dai_ops,
@@ -431,7 +424,6 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai = {
 
 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
        .probe = kirkwood_i2s_probe,
-       .remove = kirkwood_i2s_remove,
        .playback = {
                .channels_min = 1,
                .channels_max = 2,
@@ -498,10 +490,10 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       priv->extclk = clk_get(&pdev->dev, "extclk");
+       priv->extclk = devm_clk_get(&pdev->dev, "extclk");
        if (!IS_ERR(priv->extclk)) {
                if (priv->extclk == priv->clk) {
-                       clk_put(priv->extclk);
+                       devm_clk_put(&pdev->dev, priv->extclk);
                        priv->extclk = ERR_PTR(-EINVAL);
                } else {
                        dev_info(&pdev->dev, "found external clock\n");
@@ -525,14 +517,22 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 
        err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
                                         soc_dai, 1);
-       if (!err)
-               return 0;
-       dev_err(&pdev->dev, "snd_soc_register_component failed\n");
+       if (err) {
+               dev_err(&pdev->dev, "snd_soc_register_component failed\n");
+               goto err_component;
+       }
 
-       if (!IS_ERR(priv->extclk)) {
-               clk_disable_unprepare(priv->extclk);
-               clk_put(priv->extclk);
+       err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
+       if (err) {
+               dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
+               goto err_platform;
        }
+       return 0;
+ err_platform:
+       snd_soc_unregister_component(&pdev->dev);
+ err_component:
+       if (!IS_ERR(priv->extclk))
+               clk_disable_unprepare(priv->extclk);
        clk_disable_unprepare(priv->clk);
 
        return err;
@@ -542,12 +542,11 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
        struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
 
+       snd_soc_unregister_platform(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
 
-       if (!IS_ERR(priv->extclk)) {
+       if (!IS_ERR(priv->extclk))
                clk_disable_unprepare(priv->extclk);
-               clk_put(priv->extclk);
-       }
        clk_disable_unprepare(priv->clk);
 
        return 0;
@@ -568,4 +567,4 @@ module_platform_driver(kirkwood_i2s_driver);
 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:kirkwood-i2s");
+MODULE_ALIAS("platform:mvebu-audio");
index b979c71..025be0e 100644 (file)
@@ -16,9 +16,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <mach/kirkwood.h>
 #include <linux/platform_data/asoc-kirkwood.h>
-#include <asm/mach-types.h>
 #include "../codecs/cs42l51.h"
 
 static int openrd_client_hw_params(struct snd_pcm_substream *substream,
@@ -54,8 +52,8 @@ static struct snd_soc_dai_link openrd_client_dai[] = {
 {
        .name = "CS42L51",
        .stream_name = "CS42L51 HiFi",
-       .cpu_dai_name = "kirkwood-i2s",
-       .platform_name = "kirkwood-pcm-audio",
+       .cpu_dai_name = "mvebu-audio",
+       .platform_name = "mvebu-audio",
        .codec_dai_name = "cs42l51-hifi",
        .codec_name = "cs42l51-codec.0-004a",
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
index 1d0ed6f..27545b0 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <sound/soc.h>
-#include <mach/kirkwood.h>
 #include <linux/platform_data/asoc-kirkwood.h>
-#include <asm/mach-types.h>
 #include "../codecs/alc5623.h"
 
 static int t5325_hw_params(struct snd_pcm_substream *substream,
@@ -70,8 +68,8 @@ static struct snd_soc_dai_link t5325_dai[] = {
 {
        .name = "ALC5621",
        .stream_name = "ALC5621 HiFi",
-       .cpu_dai_name = "kirkwood-i2s",
-       .platform_name = "kirkwood-pcm-audio",
+       .cpu_dai_name = "mvebu-audio",
+       .platform_name = "mvebu-audio",
        .codec_dai_name = "alc5621-hifi",
        .codec_name = "alc562x-codec.0-001a",
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS,
index 4d92637..f8e1ccc 100644 (file)
@@ -54,7 +54,7 @@
 #define KIRKWOOD_PLAYCTL_MONO_OFF              (0<<5)
 #define KIRKWOOD_PLAYCTL_I2S_MUTE              (1<<7)
 #define KIRKWOOD_PLAYCTL_SPDIF_EN              (1<<4)
-#define KIRKWOOD_PLAYCTL_I2S_EN                (1<<3)
+#define KIRKWOOD_PLAYCTL_I2S_EN                        (1<<3)
 #define KIRKWOOD_PLAYCTL_SIZE_MASK             (7<<0)
 #define KIRKWOOD_PLAYCTL_SIZE_16               (7<<0)
 #define KIRKWOOD_PLAYCTL_SIZE_16_C             (3<<0)
@@ -62,6 +62,9 @@
 #define KIRKWOOD_PLAYCTL_SIZE_24               (1<<0)
 #define KIRKWOOD_PLAYCTL_SIZE_32               (0<<0)
 
+#define KIRKWOOD_PLAYCTL_ENABLE_MASK           (KIRKWOOD_PLAYCTL_SPDIF_EN | \
+                                                KIRKWOOD_PLAYCTL_I2S_EN)
+
 #define KIRKWOOD_PLAY_BUF_ADDR                 0x1104
 #define KIRKWOOD_PLAY_BUF_SIZE                 0x1108
 #define KIRKWOOD_PLAY_BYTE_COUNT               0x110C
 #define KIRKWOOD_SND_MAX_PERIODS               16
 #define KIRKWOOD_SND_MIN_PERIOD_BYTES          0x4000
 #define KIRKWOOD_SND_MAX_PERIOD_BYTES          0x4000
+#define KIRKWOOD_SND_MAX_BUFFER_BYTES          (KIRKWOOD_SND_MAX_PERIOD_BYTES \
+                                                * KIRKWOOD_SND_MAX_PERIODS)
 
 struct kirkwood_dma_data {
        void __iomem *io;
@@ -129,8 +134,12 @@ struct kirkwood_dma_data {
        struct clk *extclk;
        uint32_t ctl_play;
        uint32_t ctl_rec;
+       struct snd_pcm_substream *substream_play;
+       struct snd_pcm_substream *substream_rec;
        int irq;
        int burst;
 };
 
+extern struct snd_soc_platform_driver kirkwood_soc_platform;
+
 #endif
index 78d321c..219235c 100644 (file)
@@ -1,6 +1,7 @@
 menuconfig SND_MXS_SOC
        tristate "SoC Audio for Freescale MXS CPUs"
-       depends on ARCH_MXS
+       depends on ARCH_MXS || COMPILE_TEST
+       depends on COMMON_CLK
        select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M if you want to add support for codecs attached to
index 54511c5..b56b8a0 100644 (file)
@@ -31,7 +31,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <asm/mach-types.h>
 
 #include "mxs-saif.h"
 
index 1b134d7..ce084eb 100644 (file)
@@ -25,7 +25,6 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 #include <sound/soc-dapm.h>
-#include <asm/mach-types.h>
 
 #include "../codecs/sgtl5000.h"
 #include "mxs-saif.h"
@@ -51,18 +50,27 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
        }
 
        /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */
-       if (mclk < 8000000 || mclk > 27000000)
+       if (mclk < 8000000 || mclk > 27000000) {
+               dev_err(codec_dai->dev, "Invalid mclk frequency: %u.%03uMHz\n",
+                       mclk / 1000000, mclk / 1000 % 1000);
                return -EINVAL;
+       }
 
        /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */
        ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0);
-       if (ret)
+       if (ret) {
+               dev_err(codec_dai->dev, "Failed to set sysclk to %u.%03uMHz\n",
+                       mclk / 1000000, mclk / 1000 % 1000);
                return ret;
+       }
 
        /* The SAIF MCLK should be the same as SGTL5000_SYSCLK */
        ret = snd_soc_dai_set_sysclk(cpu_dai, MXS_SAIF_MCLK, mclk, 0);
-       if (ret)
+       if (ret) {
+               dev_err(cpu_dai->dev, "Failed to set sysclk to %u.%03uMHz\n",
+                       mclk / 1000000, mclk / 1000 % 1000);
                return ret;
+       }
 
        /* set codec to slave mode */
        dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
@@ -70,13 +78,19 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
 
        /* set codec DAI configuration */
        ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
-       if (ret)
+       if (ret) {
+               dev_err(codec_dai->dev, "Failed to set dai format to %08x\n",
+                       dai_format);
                return ret;
+       }
 
        /* set cpu DAI configuration */
        ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
-       if (ret)
+       if (ret) {
+               dev_err(cpu_dai->dev, "Failed to set dai format to %08x\n",
+                       dai_format);
                return ret;
+       }
 
        return 0;
 }
@@ -154,8 +168,10 @@ static int mxs_sgtl5000_probe(struct platform_device *pdev)
         * should be >= 8MHz and <= 27M.
         */
        ret = mxs_saif_get_mclk(0, 44100 * 256, 44100);
-       if (ret)
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get mclk\n");
                return ret;
+       }
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
index f4c2417..8987bf9 100644 (file)
@@ -333,9 +333,6 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
        spin_lock_init(&nuc900_audio->lock);
 
        nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!nuc900_audio->res)
-               return ret;
-
        nuc900_audio->mmio = devm_ioremap_resource(&pdev->dev,
                                                   nuc900_audio->res);
        if (IS_ERR(nuc900_audio->mmio))
index 9f5d55e..daa78a0 100644 (file)
@@ -1,7 +1,7 @@
 config SND_OMAP_SOC
        tristate "SoC Audio for the Texas Instruments OMAP chips"
-       depends on ARCH_OMAP && DMA_OMAP
-       select SND_SOC_DMAENGINE_PCM
+       depends on (ARCH_OMAP && DMA_OMAP) || (ARCH_ARM && COMPILE_TEST)
+       select SND_DMAENGINE_PCM
 
 config SND_OMAP_SOC_DMIC
        tristate
@@ -26,7 +26,7 @@ config SND_OMAP_SOC_N810
 
 config SND_OMAP_SOC_RX51
        tristate "SoC Audio support for Nokia RX-51"
-       depends on SND_OMAP_SOC && MACH_NOKIA_RX51
+       depends on SND_OMAP_SOC && ARCH_ARM && (MACH_NOKIA_RX51 || COMPILE_TEST)
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TLV320AIC3X
        select SND_SOC_TPA6130A2
@@ -87,7 +87,7 @@ config SND_OMAP_SOC_OMAP_TWL4030
 
 config SND_OMAP_SOC_OMAP_ABE_TWL6040
        tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec"
-       depends on TWL6040_CORE && SND_OMAP_SOC && ARCH_OMAP4
+       depends on TWL6040_CORE && SND_OMAP_SOC && (ARCH_OMAP4 || COMPILE_TEST)
        select SND_OMAP_SOC_DMIC
        select SND_OMAP_SOC_MCPDM
        select SND_SOC_TWL6040
index 70cd5c7..ebb1390 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/twl6040.h>
-#include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/module.h>
 #include <linux/of.h>
 
@@ -166,19 +165,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"AFMR", NULL, "Line In"},
 };
 
-static inline void twl6040_disconnect_pin(struct snd_soc_dapm_context *dapm,
-                                         int connected, char *pin)
-{
-       if (!connected)
-               snd_soc_dapm_disable_pin(dapm, pin);
-}
-
 static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_card *card = codec->card;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-       struct omap_abe_twl6040_data *pdata = dev_get_platdata(card->dev);
        struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
        int hs_trim;
        int ret = 0;
@@ -203,24 +193,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
                twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
        }
 
-       /*
-        * NULL pdata means we booted with DT. In this case the routing is
-        * provided and the card is fully routed, no need to mark pins.
-        */
-       if (!pdata)
-               return ret;
-
-       /* Disable not connected paths if not used */
-       twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-       twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
-       twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vibrator");
-       twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
        return ret;
 }
 
@@ -274,13 +246,18 @@ static struct snd_soc_card omap_abe_card = {
 
 static int omap_abe_probe(struct platform_device *pdev)
 {
-       struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *node = pdev->dev.of_node;
        struct snd_soc_card *card = &omap_abe_card;
+       struct device_node *dai_node;
        struct abe_twl6040 *priv;
        int num_links = 0;
        int ret = 0;
 
+       if (!node) {
+               dev_err(&pdev->dev, "of node is missing.\n");
+               return -ENODEV;
+       }
+
        card->dev = &pdev->dev;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
@@ -289,78 +266,50 @@ static int omap_abe_probe(struct platform_device *pdev)
 
        priv->dmic_codec_dev = ERR_PTR(-EINVAL);
 
-       if (node) {
-               struct device_node *dai_node;
-
-               if (snd_soc_of_parse_card_name(card, "ti,model")) {
-                       dev_err(&pdev->dev, "Card name is not provided\n");
-                       return -ENODEV;
-               }
+       if (snd_soc_of_parse_card_name(card, "ti,model")) {
+               dev_err(&pdev->dev, "Card name is not provided\n");
+               return -ENODEV;
+       }
 
-               ret = snd_soc_of_parse_audio_routing(card,
-                                               "ti,audio-routing");
-               if (ret) {
-                       dev_err(&pdev->dev,
-                               "Error while parsing DAPM routing\n");
-                       return ret;
-               }
+       ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
+       if (ret) {
+               dev_err(&pdev->dev, "Error while parsing DAPM routing\n");
+               return ret;
+       }
 
-               dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
-               if (!dai_node) {
-                       dev_err(&pdev->dev, "McPDM node is not provided\n");
-                       return -EINVAL;
-               }
-               abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
-               abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+       dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+       if (!dai_node) {
+               dev_err(&pdev->dev, "McPDM node is not provided\n");
+               return -EINVAL;
+       }
+       abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
+       abe_twl6040_dai_links[0].cpu_of_node = dai_node;
 
-               dai_node = of_parse_phandle(node, "ti,dmic", 0);
-               if (dai_node) {
-                       num_links = 2;
-                       abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
-                       abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+       dai_node = of_parse_phandle(node, "ti,dmic", 0);
+       if (dai_node) {
+               num_links = 2;
+               abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
+               abe_twl6040_dai_links[1].cpu_of_node = dai_node;
 
-                       priv->dmic_codec_dev = platform_device_register_simple(
+               priv->dmic_codec_dev = platform_device_register_simple(
                                                "dmic-codec", -1, NULL, 0);
-                       if (IS_ERR(priv->dmic_codec_dev)) {
-                               dev_err(&pdev->dev,
-                                       "Can't instantiate dmic-codec\n");
-                               return PTR_ERR(priv->dmic_codec_dev);
-                       }
-               } else {
-                       num_links = 1;
-               }
-
-               priv->jack_detection = of_property_read_bool(node,
-                                                          "ti,jack-detection");
-               of_property_read_u32(node, "ti,mclk-freq",
-                                    &priv->mclk_freq);
-               if (!priv->mclk_freq) {
-                       dev_err(&pdev->dev, "MCLK frequency not provided\n");
-                       ret = -EINVAL;
-                       goto err_unregister;
+               if (IS_ERR(priv->dmic_codec_dev)) {
+                       dev_err(&pdev->dev, "Can't instantiate dmic-codec\n");
+                       return PTR_ERR(priv->dmic_codec_dev);
                }
-
-               omap_abe_card.fully_routed = 1;
-       } else if (pdata) {
-               if (pdata->card_name) {
-                       card->name = pdata->card_name;
-               } else {
-                       dev_err(&pdev->dev, "Card name is not provided\n");
-                       return -ENODEV;
-               }
-
-               if (pdata->has_dmic)
-                       num_links = 2;
-               else
-                       num_links = 1;
-
-               priv->jack_detection = pdata->jack_detection;
-               priv->mclk_freq = pdata->mclk_freq;
        } else {
-               dev_err(&pdev->dev, "Missing pdata\n");
-               return -ENODEV;
+               num_links = 1;
+       }
+
+       priv->jack_detection = of_property_read_bool(node, "ti,jack-detection");
+       of_property_read_u32(node, "ti,mclk-freq", &priv->mclk_freq);
+       if (!priv->mclk_freq) {
+               dev_err(&pdev->dev, "MCLK frequency not provided\n");
+               ret = -EINVAL;
+               goto err_unregister;
        }
 
+       card->fully_routed = 1;
 
        if (!priv->mclk_freq) {
                dev_err(&pdev->dev, "MCLK frequency missing\n");
index 4db1f8e..12e566b 100644 (file)
@@ -480,15 +480,12 @@ static int asoc_dmic_probe(struct platform_device *pdev)
        dmic->dma_data.filter_data = "up_link";
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       if (!res) {
-               dev_err(dmic->dev, "invalid memory resource\n");
-               ret = -ENODEV;
+       dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dmic->io_base)) {
+               ret = PTR_ERR(dmic->io_base);
                goto err_put_clk;
        }
 
-       dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dmic->io_base))
-               return PTR_ERR(dmic->io_base);
 
        ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
                                         &omap_dmic_dai, 1);
index 7483efb..6c19bba 100644 (file)
@@ -433,6 +433,11 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                /* Sample rate generator drives the FS */
                regs->srgr2     |= FSGM;
                break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               /* McBSP slave. FS clock as output */
+               regs->srgr2     |= FSGM;
+               regs->pcr0      |= FSXM;
+               break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* McBSP slave */
                break;
index a49dc52..90d2a7c 100644 (file)
@@ -480,9 +480,6 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
        mcpdm->dma_data[1].filter_data = "up_link";
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
-       if (res == NULL)
-               return -ENOMEM;
-
        mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(mcpdm->io_base))
                return PTR_ERR(mcpdm->io_base);
index b358094..4db74a0 100644 (file)
@@ -11,7 +11,7 @@ config SND_PXA2XX_SOC
 config SND_MMP_SOC
        bool "Soc Audio for Marvell MMP chips"
        depends on ARCH_MMP
-       select SND_SOC_DMAENGINE_PCM
+       select SND_DMAENGINE_PCM
        select SND_ARM
        help
          Say Y if you want to add support for codecs attached to
index 4ad7609..5b7d969 100644 (file)
@@ -129,6 +129,7 @@ static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
 /* audio machine driver */
 static struct snd_soc_card brownstone = {
        .name         = "brownstone",
+       .owner        = THIS_MODULE,
        .dai_link     = brownstone_wm8994_dai,
        .num_links    = ARRAY_SIZE(brownstone_wm8994_dai),
 
index 97b711e..bbea778 100644 (file)
@@ -56,8 +56,6 @@
 #include "pxa2xx-ac97.h"
 #include "../codecs/wm9713.h"
 
-#define ARRAY_AND_SIZE(x)      (x), ARRAY_SIZE(x)
-
 #define AC97_GPIO_PULL         0x58
 
 /* Use GPIO8 for rear speaker amplifier */
@@ -133,10 +131,11 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
        unsigned short reg;
 
        /* Add mioa701 specific widgets */
-       snd_soc_dapm_new_controls(dapm, ARRAY_AND_SIZE(mioa701_dapm_widgets));
+       snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets,
+                                 ARRAY_SIZE(mioa701_dapm_widgets));
 
        /* Set up mioa701 specific audio path audio_mapnects */
-       snd_soc_dapm_add_routes(dapm, ARRAY_AND_SIZE(audio_map));
+       snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
        /* Prepare GPIO8 for rear speaker amplifier */
        reg = codec->driver->read(codec, AC97_GPIO_CFG);
index 5d57e07..8235e23 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-mmp_tdma.h>
 #include <linux/platform_data/mmp_audio.h>
+
 #include <sound/pxa2xx-lib.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -67,7 +68,7 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct pxa2xx_pcm_dma_params *dma_params;
+       struct snd_dmaengine_dai_dma_data *dma_params;
        struct dma_slave_config slave_config;
        int ret;
 
@@ -80,10 +81,10 @@ static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.dst_addr     = dma_params->dev_addr;
+               slave_config.dst_addr     = dma_params->addr;
                slave_config.dst_maxburst = 4;
        } else {
-               slave_config.src_addr     = dma_params->dev_addr;
+               slave_config.src_addr     = dma_params->addr;
                slave_config.src_maxburst = 4;
        }
 
index 62142ce..41752a5 100644 (file)
 #include <linux/slab.h>
 #include <linux/pxa2xx_ssp.h>
 #include <linux/io.h>
+#include <linux/dmaengine.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/initval.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 #include "mmp-sspa.h"
 
 /*
@@ -40,7 +43,7 @@
  */
 struct sspa_priv {
        struct ssp_device *sspa;
-       struct pxa2xx_pcm_dma_params *dma_params;
+       struct snd_dmaengine_dai_dma_data *dma_params;
        struct clk *audio_clk;
        struct clk *sysclk;
        int dai_fmt;
@@ -266,7 +269,7 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
        struct ssp_device *sspa = sspa_priv->sspa;
-       struct pxa2xx_pcm_dma_params *dma_params;
+       struct snd_dmaengine_dai_dma_data *dma_params;
        u32 sspa_ctrl;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -309,7 +312,7 @@ static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
        }
 
        dma_params = &sspa_priv->dma_params[substream->stream];
-       dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+       dma_params->addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
                                (sspa->phys_base + SSPA_TXD) :
                                (sspa->phys_base + SSPA_RXD);
        snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params);
@@ -425,14 +428,12 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        priv->dma_params = devm_kzalloc(&pdev->dev,
-                       2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL);
+                       2 * sizeof(struct snd_dmaengine_dai_dma_data),
+                       GFP_KERNEL);
        if (priv->dma_params == NULL)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL)
-               return -ENOMEM;
-
        priv->sspa->mmio_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(priv->sspa->mmio_base))
                return PTR_ERR(priv->sspa->mmio_base);
index 6f4dd75..a3119a0 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/pxa2xx_ssp.h>
+#include <linux/of.h>
+#include <linux/dmaengine.h>
 
 #include <asm/irq.h>
 
@@ -30,9 +32,9 @@
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/hardware.h>
-#include <mach/dma.h>
 
 #include "../../arm/pxa2xx-pcm.h"
 #include "pxa-ssp.h"
@@ -79,27 +81,13 @@ static void pxa_ssp_disable(struct ssp_device *ssp)
        __raw_writel(sscr0, ssp->mmio_base + SSCR0);
 }
 
-struct pxa2xx_pcm_dma_data {
-       struct pxa2xx_pcm_dma_params params;
-       char name[20];
-};
-
 static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
-                       int out, struct pxa2xx_pcm_dma_params *dma_data)
+                       int out, struct snd_dmaengine_dai_dma_data *dma)
 {
-       struct pxa2xx_pcm_dma_data *dma;
-
-       dma = container_of(dma_data, struct pxa2xx_pcm_dma_data, params);
-
-       snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
-                       width4 ? "32-bit" : "16-bit", out ? "out" : "in");
-
-       dma->params.name = dma->name;
-       dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx);
-       dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) :
-                                 (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
-                       (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
-       dma->params.dev_addr = ssp->phys_base + SSDR;
+       dma->addr_width = width4 ? DMA_SLAVE_BUSWIDTH_4_BYTES :
+                                  DMA_SLAVE_BUSWIDTH_2_BYTES;
+       dma->maxburst = 16;
+       dma->addr = ssp->phys_base + SSDR;
 }
 
 static int pxa_ssp_startup(struct snd_pcm_substream *substream,
@@ -107,7 +95,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
 {
        struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
        struct ssp_device *ssp = priv->ssp;
-       struct pxa2xx_pcm_dma_data *dma;
+       struct snd_dmaengine_dai_dma_data *dma;
        int ret = 0;
 
        if (!cpu_dai->active) {
@@ -115,10 +103,14 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
                pxa_ssp_disable(ssp);
        }
 
-       dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+       dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
        if (!dma)
                return -ENOMEM;
-       snd_soc_dai_set_dma_data(cpu_dai, substream, &dma->params);
+
+       dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                               &ssp->drcmr_tx : &ssp->drcmr_rx;
+
+       snd_soc_dai_set_dma_data(cpu_dai, substream, dma);
 
        return ret;
 }
@@ -559,7 +551,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
        u32 sspsp;
        int width = snd_pcm_format_physical_width(params_format(params));
        int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
-       struct pxa2xx_pcm_dma_params *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
 
@@ -719,6 +711,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
 
 static int pxa_ssp_probe(struct snd_soc_dai *dai)
 {
+       struct device *dev = dai->dev;
        struct ssp_priv *priv;
        int ret;
 
@@ -726,10 +719,26 @@ static int pxa_ssp_probe(struct snd_soc_dai *dai)
        if (!priv)
                return -ENOMEM;
 
-       priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
-       if (priv->ssp == NULL) {
-               ret = -ENODEV;
-               goto err_priv;
+       if (dev->of_node) {
+               struct device_node *ssp_handle;
+
+               ssp_handle = of_parse_phandle(dev->of_node, "port", 0);
+               if (!ssp_handle) {
+                       dev_err(dev, "unable to get 'port' phandle\n");
+                       return -ENODEV;
+               }
+
+               priv->ssp = pxa_ssp_request_of(ssp_handle, "SoC audio");
+               if (priv->ssp == NULL) {
+                       ret = -ENODEV;
+                       goto err_priv;
+               }
+       } else {
+               priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
+               if (priv->ssp == NULL) {
+                       ret = -ENODEV;
+                       goto err_priv;
+               }
        }
 
        priv->dai_fmt = (unsigned int) -1;
@@ -798,6 +807,12 @@ static const struct snd_soc_component_driver pxa_ssp_component = {
        .name           = "pxa-ssp",
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ssp_of_ids[] = {
+       { .compatible = "mrvl,pxa-ssp-dai" },
+};
+#endif
+
 static int asoc_ssp_probe(struct platform_device *pdev)
 {
        return snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
@@ -812,8 +827,9 @@ static int asoc_ssp_remove(struct platform_device *pdev)
 
 static struct platform_driver asoc_ssp_driver = {
        .driver = {
-                       .name = "pxa-ssp-dai",
-                       .owner = THIS_MODULE,
+               .name = "pxa-ssp-dai",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(pxa_ssp_of_ids),
        },
 
        .probe = asoc_ssp_probe,
index 1475515..f1059d9 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/dmaengine.h>
 
 #include <sound/core.h>
 #include <sound/ac97_codec.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/hardware.h>
 #include <mach/regs-ac97.h>
-#include <mach/dma.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-ac97.h"
@@ -48,44 +49,44 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
        .reset  = pxa2xx_ac97_cold_reset,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
-       .name                   = "AC97 PCM Stereo out",
-       .dev_addr               = __PREG(PCDR),
-       .drcmr                  = &DRCMR(12),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_stereo_in_req = 12;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
+       .addr           = __PREG(PCDR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .maxburst       = 32,
+       .filter_data    = &pxa2xx_ac97_pcm_stereo_in_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_in = {
-       .name                   = "AC97 PCM Stereo in",
-       .dev_addr               = __PREG(PCDR),
-       .drcmr                  = &DRCMR(11),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_ac97_pcm_stereo_out_req = 11;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
+       .addr           = __PREG(PCDR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .maxburst       = 32,
+       .filter_data    = &pxa2xx_ac97_pcm_stereo_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_out = {
-       .name                   = "AC97 Aux PCM (Slot 5) Mono out",
-       .dev_addr               = __PREG(MODR),
-       .drcmr                  = &DRCMR(10),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
+static unsigned long pxa2xx_ac97_pcm_aux_mono_out_req = 10;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
+       .addr           = __PREG(MODR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
+       .maxburst       = 16,
+       .filter_data    = &pxa2xx_ac97_pcm_aux_mono_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_aux_mono_in = {
-       .name                   = "AC97 Aux PCM (Slot 5) Mono in",
-       .dev_addr               = __PREG(MODR),
-       .drcmr                  = &DRCMR(9),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
+static unsigned long pxa2xx_ac97_pcm_aux_mono_in_req = 9;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
+       .addr           = __PREG(MODR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
+       .maxburst       = 16,
+       .filter_data    = &pxa2xx_ac97_pcm_aux_mono_in_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_mic_mono_in = {
-       .name                   = "AC97 Mic PCM (Slot 6) Mono in",
-       .dev_addr               = __PREG(MCDR),
-       .drcmr                  = &DRCMR(8),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST16 | DCMD_WIDTH2,
+static unsigned long pxa2xx_ac97_pcm_aux_mic_mono_req = 8;
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
+       .addr           = __PREG(MCDR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_2_BYTES,
+       .maxburst       = 16,
+       .filter_data    = &pxa2xx_ac97_pcm_aux_mic_mono_req,
 };
 
 #ifdef CONFIG_PM
@@ -119,7 +120,7 @@ static int pxa2xx_ac97_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
 {
-       struct pxa2xx_pcm_dma_params *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                dma_data = &pxa2xx_ac97_pcm_stereo_out;
@@ -135,7 +136,7 @@ static int pxa2xx_ac97_hw_aux_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params,
                                     struct snd_soc_dai *cpu_dai)
 {
-       struct pxa2xx_pcm_dma_params *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                dma_data = &pxa2xx_ac97_pcm_aux_mono_out;
index f7ca716..d5340a0 100644 (file)
@@ -23,9 +23,9 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <mach/hardware.h>
-#include <mach/dma.h>
 #include <mach/audio.h>
 
 #include "pxa2xx-i2s.h"
@@ -82,20 +82,20 @@ static struct pxa_i2s_port pxa_i2s;
 static struct clk *clk_i2s;
 static int clk_ena = 0;
 
-static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
-       .name                   = "I2S PCM Stereo out",
-       .dev_addr               = __PREG(SADR),
-       .drcmr                  = &DRCMR(3),
-       .dcmd                   = DCMD_INCSRCADDR | DCMD_FLOWTRG |
-                                 DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_i2s_pcm_stereo_out_req = 3;
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
+       .addr           = __PREG(SADR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .maxburst       = 32,
+       .filter_data    = &pxa2xx_i2s_pcm_stereo_out_req,
 };
 
-static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
-       .name                   = "I2S PCM Stereo in",
-       .dev_addr               = __PREG(SADR),
-       .drcmr                  = &DRCMR(2),
-       .dcmd                   = DCMD_INCTRGADDR | DCMD_FLOWSRC |
-                                 DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_i2s_pcm_stereo_in_req = 2;
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
+       .addr           = __PREG(SADR),
+       .addr_width     = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       .maxburst       = 32,
+       .filter_data    = &pxa2xx_i2s_pcm_stereo_in_req,
 };
 
 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
@@ -163,7 +163,7 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
 {
-       struct pxa2xx_pcm_dma_params *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        BUG_ON(IS_ERR(clk_i2s));
        clk_prepare_enable(clk_i2s);
index ecff116..806da27 100644 (file)
 
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "../../arm/pxa2xx-pcm.h"
 
@@ -25,7 +28,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct pxa2xx_runtime_data *prtd = runtime->private_data;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct pxa2xx_pcm_dma_params *dma;
+       struct snd_dmaengine_dai_dma_data *dma;
        int ret;
 
        dma = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -39,7 +42,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
         * with different params */
        if (prtd->params == NULL) {
                prtd->params = dma;
-               ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+               ret = pxa_request_dma("name", DMA_PRIO_LOW,
                              pxa2xx_pcm_dma_irq, substream);
                if (ret < 0)
                        return ret;
@@ -47,7 +50,7 @@ static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
        } else if (prtd->params != dma) {
                pxa_free_dma(prtd->dma_ch);
                prtd->params = dma;
-               ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
+               ret = pxa_request_dma("name", DMA_PRIO_LOW,
                              pxa2xx_pcm_dma_irq, substream);
                if (ret < 0)
                        return ret;
@@ -131,10 +134,18 @@ static int pxa2xx_soc_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id snd_soc_pxa_audio_match[] = {
+       { .compatible   = "mrvl,pxa-pcm-audio" },
+       { }
+};
+#endif
+
 static struct platform_driver pxa_pcm_driver = {
        .driver = {
-                       .name = "pxa-pcm-audio",
-                       .owner = THIS_MODULE,
+               .name = "pxa-pcm-audio",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(snd_soc_pxa_audio_match),
        },
 
        .probe = pxa2xx_soc_platform_probe,
index f4ea4f6..13c9ee0 100644 (file)
@@ -122,6 +122,7 @@ static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = {
 /* ttc/td audio machine driver */
 static struct snd_soc_card ttc_dkb_card = {
        .name = "ttc-dkb-hifi",
+       .owner = THIS_MODULE,
        .dai_link = ttc_pm860x_hifi_dai,
        .num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai),
 
index 58cfb1e..945e8ab 100644 (file)
@@ -192,7 +192,7 @@ static struct snd_soc_card snd_soc_card_s6105 = {
        .num_links = 1,
 };
 
-static struct s6000_snd_platform_data __initdata s6105_snd_data = {
+static struct s6000_snd_platform_data s6105_snd_data __initdata = {
        .wide           = 0,
        .channel_in     = 0,
        .channel_out    = 1,
index 2dd623f..2acf987 100644 (file)
@@ -404,18 +404,13 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem_res) {
-               dev_err(&pdev->dev, "Unable to get register resource\n");
-               return -ENXIO;
-       }
-
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!irq_res) {
                dev_err(&pdev->dev, "AC97 IRQ not provided!\n");
                return -ENXIO;
        }
 
+       mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res);
        if (IS_ERR(s3c_ac97.regs))
                return PTR_ERR(s3c_ac97.regs);
@@ -462,7 +457,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
        if (ret)
                goto err5;
 
-       ret = asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
                goto err6;
@@ -485,7 +480,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
 {
        struct resource *irq_res;
 
-       asoc_dma_platform_unregister(&pdev->dev);
+       samsung_asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
 
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
index 21b7926..a0c67f6 100644 (file)
@@ -176,6 +176,10 @@ static int dma_hw_params(struct snd_pcm_substream *substream,
                prtd->params->ch = prtd->params->ops->request(
                                prtd->params->channel, &req, rtd->cpu_dai->dev,
                                prtd->params->ch_name);
+               if (!prtd->params->ch) {
+                       pr_err("Failed to allocate DMA channel\n");
+                       return -ENXIO;
+               }
                prtd->params->ops->config(prtd->params->ch, &config);
        }
 
@@ -433,17 +437,17 @@ static struct snd_soc_platform_driver samsung_asoc_platform = {
        .pcm_free       = dma_free_dma_buffers,
 };
 
-int asoc_dma_platform_register(struct device *dev)
+int samsung_asoc_dma_platform_register(struct device *dev)
 {
        return snd_soc_register_platform(dev, &samsung_asoc_platform);
 }
-EXPORT_SYMBOL_GPL(asoc_dma_platform_register);
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
 
-void asoc_dma_platform_unregister(struct device *dev)
+void samsung_asoc_dma_platform_unregister(struct device *dev)
 {
        snd_soc_unregister_platform(dev);
 }
-EXPORT_SYMBOL_GPL(asoc_dma_platform_unregister);
+EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
 
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
index 189a7a6..0e86315 100644 (file)
@@ -22,7 +22,7 @@ struct s3c_dma_params {
        char *ch_name;
 };
 
-int asoc_dma_platform_register(struct device *dev);
-void asoc_dma_platform_unregister(struct device *dev);
+int samsung_asoc_dma_platform_register(struct device *dev);
+void samsung_asoc_dma_platform_unregister(struct device *dev);
 
 #endif
index c0e6d9a..821a502 100644 (file)
 #define I2SLVL1ADDR    0x34
 #define I2SLVL2ADDR    0x38
 #define I2SLVL3ADDR    0x3c
+#define I2SSTR1                0x40
+#define I2SVER         0x44
+#define I2SFIC2                0x48
+#define I2STDM         0x4c
 
 #define CON_RSTCLR             (1 << 31)
 #define CON_FRXOFSTATUS                (1 << 26)
 #define MOD_RXONLY             (1 << 8)
 #define MOD_TXRX               (2 << 8)
 #define MOD_MASK               (3 << 8)
-#define MOD_LR_LLOW            (0 << 7)
-#define MOD_LR_RLOW            (1 << 7)
-#define MOD_SDF_IIS            (0 << 5)
-#define MOD_SDF_MSB            (1 << 5)
-#define MOD_SDF_LSB            (2 << 5)
-#define MOD_SDF_MASK           (3 << 5)
-#define MOD_RCLK_256FS         (0 << 3)
-#define MOD_RCLK_512FS         (1 << 3)
-#define MOD_RCLK_384FS         (2 << 3)
-#define MOD_RCLK_768FS         (3 << 3)
-#define MOD_RCLK_MASK          (3 << 3)
-#define MOD_BCLK_32FS          (0 << 1)
-#define MOD_BCLK_48FS          (1 << 1)
-#define MOD_BCLK_16FS          (2 << 1)
-#define MOD_BCLK_24FS          (3 << 1)
-#define MOD_BCLK_MASK          (3 << 1)
+#define MOD_LRP_SHIFT          7
+#define MOD_LR_LLOW            0
+#define MOD_LR_RLOW            1
+#define MOD_SDF_SHIFT          5
+#define MOD_SDF_IIS            0
+#define MOD_SDF_MSB            1
+#define MOD_SDF_LSB            2
+#define MOD_SDF_MASK           3
+#define MOD_RCLK_SHIFT         3
+#define MOD_RCLK_256FS         0
+#define MOD_RCLK_512FS         1
+#define MOD_RCLK_384FS         2
+#define MOD_RCLK_768FS         3
+#define MOD_RCLK_MASK          3
+#define MOD_BCLK_SHIFT         1
+#define MOD_BCLK_32FS          0
+#define MOD_BCLK_48FS          1
+#define MOD_BCLK_16FS          2
+#define MOD_BCLK_24FS          3
+#define MOD_BCLK_MASK          3
 #define MOD_8BIT               (1 << 0)
 
+#define EXYNOS5420_MOD_LRP_SHIFT       15
+#define EXYNOS5420_MOD_SDF_SHIFT       6
+#define EXYNOS5420_MOD_RCLK_SHIFT      4
+#define EXYNOS5420_MOD_BCLK_SHIFT      0
+#define EXYNOS5420_MOD_BCLK_64FS       4
+#define EXYNOS5420_MOD_BCLK_96FS       5
+#define EXYNOS5420_MOD_BCLK_128FS      6
+#define EXYNOS5420_MOD_BCLK_192FS      7
+#define EXYNOS5420_MOD_BCLK_256FS      8
+#define EXYNOS5420_MOD_BCLK_MASK       0xf
+
 #define MOD_CDCLKCON           (1 << 12)
 
 #define PSR_PSREN              (1 << 15)
index 959c702..b302f3b 100644 (file)
@@ -40,6 +40,7 @@ enum samsung_dai_type {
 
 struct samsung_i2s_dai_data {
        int dai_type;
+       u32 quirks;
 };
 
 struct i2s_dai {
@@ -198,7 +199,13 @@ static inline bool is_manager(struct i2s_dai *i2s)
 /* Read RCLK of I2S (in multiples of LRCLK) */
 static inline unsigned get_rfs(struct i2s_dai *i2s)
 {
-       u32 rfs = (readl(i2s->addr + I2SMOD) >> 3) & 0x3;
+       u32 rfs;
+
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM)
+               rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
+       else
+               rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
+       rfs &= MOD_RCLK_MASK;
 
        switch (rfs) {
        case 3: return 768;
@@ -212,21 +219,26 @@ static inline unsigned get_rfs(struct i2s_dai *i2s)
 static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
 {
        u32 mod = readl(i2s->addr + I2SMOD);
+       int rfs_shift;
 
-       mod &= ~MOD_RCLK_MASK;
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM)
+               rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
+       else
+               rfs_shift = MOD_RCLK_SHIFT;
+       mod &= ~(MOD_RCLK_MASK << rfs_shift);
 
        switch (rfs) {
        case 768:
-               mod |= MOD_RCLK_768FS;
+               mod |= (MOD_RCLK_768FS << rfs_shift);
                break;
        case 512:
-               mod |= MOD_RCLK_512FS;
+               mod |= (MOD_RCLK_512FS << rfs_shift);
                break;
        case 384:
-               mod |= MOD_RCLK_384FS;
+               mod |= (MOD_RCLK_384FS << rfs_shift);
                break;
        default:
-               mod |= MOD_RCLK_256FS;
+               mod |= (MOD_RCLK_256FS << rfs_shift);
                break;
        }
 
@@ -236,9 +248,22 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
 /* Read Bit-Clock of I2S (in multiples of LRCLK) */
 static inline unsigned get_bfs(struct i2s_dai *i2s)
 {
-       u32 bfs = (readl(i2s->addr + I2SMOD) >> 1) & 0x3;
+       u32 bfs;
+
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+               bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
+               bfs &= EXYNOS5420_MOD_BCLK_MASK;
+       } else {
+               bfs =  readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
+               bfs &= MOD_BCLK_MASK;
+       }
 
        switch (bfs) {
+       case 8: return 256;
+       case 7: return 192;
+       case 6: return 128;
+       case 5: return 96;
+       case 4: return 64;
        case 3: return 24;
        case 2: return 16;
        case 1: return 48;
@@ -250,21 +275,50 @@ static inline unsigned get_bfs(struct i2s_dai *i2s)
 static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
 {
        u32 mod = readl(i2s->addr + I2SMOD);
+       int bfs_shift;
+       int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
 
-       mod &= ~MOD_BCLK_MASK;
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+               bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
+               mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
+       } else {
+               bfs_shift = MOD_BCLK_SHIFT;
+               mod &= ~(MOD_BCLK_MASK << bfs_shift);
+       }
+
+       /* Non-TDM I2S controllers do not support BCLK > 48 * FS */
+       if (!tdm && bfs > 48) {
+               dev_err(&i2s->pdev->dev, "Unsupported BCLK divider\n");
+               return;
+       }
 
        switch (bfs) {
        case 48:
-               mod |= MOD_BCLK_48FS;
+               mod |= (MOD_BCLK_48FS << bfs_shift);
                break;
        case 32:
-               mod |= MOD_BCLK_32FS;
+               mod |= (MOD_BCLK_32FS << bfs_shift);
                break;
        case 24:
-               mod |= MOD_BCLK_24FS;
+               mod |= (MOD_BCLK_24FS << bfs_shift);
                break;
        case 16:
-               mod |= MOD_BCLK_16FS;
+               mod |= (MOD_BCLK_16FS << bfs_shift);
+               break;
+       case 64:
+               mod |= (EXYNOS5420_MOD_BCLK_64FS << bfs_shift);
+               break;
+       case 96:
+               mod |= (EXYNOS5420_MOD_BCLK_96FS << bfs_shift);
+               break;
+       case 128:
+               mod |= (EXYNOS5420_MOD_BCLK_128FS << bfs_shift);
+               break;
+       case 192:
+               mod |= (EXYNOS5420_MOD_BCLK_192FS << bfs_shift);
+               break;
+       case 256:
+               mod |= (EXYNOS5420_MOD_BCLK_256FS << bfs_shift);
                break;
        default:
                dev_err(&i2s->pdev->dev, "Wrong BCLK Divider!\n");
@@ -491,20 +545,32 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
 {
        struct i2s_dai *i2s = to_info(dai);
        u32 mod = readl(i2s->addr + I2SMOD);
+       int lrp_shift, sdf_shift, sdf_mask, lrp_rlow;
        u32 tmp = 0;
 
+       if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
+               lrp_shift = EXYNOS5420_MOD_LRP_SHIFT;
+               sdf_shift = EXYNOS5420_MOD_SDF_SHIFT;
+       } else {
+               lrp_shift = MOD_LRP_SHIFT;
+               sdf_shift = MOD_SDF_SHIFT;
+       }
+
+       sdf_mask = MOD_SDF_MASK << sdf_shift;
+       lrp_rlow = MOD_LR_RLOW << lrp_shift;
+
        /* Format is priority */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_RIGHT_J:
-               tmp |= MOD_LR_RLOW;
-               tmp |= MOD_SDF_MSB;
+               tmp |= lrp_rlow;
+               tmp |= (MOD_SDF_MSB << sdf_shift);
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               tmp |= MOD_LR_RLOW;
-               tmp |= MOD_SDF_LSB;
+               tmp |= lrp_rlow;
+               tmp |= (MOD_SDF_LSB << sdf_shift);
                break;
        case SND_SOC_DAIFMT_I2S:
-               tmp |= MOD_SDF_IIS;
+               tmp |= (MOD_SDF_IIS << sdf_shift);
                break;
        default:
                dev_err(&i2s->pdev->dev, "Format not supported\n");
@@ -519,10 +585,10 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
        case SND_SOC_DAIFMT_NB_NF:
                break;
        case SND_SOC_DAIFMT_NB_IF:
-               if (tmp & MOD_LR_RLOW)
-                       tmp &= ~MOD_LR_RLOW;
+               if (tmp & lrp_rlow)
+                       tmp &= ~lrp_rlow;
                else
-                       tmp |= MOD_LR_RLOW;
+                       tmp |= lrp_rlow;
                break;
        default:
                dev_err(&i2s->pdev->dev, "Polarity not supported\n");
@@ -544,15 +610,18 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       /*
+        * Don't change the I2S mode if any controller is active on this
+        * channel.
+        */
        if (any_active(i2s) &&
-                       ((mod & (MOD_SDF_MASK | MOD_LR_RLOW
-                               | MOD_SLAVE)) != tmp)) {
+               ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) {
                dev_err(&i2s->pdev->dev,
                                "%s:%d Other DAI busy\n", __func__, __LINE__);
                return -EAGAIN;
        }
 
-       mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
+       mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE);
        mod |= tmp;
        writel(mod, i2s->addr + I2SMOD);
 
@@ -1007,6 +1076,8 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
                if (IS_ERR(i2s->pdev))
                        return NULL;
 
+               i2s->pdev->dev.parent = &pdev->dev;
+
                platform_set_drvdata(i2s->pdev, i2s);
                ret = platform_device_add(i2s->pdev);
                if (ret < 0)
@@ -1018,18 +1089,18 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
 
 static const struct of_device_id exynos_i2s_match[];
 
-static inline int samsung_i2s_get_driver_data(struct platform_device *pdev)
+static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
+                                               struct platform_device *pdev)
 {
 #ifdef CONFIG_OF
-       struct samsung_i2s_dai_data *data;
        if (pdev->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
-               data = (struct samsung_i2s_dai_data *) match->data;
-               return data->dai_type;
+               return match->data;
        } else
 #endif
-               return platform_get_device_id(pdev)->driver_data;
+               return (struct samsung_i2s_dai_data *)
+                               platform_get_device_id(pdev)->driver_data;
 }
 
 #ifdef CONFIG_PM_RUNTIME
@@ -1060,13 +1131,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        struct resource *res;
        u32 regs_base, quirks = 0, idma_addr = 0;
        struct device_node *np = pdev->dev.of_node;
-       enum samsung_dai_type samsung_dai_type;
+       const struct samsung_i2s_dai_data *i2s_dai_data;
        int ret = 0;
 
        /* Call during Seconday interface registration */
-       samsung_dai_type = samsung_i2s_get_driver_data(pdev);
+       i2s_dai_data = samsung_i2s_get_driver_data(pdev);
 
-       if (samsung_dai_type == TYPE_SEC) {
+       if (i2s_dai_data->dai_type == TYPE_SEC) {
                sec_dai = dev_get_drvdata(&pdev->dev);
                if (!sec_dai) {
                        dev_err(&pdev->dev, "Unable to get drvdata\n");
@@ -1075,7 +1146,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                snd_soc_register_component(&sec_dai->pdev->dev,
                                           &samsung_i2s_component,
                                           &sec_dai->i2s_dai_drv, 1);
-               asoc_dma_platform_register(&pdev->dev);
+               samsung_asoc_dma_platform_register(&pdev->dev);
                return 0;
        }
 
@@ -1115,15 +1186,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                        idma_addr = i2s_cfg->idma_addr;
                }
        } else {
-               if (of_find_property(np, "samsung,supports-6ch", NULL))
-                       quirks |= QUIRK_PRI_6CHAN;
-
-               if (of_find_property(np, "samsung,supports-secdai", NULL))
-                       quirks |= QUIRK_SEC_DAI;
-
-               if (of_find_property(np, "samsung,supports-rstclr", NULL))
-                       quirks |= QUIRK_NEED_RSTCLR;
-
+               quirks = i2s_dai_data->quirks;
                if (of_property_read_u32(np, "samsung,idma-addr",
                                         &idma_addr)) {
                        if (quirks & QUIRK_SEC_DAI) {
@@ -1200,7 +1263,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       asoc_dma_platform_register(&pdev->dev);
+       samsung_asoc_dma_platform_register(&pdev->dev);
 
        return 0;
 err:
@@ -1230,33 +1293,59 @@ static int samsung_i2s_remove(struct platform_device *pdev)
        i2s->pri_dai = NULL;
        i2s->sec_dai = NULL;
 
-       asoc_dma_platform_unregister(&pdev->dev);
+       samsung_asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
 
+static const struct samsung_i2s_dai_data i2sv3_dai_type = {
+       .dai_type = TYPE_PRI,
+       .quirks = QUIRK_NO_MUXPSR,
+};
+
+static const struct samsung_i2s_dai_data i2sv5_dai_type = {
+       .dai_type = TYPE_PRI,
+       .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
+};
+
+static const struct samsung_i2s_dai_data i2sv6_dai_type = {
+       .dai_type = TYPE_PRI,
+       .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
+                       QUIRK_SUPPORTS_TDM,
+};
+
+static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
+       .dai_type = TYPE_PRI,
+};
+
+static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
+       .dai_type = TYPE_SEC,
+};
+
 static struct platform_device_id samsung_i2s_driver_ids[] = {
        {
                .name           = "samsung-i2s",
-               .driver_data    = TYPE_PRI,
+               .driver_data    = (kernel_ulong_t)&samsung_dai_type_pri,
        }, {
                .name           = "samsung-i2s-sec",
-               .driver_data    = TYPE_SEC,
+               .driver_data    = (kernel_ulong_t)&samsung_dai_type_sec,
        },
        {},
 };
 MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
 
 #ifdef CONFIG_OF
-static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
-       [TYPE_PRI] = { TYPE_PRI },
-       [TYPE_SEC] = { TYPE_SEC },
-};
-
 static const struct of_device_id exynos_i2s_match[] = {
-       { .compatible = "samsung,i2s-v5",
-         .data = &samsung_i2s_dai_data_array[TYPE_PRI],
+       {
+               .compatible = "samsung,s3c6410-i2s",
+               .data = &i2sv3_dai_type,
+       }, {
+               .compatible = "samsung,s5pv210-i2s",
+               .data = &i2sv5_dai_type,
+       }, {
+               .compatible = "samsung,exynos5420-i2s",
+               .data = &i2sv6_dai_type,
        },
        {},
 };
index 1566afe..e54256f 100644 (file)
@@ -594,7 +594,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
                goto err5;
        }
 
-       ret = asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret);
                goto err6;
@@ -623,7 +623,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev)
        struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id];
        struct resource *mem_res;
 
-       asoc_dma_platform_unregister(&pdev->dev);
+       samsung_asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
index 47e2386..ea885cb 100644 (file)
@@ -176,7 +176,7 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
        if (ret) {
                pr_err("failed to register the DMA: %d\n", ret);
                goto err;
@@ -190,7 +190,7 @@ err:
 
 static int s3c2412_iis_dev_remove(struct platform_device *pdev)
 {
-       asoc_dma_platform_unregister(&pdev->dev);
+       samsung_asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
index 8b34145..9c8ebd8 100644 (file)
@@ -480,7 +480,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
        if (ret) {
                pr_err("failed to register the dma: %d\n", ret);
                goto err;
@@ -494,7 +494,7 @@ err:
 
 static int s3c24xx_iis_dev_remove(struct platform_device *pdev)
 {
-       asoc_dma_platform_unregister(&pdev->dev);
+       samsung_asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
index 581ea4a..5fd7a05 100644 (file)
@@ -11,6 +11,7 @@
 #include <sound/pcm_params.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 
  /*
   * Default CFG switch settings to use this driver:
 /* SMDK has a 16.934MHZ crystal attached to WM8994 */
 #define SMDK_WM8994_FREQ 16934000
 
+struct smdk_wm8994_data {
+       int mclk1_rate;
+};
+
+/* Default SMDKs */
+static struct smdk_wm8994_data smdk_board_data = {
+       .mclk1_rate = SMDK_WM8994_FREQ,
+};
+
 static int smdk_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pll_out;
        int ret;
@@ -54,18 +63,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        else
                pll_out = params_rate(params) * 256;
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1,
                                        SMDK_WM8994_FREQ, pll_out);
        if (ret < 0)
@@ -131,6 +128,8 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .platform_name = "samsung-i2s.0",
                .codec_name = "wm8994-codec",
                .init = smdk_wm8994_init_paiftx,
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM,
                .ops = &smdk_ops,
        }, { /* Sec_Fifo Playback i/f */
                .name = "Sec_FIFO TX",
@@ -139,6 +138,8 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8994-aif1",
                .platform_name = "samsung-i2s-sec",
                .codec_name = "wm8994-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBM_CFM,
                .ops = &smdk_ops,
        },
 };
@@ -150,15 +151,28 @@ static struct snd_soc_card smdk = {
        .num_links = ARRAY_SIZE(smdk_dai),
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id samsung_wm8994_of_match[] = {
+       { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
+       {},
+};
+MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
+#endif /* CONFIG_OF */
 
 static int smdk_audio_probe(struct platform_device *pdev)
 {
        int ret;
        struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &smdk;
+       struct smdk_wm8994_data *board;
+       const struct of_device_id *id;
 
        card->dev = &pdev->dev;
 
+       board = devm_kzalloc(&pdev->dev, sizeof(*board), GFP_KERNEL);
+       if (!board)
+               return -ENOMEM;
+
        if (np) {
                smdk_dai[0].cpu_dai_name = NULL;
                smdk_dai[0].cpu_of_node = of_parse_phandle(np,
@@ -173,6 +187,12 @@ static int smdk_audio_probe(struct platform_device *pdev)
                smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node;
        }
 
+       id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
+       if (id)
+               *board = *((struct smdk_wm8994_data *)id->data);
+
+       platform_set_drvdata(pdev, board);
+
        ret = snd_soc_register_card(card);
 
        if (ret)
@@ -190,17 +210,9 @@ static int smdk_audio_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id samsung_wm8994_of_match[] = {
-       { .compatible = "samsung,smdk-wm8994", },
-       {},
-};
-MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
-#endif /* CONFIG_OF */
-
 static struct platform_driver smdk_audio_driver = {
        .driver         = {
-               .name   = "smdk-audio",
+               .name   = "smdk-audio-wm8894",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(samsung_wm8994_of_match),
        },
@@ -212,4 +224,4 @@ module_platform_driver(smdk_audio_driver);
 
 MODULE_DESCRIPTION("ALSA SoC SMDK WM8994");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:smdk-audio");
+MODULE_ALIAS("platform:smdk-audio-wm8994");
index 2e5ebb2..28487dc 100644 (file)
@@ -395,7 +395,7 @@ static int spdif_probe(struct platform_device *pdev)
 
        spin_lock_init(&spdif->lock);
 
-       spdif->pclk = clk_get(&pdev->dev, "spdif");
+       spdif->pclk = devm_clk_get(&pdev->dev, "spdif");
        if (IS_ERR(spdif->pclk)) {
                dev_err(&pdev->dev, "failed to get peri-clock\n");
                ret = -ENOENT;
@@ -403,7 +403,7 @@ static int spdif_probe(struct platform_device *pdev)
        }
        clk_prepare_enable(spdif->pclk);
 
-       spdif->sclk = clk_get(&pdev->dev, "sclk_spdif");
+       spdif->sclk = devm_clk_get(&pdev->dev, "sclk_spdif");
        if (IS_ERR(spdif->sclk)) {
                dev_err(&pdev->dev, "failed to get internal source clock\n");
                ret = -ENOENT;
@@ -442,7 +442,7 @@ static int spdif_probe(struct platform_device *pdev)
 
        spdif->dma_playback = &spdif_stereo_out;
 
-       ret = asoc_dma_platform_register(&pdev->dev);
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "failed to register DMA: %d\n", ret);
                goto err5;
@@ -457,10 +457,8 @@ err3:
        release_mem_region(mem_res->start, resource_size(mem_res));
 err2:
        clk_disable_unprepare(spdif->sclk);
-       clk_put(spdif->sclk);
 err1:
        clk_disable_unprepare(spdif->pclk);
-       clk_put(spdif->pclk);
 err0:
        return ret;
 }
@@ -470,7 +468,7 @@ static int spdif_remove(struct platform_device *pdev)
        struct samsung_spdif_info *spdif = &spdif_info;
        struct resource *mem_res;
 
-       asoc_dma_platform_unregister(&pdev->dev);
+       samsung_asoc_dma_platform_unregister(&pdev->dev);
        snd_soc_unregister_component(&pdev->dev);
 
        iounmap(spdif->regs);
@@ -480,9 +478,7 @@ static int spdif_remove(struct platform_device *pdev)
                release_mem_region(mem_res->start, resource_size(mem_res));
 
        clk_disable_unprepare(spdif->sclk);
-       clk_put(spdif->sclk);
        clk_disable_unprepare(spdif->pclk);
-       clk_put(spdif->pclk);
 
        return 0;
 }
index 6bcb116..56d8ff6 100644 (file)
@@ -34,6 +34,13 @@ config SND_SOC_SH4_SIU
        select SH_DMAE
        select FW_LOADER
 
+config SND_SOC_RCAR
+       tristate "R-Car series SRU/SCU/SSIU/SSI support"
+       select SND_SIMPLE_CARD
+       select RCAR_CLK_ADG
+       help
+         This option enables R-Car SUR/SCU/SSIU/SSI sound support
+
 ##
 ## Boards
 ##
index 849b387..aaf3dcd 100644 (file)
@@ -12,6 +12,9 @@ obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o
 obj-$(CONFIG_SND_SOC_SH4_FSI)  += snd-soc-fsi.o
 obj-$(CONFIG_SND_SOC_SH4_SIU)  += snd-soc-siu.o
 
+## audio units for R-Car
+obj-$(CONFIG_SND_SOC_RCAR)     += rcar/
+
 ## boards
 snd-soc-sh7760-ac97-objs       := sh7760-ac97.o
 snd-soc-migor-objs             := migor.o
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile
new file mode 100644 (file)
index 0000000..0ff492d
--- /dev/null
@@ -0,0 +1,2 @@
+snd-soc-rcar-objs      := core.o gen.o scu.o adg.o ssi.o
+obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
\ No newline at end of file
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
new file mode 100644 (file)
index 0000000..d80deb7
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * Helper routines for R-Car sound ADG.
+ *
+ *  Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/sh_clk.h>
+#include <mach/clock.h>
+#include "rsnd.h"
+
+#define CLKA   0
+#define CLKB   1
+#define CLKC   2
+#define CLKI   3
+#define CLKMAX 4
+
+struct rsnd_adg {
+       struct clk *clk[CLKMAX];
+
+       int rate_of_441khz_div_6;
+       int rate_of_48khz_div_6;
+};
+
+#define for_each_rsnd_clk(pos, adg, i)         \
+       for (i = 0, (pos) = adg->clk[i];        \
+            i < CLKMAX;                        \
+            i++, (pos) = adg->clk[i])
+#define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg)
+
+static enum rsnd_reg rsnd_adg_ssi_reg_get(int id)
+{
+       enum rsnd_reg reg;
+
+       /*
+        * SSI 8 is not connected to ADG.
+        * it works with SSI 7
+        */
+       if (id == 8)
+               return RSND_REG_MAX;
+
+       if (0 <= id && id <= 3)
+               reg = RSND_REG_AUDIO_CLK_SEL0;
+       else if (4 <= id && id <= 7)
+               reg = RSND_REG_AUDIO_CLK_SEL1;
+       else
+               reg = RSND_REG_AUDIO_CLK_SEL2;
+
+       return reg;
+}
+
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       enum rsnd_reg reg;
+       int id;
+
+       /*
+        * "mod" = "ssi" here.
+        * we can get "ssi id" from mod
+        */
+       id  = rsnd_mod_id(mod);
+       reg = rsnd_adg_ssi_reg_get(id);
+
+       rsnd_write(priv, mod, reg, 0);
+
+       return 0;
+}
+
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_adg *adg = rsnd_priv_to_adg(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       enum rsnd_reg reg;
+       int id, shift, i;
+       u32 data;
+       int sel_table[] = {
+               [CLKA] = 0x1,
+               [CLKB] = 0x2,
+               [CLKC] = 0x3,
+               [CLKI] = 0x0,
+       };
+
+       dev_dbg(dev, "request clock = %d\n", rate);
+
+       /*
+        * find suitable clock from
+        * AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC/AUDIO_CLKI.
+        */
+       data = 0;
+       for_each_rsnd_clk(clk, adg, i) {
+               if (rate == clk_get_rate(clk)) {
+                       data = sel_table[i];
+                       goto found_clock;
+               }
+       }
+
+       /*
+        * find 1/6 clock from BRGA/BRGB
+        */
+       if (rate == adg->rate_of_441khz_div_6) {
+               data = 0x10;
+               goto found_clock;
+       }
+
+       if (rate == adg->rate_of_48khz_div_6) {
+               data = 0x20;
+               goto found_clock;
+       }
+
+       return -EIO;
+
+found_clock:
+
+       /*
+        * This "mod" = "ssi" here.
+        * we can get "ssi id" from mod
+        */
+       id  = rsnd_mod_id(mod);
+       reg = rsnd_adg_ssi_reg_get(id);
+
+       dev_dbg(dev, "ADG: ssi%d selects clk%d = %d", id, i, rate);
+
+       /*
+        * Enable SSIx clock
+        */
+       shift = (id % 4) * 8;
+
+       rsnd_bset(priv, mod, reg,
+                  0xFF << shift,
+                  data << shift);
+
+       return 0;
+}
+
+static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg)
+{
+       struct clk *clk;
+       unsigned long rate;
+       u32 ckr;
+       int i;
+       int brg_table[] = {
+               [CLKA] = 0x0,
+               [CLKB] = 0x1,
+               [CLKC] = 0x4,
+               [CLKI] = 0x2,
+       };
+
+       /*
+        * This driver is assuming that AUDIO_CLKA/AUDIO_CLKB/AUDIO_CLKC
+        * have 44.1kHz or 48kHz base clocks for now.
+        *
+        * SSI itself can divide parent clock by 1/1 - 1/16
+        * So,  BRGA outputs 44.1kHz base parent clock 1/32,
+        * and, BRGB outputs 48.0kHz base parent clock 1/32 here.
+        * see
+        *      rsnd_adg_ssi_clk_try_start()
+        */
+       ckr = 0;
+       adg->rate_of_441khz_div_6 = 0;
+       adg->rate_of_48khz_div_6  = 0;
+       for_each_rsnd_clk(clk, adg, i) {
+               rate = clk_get_rate(clk);
+
+               if (0 == rate) /* not used */
+                       continue;
+
+               /* RBGA */
+               if (!adg->rate_of_441khz_div_6 && (0 == rate % 44100)) {
+                       adg->rate_of_441khz_div_6 = rate / 6;
+                       ckr |= brg_table[i] << 20;
+               }
+
+               /* RBGB */
+               if (!adg->rate_of_48khz_div_6 && (0 == rate % 48000)) {
+                       adg->rate_of_48khz_div_6 = rate / 6;
+                       ckr |= brg_table[i] << 16;
+               }
+       }
+
+       rsnd_priv_bset(priv, SSICKR, 0x00FF0000, ckr);
+       rsnd_priv_write(priv, BRRA,  0x00000002); /* 1/6 */
+       rsnd_priv_write(priv, BRRB,  0x00000002); /* 1/6 */
+}
+
+int rsnd_adg_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct clk *clk;
+       int i;
+
+       adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL);
+       if (!adg) {
+               dev_err(dev, "ADG allocate failed\n");
+               return -ENOMEM;
+       }
+
+       adg->clk[CLKA] = clk_get(NULL, "audio_clk_a");
+       adg->clk[CLKB] = clk_get(NULL, "audio_clk_b");
+       adg->clk[CLKC] = clk_get(NULL, "audio_clk_c");
+       adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal");
+       for_each_rsnd_clk(clk, adg, i) {
+               if (IS_ERR(clk)) {
+                       dev_err(dev, "Audio clock failed\n");
+                       return -EIO;
+               }
+       }
+
+       rsnd_adg_ssi_clk_init(priv, adg);
+
+       priv->adg = adg;
+
+       dev_dbg(dev, "adg probed\n");
+
+       return 0;
+}
+
+void rsnd_adg_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_adg *adg = priv->adg;
+       struct clk *clk;
+       int i;
+
+       for_each_rsnd_clk(clk, adg, i)
+               clk_put(clk);
+}
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
new file mode 100644 (file)
index 0000000..a357060
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ * Renesas R-Car SRU/SCU/SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on fsi.c
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/*
+ * Renesas R-Car sound device structure
+ *
+ * Gen1
+ *
+ * SRU         : Sound Routing Unit
+ *  - SRC      : Sampling Rate Converter
+ *  - CMD
+ *    - CTU    : Channel Count Conversion Unit
+ *    - MIX    : Mixer
+ *    - DVC    : Digital Volume and Mute Function
+ *  - SSI      : Serial Sound Interface
+ *
+ * Gen2
+ *
+ * SCU         : Sampling Rate Converter Unit
+ *  - SRC      : Sampling Rate Converter
+ *  - CMD
+ *   - CTU     : Channel Count Conversion Unit
+ *   - MIX     : Mixer
+ *   - DVC     : Digital Volume and Mute Function
+ * SSIU                : Serial Sound Interface Unit
+ *  - SSI      : Serial Sound Interface
+ */
+
+/*
+ *     driver data Image
+ *
+ * rsnd_priv
+ *   |
+ *   | ** this depends on Gen1/Gen2
+ *   |
+ *   +- gen
+ *   |
+ *   | ** these depend on data path
+ *   | ** gen and platform data control it
+ *   |
+ *   +- rdai[0]
+ *   |   |              sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |              sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   |
+ *   +- rdai[1]
+ *   |   |              sru     ssiu      ssi
+ *   |   +- playback -> [mod] -> [mod] -> [mod] -> ...
+ *   |   |
+ *   |   |              sru     ssiu      ssi
+ *   |   +- capture  -> [mod] -> [mod] -> [mod] -> ...
+ *   ...
+ *   |
+ *   | ** these control ssi
+ *   |
+ *   +- ssi
+ *   |  |
+ *   |  +- ssi[0]
+ *   |  +- ssi[1]
+ *   |  +- ssi[2]
+ *   |  ...
+ *   |
+ *   | ** these control scu
+ *   |
+ *   +- scu
+ *      |
+ *      +- scu[0]
+ *      +- scu[1]
+ *      +- scu[2]
+ *      ...
+ *
+ *
+ * for_each_rsnd_dai(xx, priv, xx)
+ *  rdai[0] => rdai[1] => rdai[2] => ...
+ *
+ * for_each_rsnd_mod(xx, rdai, xx)
+ *  [mod] => [mod] => [mod] => ...
+ *
+ * rsnd_dai_call(xxx, fn )
+ *  [mod]->fn() -> [mod]->fn() -> [mod]->fn()...
+ *
+ */
+#include <linux/pm_runtime.h>
+#include "rsnd.h"
+
+#define RSND_RATES SNDRV_PCM_RATE_8000_96000
+#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
+
+/*
+ *     rsnd_platform functions
+ */
+#define rsnd_platform_call(priv, dai, func, param...)  \
+       (!(priv->info->func) ? -ENODEV :                \
+        priv->info->func(param))
+
+
+/*
+ *     basic function
+ */
+u32 rsnd_read(struct rsnd_priv *priv,
+             struct rsnd_mod *mod, enum rsnd_reg reg)
+{
+       void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+
+       BUG_ON(!base);
+
+       return ioread32(base);
+}
+
+void rsnd_write(struct rsnd_priv *priv,
+               struct rsnd_mod *mod,
+               enum rsnd_reg reg, u32 data)
+{
+       void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       BUG_ON(!base);
+
+       dev_dbg(dev, "w %p : %08x\n", base, data);
+
+       iowrite32(data, base);
+}
+
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
+              enum rsnd_reg reg, u32 mask, u32 data)
+{
+       void __iomem *base = rsnd_gen_reg_get(priv, mod, reg);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 val;
+
+       BUG_ON(!base);
+
+       val = ioread32(base);
+       val &= ~mask;
+       val |= data & mask;
+       iowrite32(val, base);
+
+       dev_dbg(dev, "s %p : %08x\n", base, val);
+}
+
+/*
+ *     rsnd_mod functions
+ */
+char *rsnd_mod_name(struct rsnd_mod *mod)
+{
+       if (!mod || !mod->ops)
+               return "unknown";
+
+       return mod->ops->name;
+}
+
+void rsnd_mod_init(struct rsnd_priv *priv,
+                  struct rsnd_mod *mod,
+                  struct rsnd_mod_ops *ops,
+                  int id)
+{
+       mod->priv       = priv;
+       mod->id         = id;
+       mod->ops        = ops;
+       INIT_LIST_HEAD(&mod->list);
+}
+
+/*
+ *     rsnd_dma functions
+ */
+static void rsnd_dma_continue(struct rsnd_dma *dma)
+{
+       /* push next A or B plane */
+       dma->submit_loop = 1;
+       schedule_work(&dma->work);
+}
+
+void rsnd_dma_start(struct rsnd_dma *dma)
+{
+       /* push both A and B plane*/
+       dma->submit_loop = 2;
+       schedule_work(&dma->work);
+}
+
+void rsnd_dma_stop(struct rsnd_dma *dma)
+{
+       dma->submit_loop = 0;
+       cancel_work_sync(&dma->work);
+       dmaengine_terminate_all(dma->chan);
+}
+
+static void rsnd_dma_complete(void *data)
+{
+       struct rsnd_dma *dma = (struct rsnd_dma *)data;
+       struct rsnd_priv *priv = dma->priv;
+       unsigned long flags;
+
+       rsnd_lock(priv, flags);
+
+       dma->complete(dma);
+
+       if (dma->submit_loop)
+               rsnd_dma_continue(dma);
+
+       rsnd_unlock(priv, flags);
+}
+
+static void rsnd_dma_do_work(struct work_struct *work)
+{
+       struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work);
+       struct rsnd_priv *priv = dma->priv;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct dma_async_tx_descriptor *desc;
+       dma_addr_t buf;
+       size_t len;
+       int i;
+
+       for (i = 0; i < dma->submit_loop; i++) {
+
+               if (dma->inquiry(dma, &buf, &len) < 0)
+                       return;
+
+               desc = dmaengine_prep_slave_single(
+                       dma->chan, buf, len, dma->dir,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+               if (!desc) {
+                       dev_err(dev, "dmaengine_prep_slave_sg() fail\n");
+                       return;
+               }
+
+               desc->callback          = rsnd_dma_complete;
+               desc->callback_param    = dma;
+
+               if (dmaengine_submit(desc) < 0) {
+                       dev_err(dev, "dmaengine_submit() fail\n");
+                       return;
+               }
+
+       }
+
+       dma_async_issue_pending(dma->chan);
+}
+
+int rsnd_dma_available(struct rsnd_dma *dma)
+{
+       return !!dma->chan;
+}
+
+static bool rsnd_dma_filter(struct dma_chan *chan, void *param)
+{
+       chan->private = param;
+
+       return true;
+}
+
+int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
+                 int is_play, int id,
+                 int (*inquiry)(struct rsnd_dma *dma,
+                                 dma_addr_t *buf, int *len),
+                 int (*complete)(struct rsnd_dma *dma))
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       dma_cap_mask_t mask;
+
+       if (dma->chan) {
+               dev_err(dev, "it already has dma channel\n");
+               return -EIO;
+       }
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+
+       dma->slave.shdma_slave.slave_id = id;
+
+       dma->chan = dma_request_channel(mask, rsnd_dma_filter,
+                                       &dma->slave.shdma_slave);
+       if (!dma->chan) {
+               dev_err(dev, "can't get dma channel\n");
+               return -EIO;
+       }
+
+       dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
+       dma->priv = priv;
+       dma->inquiry = inquiry;
+       dma->complete = complete;
+       INIT_WORK(&dma->work, rsnd_dma_do_work);
+
+       return 0;
+}
+
+void  rsnd_dma_quit(struct rsnd_priv *priv,
+                   struct rsnd_dma *dma)
+{
+       if (dma->chan)
+               dma_release_channel(dma->chan);
+
+       dma->chan = NULL;
+}
+
+/*
+ *     rsnd_dai functions
+ */
+#define rsnd_dai_call(rdai, io, fn)                    \
+({                                                     \
+       struct rsnd_mod *mod, *n;                       \
+       int ret = 0;                                    \
+       for_each_rsnd_mod(mod, n, io) {                 \
+               ret = rsnd_mod_call(mod, fn, rdai, io); \
+               if (ret < 0)                            \
+                       break;                          \
+       }                                               \
+       ret;                                            \
+})
+
+int rsnd_dai_connect(struct rsnd_dai *rdai,
+                    struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       if (!mod) {
+               dev_err(dev, "NULL mod\n");
+               return -EIO;
+       }
+
+       if (!list_empty(&mod->list)) {
+               dev_err(dev, "%s%d is not empty\n",
+                       rsnd_mod_name(mod),
+                       rsnd_mod_id(mod));
+               return -EIO;
+       }
+
+       list_add_tail(&mod->list, &io->head);
+
+       return 0;
+}
+
+int rsnd_dai_disconnect(struct rsnd_mod *mod)
+{
+       list_del_init(&mod->list);
+
+       return 0;
+}
+
+int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
+{
+       int id = rdai - priv->rdai;
+
+       if ((id < 0) || (id >= rsnd_dai_nr(priv)))
+               return -EINVAL;
+
+       return id;
+}
+
+struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
+{
+       return priv->rdai + id;
+}
+
+static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+       return rsnd_dai_get(priv, dai->id);
+}
+
+int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io)
+{
+       return &rdai->playback == io;
+}
+
+/*
+ *     rsnd_soc_dai functions
+ */
+int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
+{
+       struct snd_pcm_substream *substream = io->substream;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int pos = io->byte_pos + additional;
+
+       pos %= (runtime->periods * io->byte_per_period);
+
+       return pos;
+}
+
+void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
+{
+       io->byte_pos += byte;
+
+       if (io->byte_pos >= io->next_period_byte) {
+               struct snd_pcm_substream *substream = io->substream;
+               struct snd_pcm_runtime *runtime = substream->runtime;
+
+               io->period_pos++;
+               io->next_period_byte += io->byte_per_period;
+
+               if (io->period_pos >= runtime->periods) {
+                       io->byte_pos = 0;
+                       io->period_pos = 0;
+                       io->next_period_byte = io->byte_per_period;
+               }
+
+               snd_pcm_period_elapsed(substream);
+       }
+}
+
+static int rsnd_dai_stream_init(struct rsnd_dai_stream *io,
+                               struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (!list_empty(&io->head))
+               return -EIO;
+
+       INIT_LIST_HEAD(&io->head);
+       io->substream           = substream;
+       io->byte_pos            = 0;
+       io->period_pos          = 0;
+       io->byte_per_period     = runtime->period_size *
+                                 runtime->channels *
+                                 samples_to_bytes(runtime, 1);
+       io->next_period_byte    = io->byte_per_period;
+
+       return 0;
+}
+
+static
+struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+       return  rtd->cpu_dai;
+}
+
+static
+struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai,
+                                       struct snd_pcm_substream *substream)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return &rdai->playback;
+       else
+               return &rdai->capture;
+}
+
+static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+                           struct snd_soc_dai *dai)
+{
+       struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+       struct rsnd_mod *mod = rsnd_ssi_mod_get_frm_dai(priv,
+                                               rsnd_dai_id(priv, rdai),
+                                               rsnd_dai_is_play(rdai, io));
+       int ssi_id = rsnd_mod_id(mod);
+       int ret;
+       unsigned long flags;
+
+       rsnd_lock(priv, flags);
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+               ret = rsnd_dai_stream_init(io, substream);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_platform_call(priv, dai, start, ssi_id);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_gen_path_init(priv, rdai, io);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(rdai, io, init);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(rdai, io, start);
+               if (ret < 0)
+                       goto dai_trigger_end;
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               ret = rsnd_dai_call(rdai, io, stop);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_dai_call(rdai, io, quit);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_gen_path_exit(priv, rdai, io);
+               if (ret < 0)
+                       goto dai_trigger_end;
+
+               ret = rsnd_platform_call(priv, dai, stop, ssi_id);
+               if (ret < 0)
+                       goto dai_trigger_end;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+dai_trigger_end:
+       rsnd_unlock(priv, flags);
+
+       return ret;
+}
+
+static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+
+       /* set master/slave audio interface */
+       switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+               rdai->clk_master = 1;
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:
+               rdai->clk_master = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* set clock inversion */
+       switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               rdai->bit_clk_inv = 0;
+               rdai->frm_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_IB_NF:
+               rdai->bit_clk_inv = 1;
+               rdai->frm_clk_inv = 0;
+               break;
+       case SND_SOC_DAIFMT_IB_IF:
+               rdai->bit_clk_inv = 1;
+               rdai->frm_clk_inv = 1;
+               break;
+       case SND_SOC_DAIFMT_NB_NF:
+       default:
+               rdai->bit_clk_inv = 0;
+               rdai->frm_clk_inv = 0;
+               break;
+       }
+
+       /* set format */
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_I2S:
+               rdai->sys_delay = 0;
+               rdai->data_alignment = 0;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               rdai->sys_delay = 1;
+               rdai->data_alignment = 0;
+               break;
+       case SND_SOC_DAIFMT_RIGHT_J:
+               rdai->sys_delay = 1;
+               rdai->data_alignment = 1;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+       .trigger        = rsnd_soc_dai_trigger,
+       .set_fmt        = rsnd_soc_dai_set_fmt,
+};
+
+static int rsnd_dai_probe(struct platform_device *pdev,
+                         struct rcar_snd_info *info,
+                         struct rsnd_priv *priv)
+{
+       struct snd_soc_dai_driver *drv;
+       struct rsnd_dai *rdai;
+       struct rsnd_mod *pmod, *cmod;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int dai_nr;
+       int i;
+
+       /* get max dai nr */
+       for (dai_nr = 0; dai_nr < 32; dai_nr++) {
+               pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1);
+               cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0);
+
+               if (!pmod && !cmod)
+                       break;
+       }
+
+       if (!dai_nr) {
+               dev_err(dev, "no dai\n");
+               return -EIO;
+       }
+
+       drv  = devm_kzalloc(dev, sizeof(*drv)  * dai_nr, GFP_KERNEL);
+       rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
+       if (!drv || !rdai) {
+               dev_err(dev, "dai allocate failed\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < dai_nr; i++) {
+
+               pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1);
+               cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0);
+
+               /*
+                *      init rsnd_dai
+                */
+               INIT_LIST_HEAD(&rdai[i].playback.head);
+               INIT_LIST_HEAD(&rdai[i].capture.head);
+
+               snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
+
+               /*
+                *      init snd_soc_dai_driver
+                */
+               drv[i].name     = rdai[i].name;
+               drv[i].ops      = &rsnd_soc_dai_ops;
+               if (pmod) {
+                       drv[i].playback.rates           = RSND_RATES;
+                       drv[i].playback.formats         = RSND_FMTS;
+                       drv[i].playback.channels_min    = 2;
+                       drv[i].playback.channels_max    = 2;
+               }
+               if (cmod) {
+                       drv[i].capture.rates            = RSND_RATES;
+                       drv[i].capture.formats          = RSND_FMTS;
+                       drv[i].capture.channels_min     = 2;
+                       drv[i].capture.channels_max     = 2;
+               }
+
+               dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
+                       pmod ? "play"    : " -- ",
+                       cmod ? "capture" : "  --   ");
+       }
+
+       priv->dai_nr    = dai_nr;
+       priv->daidrv    = drv;
+       priv->rdai      = rdai;
+
+       return 0;
+}
+
+static void rsnd_dai_remove(struct platform_device *pdev,
+                         struct rsnd_priv *priv)
+{
+}
+
+/*
+ *             pcm ops
+ */
+static struct snd_pcm_hardware rsnd_pcm_hardware = {
+       .info =         SNDRV_PCM_INFO_INTERLEAVED      |
+                       SNDRV_PCM_INFO_MMAP             |
+                       SNDRV_PCM_INFO_MMAP_VALID       |
+                       SNDRV_PCM_INFO_PAUSE,
+       .formats                = RSND_FMTS,
+       .rates                  = RSND_RATES,
+       .rate_min               = 8000,
+       .rate_max               = 192000,
+       .channels_min           = 2,
+       .channels_max           = 2,
+       .buffer_bytes_max       = 64 * 1024,
+       .period_bytes_min       = 32,
+       .period_bytes_max       = 8192,
+       .periods_min            = 1,
+       .periods_max            = 32,
+       .fifo_size              = 256,
+};
+
+static int rsnd_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int ret = 0;
+
+       snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware);
+
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+
+       return ret;
+}
+
+static int rsnd_hw_params(struct snd_pcm_substream *substream,
+                        struct snd_pcm_hw_params *hw_params)
+{
+       return snd_pcm_lib_malloc_pages(substream,
+                                       params_buffer_bytes(hw_params));
+}
+
+static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
+       struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+       struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+
+       return bytes_to_frames(runtime, io->byte_pos);
+}
+
+static struct snd_pcm_ops rsnd_pcm_ops = {
+       .open           = rsnd_pcm_open,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .hw_params      = rsnd_hw_params,
+       .hw_free        = snd_pcm_lib_free_pages,
+       .pointer        = rsnd_pointer,
+};
+
+/*
+ *             snd_soc_platform
+ */
+
+#define PREALLOC_BUFFER                (32 * 1024)
+#define PREALLOC_BUFFER_MAX    (32 * 1024)
+
+static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return snd_pcm_lib_preallocate_pages_for_all(
+               rtd->pcm,
+               SNDRV_DMA_TYPE_DEV,
+               rtd->card->snd_card->dev,
+               PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
+}
+
+static void rsnd_pcm_free(struct snd_pcm *pcm)
+{
+       snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static struct snd_soc_platform_driver rsnd_soc_platform = {
+       .ops            = &rsnd_pcm_ops,
+       .pcm_new        = rsnd_pcm_new,
+       .pcm_free       = rsnd_pcm_free,
+};
+
+static const struct snd_soc_component_driver rsnd_soc_component = {
+       .name           = "rsnd",
+};
+
+/*
+ *     rsnd probe
+ */
+static int rsnd_probe(struct platform_device *pdev)
+{
+       struct rcar_snd_info *info;
+       struct rsnd_priv *priv;
+       struct device *dev = &pdev->dev;
+       int ret;
+
+       info = pdev->dev.platform_data;
+       if (!info) {
+               dev_err(dev, "driver needs R-Car sound information\n");
+               return -ENODEV;
+       }
+
+       /*
+        *      init priv data
+        */
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(dev, "priv allocate failed\n");
+               return -ENODEV;
+       }
+
+       priv->dev       = dev;
+       priv->info      = info;
+       spin_lock_init(&priv->lock);
+
+       /*
+        *      init each module
+        */
+       ret = rsnd_gen_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_scu_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_adg_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_ssi_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_dai_probe(pdev, info, priv);
+       if (ret < 0)
+               return ret;
+
+       /*
+        *      asoc register
+        */
+       ret = snd_soc_register_platform(dev, &rsnd_soc_platform);
+       if (ret < 0) {
+               dev_err(dev, "cannot snd soc register\n");
+               return ret;
+       }
+
+       ret = snd_soc_register_component(dev, &rsnd_soc_component,
+                                        priv->daidrv, rsnd_dai_nr(priv));
+       if (ret < 0) {
+               dev_err(dev, "cannot snd dai register\n");
+               goto exit_snd_soc;
+       }
+
+       dev_set_drvdata(dev, priv);
+
+       pm_runtime_enable(dev);
+
+       dev_info(dev, "probed\n");
+       return ret;
+
+exit_snd_soc:
+       snd_soc_unregister_platform(dev);
+
+       return ret;
+}
+
+static int rsnd_remove(struct platform_device *pdev)
+{
+       struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       /*
+        *      remove each module
+        */
+       rsnd_ssi_remove(pdev, priv);
+       rsnd_adg_remove(pdev, priv);
+       rsnd_scu_remove(pdev, priv);
+       rsnd_dai_remove(pdev, priv);
+       rsnd_gen_remove(pdev, priv);
+
+       return 0;
+}
+
+static struct platform_driver rsnd_driver = {
+       .driver = {
+               .name   = "rcar_sound",
+       },
+       .probe          = rsnd_probe,
+       .remove         = rsnd_remove,
+};
+module_platform_driver(rsnd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Renesas R-Car audio driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_ALIAS("platform:rcar-pcm-audio");
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
new file mode 100644 (file)
index 0000000..babb203
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Renesas R-Car Gen1 SRU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_gen_ops {
+       int (*path_init)(struct rsnd_priv *priv,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io);
+       int (*path_exit)(struct rsnd_priv *priv,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io);
+};
+
+struct rsnd_gen_reg_map {
+       int index;      /* -1 : not supported */
+       u32 offset_id;  /* offset of ssi0, ssi1, ssi2... */
+       u32 offset_adr; /* offset of SSICR, SSISR, ... */
+};
+
+struct rsnd_gen {
+       void __iomem *base[RSND_BASE_MAX];
+
+       struct rsnd_gen_reg_map reg_map[RSND_REG_MAX];
+       struct rsnd_gen_ops *ops;
+};
+
+#define rsnd_priv_to_gen(p)    ((struct rsnd_gen *)(p)->gen)
+
+/*
+ *             Gen2
+ *             will be filled in the future
+ */
+
+/*
+ *             Gen1
+ */
+static int rsnd_gen1_path_init(struct rsnd_priv *priv,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod;
+       int ret;
+       int id;
+
+       /*
+        * Gen1 is created by SRU/SSI, and this SRU is base module of
+        * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
+        *
+        * Easy image is..
+        *      Gen1 SRU = Gen2 SCU + SSIU + etc
+        *
+        * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
+        * using fixed path.
+        *
+        * Then, SSI id = SCU id here
+        */
+
+       /* get SSI's ID */
+       mod = rsnd_ssi_mod_get_frm_dai(priv,
+                                      rsnd_dai_id(priv, rdai),
+                                      rsnd_dai_is_play(rdai, io));
+       id = rsnd_mod_id(mod);
+
+       /* SSI */
+       mod = rsnd_ssi_mod_get(priv, id);
+       ret = rsnd_dai_connect(rdai, mod, io);
+       if (ret < 0)
+               return ret;
+
+       /* SCU */
+       mod = rsnd_scu_mod_get(priv, id);
+       ret = rsnd_dai_connect(rdai, mod, io);
+
+       return ret;
+}
+
+static int rsnd_gen1_path_exit(struct rsnd_priv *priv,
+                              struct rsnd_dai *rdai,
+                              struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *mod, *n;
+       int ret = 0;
+
+       /*
+        * remove all mod from rdai
+        */
+       for_each_rsnd_mod(mod, n, io)
+               ret |= rsnd_dai_disconnect(mod);
+
+       return ret;
+}
+
+static struct rsnd_gen_ops rsnd_gen1_ops = {
+       .path_init      = rsnd_gen1_path_init,
+       .path_exit      = rsnd_gen1_path_exit,
+};
+
+#define RSND_GEN1_REG_MAP(g, s, i, oi, oa)                             \
+       do {                                                            \
+               (g)->reg_map[RSND_REG_##i].index  = RSND_GEN1_##s;      \
+               (g)->reg_map[RSND_REG_##i].offset_id = oi;              \
+               (g)->reg_map[RSND_REG_##i].offset_adr = oa;             \
+       } while (0)
+
+static void rsnd_gen1_reg_map_init(struct rsnd_gen *gen)
+{
+       RSND_GEN1_REG_MAP(gen, SRU,     SRC_ROUTE_SEL,  0x0,    0x00);
+       RSND_GEN1_REG_MAP(gen, SRU,     SRC_TMG_SEL0,   0x0,    0x08);
+       RSND_GEN1_REG_MAP(gen, SRU,     SRC_TMG_SEL1,   0x0,    0x0c);
+       RSND_GEN1_REG_MAP(gen, SRU,     SRC_TMG_SEL2,   0x0,    0x10);
+       RSND_GEN1_REG_MAP(gen, SRU,     SRC_CTRL,       0x0,    0xc0);
+       RSND_GEN1_REG_MAP(gen, SRU,     SSI_MODE0,      0x0,    0xD0);
+       RSND_GEN1_REG_MAP(gen, SRU,     SSI_MODE1,      0x0,    0xD4);
+       RSND_GEN1_REG_MAP(gen, SRU,     BUSIF_MODE,     0x4,    0x20);
+       RSND_GEN1_REG_MAP(gen, SRU,     BUSIF_ADINR,    0x40,   0x214);
+
+       RSND_GEN1_REG_MAP(gen, ADG,     BRRA,           0x0,    0x00);
+       RSND_GEN1_REG_MAP(gen, ADG,     BRRB,           0x0,    0x04);
+       RSND_GEN1_REG_MAP(gen, ADG,     SSICKR,         0x0,    0x08);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL0, 0x0,    0x0c);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL1, 0x0,    0x10);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL3, 0x0,    0x18);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL4, 0x0,    0x1c);
+       RSND_GEN1_REG_MAP(gen, ADG,     AUDIO_CLK_SEL5, 0x0,    0x20);
+
+       RSND_GEN1_REG_MAP(gen, SSI,     SSICR,          0x40,   0x00);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSISR,          0x40,   0x04);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSITDR,         0x40,   0x08);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSIRDR,         0x40,   0x0c);
+       RSND_GEN1_REG_MAP(gen, SSI,     SSIWSR,         0x40,   0x20);
+}
+
+static int rsnd_gen1_probe(struct platform_device *pdev,
+                          struct rcar_snd_info *info,
+                          struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       struct resource *sru_res;
+       struct resource *adg_res;
+       struct resource *ssi_res;
+
+       /*
+        * map address
+        */
+       sru_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SRU);
+       adg_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_ADG);
+       ssi_res = platform_get_resource(pdev, IORESOURCE_MEM, RSND_GEN1_SSI);
+
+       gen->base[RSND_GEN1_SRU] = devm_ioremap_resource(dev, sru_res);
+       gen->base[RSND_GEN1_ADG] = devm_ioremap_resource(dev, adg_res);
+       gen->base[RSND_GEN1_SSI] = devm_ioremap_resource(dev, ssi_res);
+       if (IS_ERR(gen->base[RSND_GEN1_SRU]) ||
+           IS_ERR(gen->base[RSND_GEN1_ADG]) ||
+           IS_ERR(gen->base[RSND_GEN1_SSI]))
+               return -ENODEV;
+
+       gen->ops = &rsnd_gen1_ops;
+       rsnd_gen1_reg_map_init(gen);
+
+       dev_dbg(dev, "Gen1 device probed\n");
+       dev_dbg(dev, "SRU : %08x => %p\n",      sru_res->start,
+                                               gen->base[RSND_GEN1_SRU]);
+       dev_dbg(dev, "ADG : %08x => %p\n",      adg_res->start,
+                                               gen->base[RSND_GEN1_ADG]);
+       dev_dbg(dev, "SSI : %08x => %p\n",      ssi_res->start,
+                                               gen->base[RSND_GEN1_SSI]);
+
+       return 0;
+
+}
+
+static void rsnd_gen1_remove(struct platform_device *pdev,
+                            struct rsnd_priv *priv)
+{
+}
+
+/*
+ *             Gen
+ */
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       return gen->ops->path_init(priv, rdai, io);
+}
+
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       return gen->ops->path_exit(priv, rdai, io);
+}
+
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+                              struct rsnd_mod *mod,
+                              enum rsnd_reg reg)
+{
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int index;
+       u32 offset_id, offset_adr;
+
+       if (reg >= RSND_REG_MAX) {
+               dev_err(dev, "rsnd_reg reg error\n");
+               return NULL;
+       }
+
+       index           = gen->reg_map[reg].index;
+       offset_id       = gen->reg_map[reg].offset_id;
+       offset_adr      = gen->reg_map[reg].offset_adr;
+
+       if (index < 0) {
+               dev_err(dev, "unsupported reg access %d\n", reg);
+               return NULL;
+       }
+
+       if (offset_id && mod)
+               offset_id *= rsnd_mod_id(mod);
+
+       /*
+        * index/offset were set on gen1/gen2
+        */
+
+       return gen->base[index] + offset_id + offset_adr;
+}
+
+int rsnd_gen_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen;
+       int i;
+
+       gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL);
+       if (!gen) {
+               dev_err(dev, "GEN allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->gen = gen;
+
+       /*
+        * see
+        *      rsnd_reg_get()
+        *      rsnd_gen_probe()
+        */
+       for (i = 0; i < RSND_REG_MAX; i++)
+               gen->reg_map[i].index = -1;
+
+       /*
+        *      init each module
+        */
+       if (rsnd_is_gen1(priv))
+               return rsnd_gen1_probe(pdev, info, priv);
+
+       dev_err(dev, "unknown generation R-Car sound device\n");
+
+       return -ENODEV;
+}
+
+void rsnd_gen_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       if (rsnd_is_gen1(priv))
+               rsnd_gen1_remove(pdev, priv);
+}
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
new file mode 100644 (file)
index 0000000..9cc6986
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Renesas R-Car
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef RSND_H
+#define RSND_H
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/sh_dma.h>
+#include <linux/workqueue.h>
+#include <sound/rcar_snd.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+/*
+ *     pseudo register
+ *
+ * The register address offsets SRU/SCU/SSIU on Gen1/Gen2 are very different.
+ * This driver uses pseudo register in order to hide it.
+ * see gen1/gen2 for detail
+ */
+enum rsnd_reg {
+       /* SRU/SCU */
+       RSND_REG_SRC_ROUTE_SEL,
+       RSND_REG_SRC_TMG_SEL0,
+       RSND_REG_SRC_TMG_SEL1,
+       RSND_REG_SRC_TMG_SEL2,
+       RSND_REG_SRC_CTRL,
+       RSND_REG_SSI_MODE0,
+       RSND_REG_SSI_MODE1,
+       RSND_REG_BUSIF_MODE,
+       RSND_REG_BUSIF_ADINR,
+
+       /* ADG */
+       RSND_REG_BRRA,
+       RSND_REG_BRRB,
+       RSND_REG_SSICKR,
+       RSND_REG_AUDIO_CLK_SEL0,
+       RSND_REG_AUDIO_CLK_SEL1,
+       RSND_REG_AUDIO_CLK_SEL2,
+       RSND_REG_AUDIO_CLK_SEL3,
+       RSND_REG_AUDIO_CLK_SEL4,
+       RSND_REG_AUDIO_CLK_SEL5,
+
+       /* SSI */
+       RSND_REG_SSICR,
+       RSND_REG_SSISR,
+       RSND_REG_SSITDR,
+       RSND_REG_SSIRDR,
+       RSND_REG_SSIWSR,
+
+       RSND_REG_MAX,
+};
+
+struct rsnd_priv;
+struct rsnd_mod;
+struct rsnd_dai;
+struct rsnd_dai_stream;
+
+/*
+ *     R-Car basic functions
+ */
+#define rsnd_mod_read(m, r) \
+       rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
+#define rsnd_mod_write(m, r, d) \
+       rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
+#define rsnd_mod_bset(m, r, s, d) \
+       rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
+
+#define rsnd_priv_read(p, r)           rsnd_read(p, NULL, RSND_REG_##r)
+#define rsnd_priv_write(p, r, d)       rsnd_write(p, NULL, RSND_REG_##r, d)
+#define rsnd_priv_bset(p, r, s, d)     rsnd_bset(p, NULL, RSND_REG_##r, s, d)
+
+u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
+void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
+               enum rsnd_reg reg, u32 data);
+void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
+                   u32 mask, u32 data);
+
+/*
+ *     R-Car DMA
+ */
+struct rsnd_dma {
+       struct rsnd_priv        *priv;
+       struct sh_dmae_slave    slave;
+       struct work_struct      work;
+       struct dma_chan         *chan;
+       enum dma_data_direction dir;
+       int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len);
+       int (*complete)(struct rsnd_dma *dma);
+
+       int submit_loop;
+};
+
+void rsnd_dma_start(struct rsnd_dma *dma);
+void rsnd_dma_stop(struct rsnd_dma *dma);
+int rsnd_dma_available(struct rsnd_dma *dma);
+int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
+       int is_play, int id,
+       int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len),
+       int (*complete)(struct rsnd_dma *dma));
+void  rsnd_dma_quit(struct rsnd_priv *priv,
+                   struct rsnd_dma *dma);
+
+
+/*
+ *     R-Car sound mod
+ */
+
+struct rsnd_mod_ops {
+       char *name;
+       int (*init)(struct rsnd_mod *mod,
+                   struct rsnd_dai *rdai,
+                   struct rsnd_dai_stream *io);
+       int (*quit)(struct rsnd_mod *mod,
+                   struct rsnd_dai *rdai,
+                   struct rsnd_dai_stream *io);
+       int (*start)(struct rsnd_mod *mod,
+                    struct rsnd_dai *rdai,
+                    struct rsnd_dai_stream *io);
+       int (*stop)(struct rsnd_mod *mod,
+                   struct rsnd_dai *rdai,
+                   struct rsnd_dai_stream *io);
+};
+
+struct rsnd_mod {
+       int id;
+       struct rsnd_priv *priv;
+       struct rsnd_mod_ops *ops;
+       struct list_head list; /* connect to rsnd_dai playback/capture */
+       struct rsnd_dma dma;
+};
+
+#define rsnd_mod_to_priv(mod) ((mod)->priv)
+#define rsnd_mod_to_dma(mod) (&(mod)->dma)
+#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
+#define rsnd_mod_id(mod) ((mod)->id)
+#define for_each_rsnd_mod(pos, n, io)  \
+       list_for_each_entry_safe(pos, n, &(io)->head, list)
+#define rsnd_mod_call(mod, func, rdai, io)     \
+       (!(mod) ? -ENODEV :                     \
+        !((mod)->ops->func) ? 0 :              \
+        (mod)->ops->func(mod, rdai, io))
+
+void rsnd_mod_init(struct rsnd_priv *priv,
+                  struct rsnd_mod *mod,
+                  struct rsnd_mod_ops *ops,
+                  int id);
+char *rsnd_mod_name(struct rsnd_mod *mod);
+
+/*
+ *     R-Car sound DAI
+ */
+#define RSND_DAI_NAME_SIZE     16
+struct rsnd_dai_stream {
+       struct list_head head; /* head of rsnd_mod list */
+       struct snd_pcm_substream *substream;
+       int byte_pos;
+       int period_pos;
+       int byte_per_period;
+       int next_period_byte;
+};
+
+struct rsnd_dai {
+       char name[RSND_DAI_NAME_SIZE];
+       struct rsnd_dai_platform_info *info; /* rcar_snd.h */
+       struct rsnd_dai_stream playback;
+       struct rsnd_dai_stream capture;
+
+       int clk_master:1;
+       int bit_clk_inv:1;
+       int frm_clk_inv:1;
+       int sys_delay:1;
+       int data_alignment:1;
+};
+
+#define rsnd_dai_nr(priv) ((priv)->dai_nr)
+#define for_each_rsnd_dai(rdai, priv, i)               \
+       for (i = 0, (rdai) = rsnd_dai_get(priv, i);     \
+            i < rsnd_dai_nr(priv);                     \
+            i++, (rdai) = rsnd_dai_get(priv, i))
+
+struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
+int rsnd_dai_disconnect(struct rsnd_mod *mod);
+int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod,
+                    struct rsnd_dai_stream *io);
+int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
+int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
+#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
+#define rsnd_io_to_runtime(io) ((io)->substream->runtime)
+
+void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
+int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
+
+/*
+ *     R-Car Gen1/Gen2
+ */
+int rsnd_gen_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_gen_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
+int rsnd_gen_path_init(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io);
+int rsnd_gen_path_exit(struct rsnd_priv *priv,
+                      struct rsnd_dai *rdai,
+                      struct rsnd_dai_stream *io);
+void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv,
+                              struct rsnd_mod *mod,
+                              enum rsnd_reg reg);
+#define rsnd_is_gen1(s)                ((s)->info->flags & RSND_GEN1)
+#define rsnd_is_gen2(s)                ((s)->info->flags & RSND_GEN2)
+
+/*
+ *     R-Car ADG
+ */
+int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod);
+int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate);
+int rsnd_adg_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_adg_remove(struct platform_device *pdev,
+                  struct rsnd_priv *priv);
+
+/*
+ *     R-Car sound priv
+ */
+struct rsnd_priv {
+
+       struct device *dev;
+       struct rcar_snd_info *info;
+       spinlock_t lock;
+
+       /*
+        * below value will be filled on rsnd_gen_probe()
+        */
+       void *gen;
+
+       /*
+        * below value will be filled on rsnd_scu_probe()
+        */
+       void *scu;
+       int scu_nr;
+
+       /*
+        * below value will be filled on rsnd_adg_probe()
+        */
+       void *adg;
+
+       /*
+        * below value will be filled on rsnd_ssi_probe()
+        */
+       void *ssiu;
+
+       /*
+        * below value will be filled on rsnd_dai_probe()
+        */
+       struct snd_soc_dai_driver *daidrv;
+       struct rsnd_dai *rdai;
+       int dai_nr;
+};
+
+#define rsnd_priv_to_dev(priv) ((priv)->dev)
+#define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags)
+#define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags)
+
+/*
+ *     R-Car SCU
+ */
+int rsnd_scu_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_scu_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id);
+#define rsnd_scu_nr(priv) ((priv)->scu_nr)
+
+/*
+ *     R-Car SSI
+ */
+int rsnd_ssi_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+                  struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
+struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
+                                         int dai_id, int is_play);
+
+#endif
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c
new file mode 100644 (file)
index 0000000..184d900
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Renesas R-Car SCU support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "rsnd.h"
+
+struct rsnd_scu {
+       struct rsnd_scu_platform_info *info; /* rcar_snd.h */
+       struct rsnd_mod mod;
+};
+
+#define rsnd_scu_mode_flags(p) ((p)->info->flags)
+
+/*
+ * ADINR
+ */
+#define OTBL_24                (0 << 16)
+#define OTBL_22                (2 << 16)
+#define OTBL_20                (4 << 16)
+#define OTBL_18                (6 << 16)
+#define OTBL_16                (8 << 16)
+
+
+#define rsnd_mod_to_scu(_mod)  \
+       container_of((_mod), struct rsnd_scu, mod)
+
+#define for_each_rsnd_scu(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_scu_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_scu *)(priv)->scu + i);      \
+            i++)
+
+static int rsnd_scu_set_route(struct rsnd_priv *priv,
+                             struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct scu_route_config {
+               u32 mask;
+               int shift;
+       } routes[] = {
+               { 0xF,  0, }, /* 0 */
+               { 0xF,  4, }, /* 1 */
+               { 0xF,  8, }, /* 2 */
+               { 0x7, 12, }, /* 3 */
+               { 0x7, 16, }, /* 4 */
+               { 0x7, 20, }, /* 5 */
+               { 0x7, 24, }, /* 6 */
+               { 0x3, 28, }, /* 7 */
+               { 0x3, 30, }, /* 8 */
+       };
+
+       u32 mask;
+       u32 val;
+       int shift;
+       int id;
+
+       /*
+        * Gen1 only
+        */
+       if (!rsnd_is_gen1(priv))
+               return 0;
+
+       id = rsnd_mod_id(mod);
+       if (id < 0 || id > ARRAY_SIZE(routes))
+               return -EIO;
+
+       /*
+        * SRC_ROUTE_SELECT
+        */
+       val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
+       val = val               << routes[id].shift;
+       mask = routes[id].mask  << routes[id].shift;
+
+       rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val);
+
+       /*
+        * SRC_TIMING_SELECT
+        */
+       shift   = (id % 4) * 8;
+       mask    = 0x1F << shift;
+       if (8 == id) /* SRU8 is very special */
+               val = id << shift;
+       else
+               val = (id + 1) << shift;
+
+       switch (id / 4) {
+       case 0:
+               rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val);
+               break;
+       case 1:
+               rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val);
+               break;
+       case 2:
+               rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val);
+               break;
+       }
+
+       return 0;
+}
+
+static int rsnd_scu_set_mode(struct rsnd_priv *priv,
+                            struct rsnd_mod *mod,
+                            struct rsnd_dai *rdai,
+                            struct rsnd_dai_stream *io)
+{
+       int id = rsnd_mod_id(mod);
+       u32 val;
+
+       if (rsnd_is_gen1(priv)) {
+               val = (1 << id);
+               rsnd_mod_bset(mod, SRC_CTRL, val, val);
+       }
+
+       return 0;
+}
+
+static int rsnd_scu_set_hpbif(struct rsnd_priv *priv,
+                             struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 adinr = runtime->channels;
+
+       switch (runtime->sample_bits) {
+       case 16:
+               adinr |= OTBL_16;
+               break;
+       case 32:
+               adinr |= OTBL_24;
+               break;
+       default:
+               return -EIO;
+       }
+
+       rsnd_mod_write(mod, BUSIF_MODE, 1);
+       rsnd_mod_write(mod, BUSIF_ADINR, adinr);
+
+       return 0;
+}
+
+static int rsnd_scu_start(struct rsnd_mod *mod,
+                         struct rsnd_dai *rdai,
+                         struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_scu *scu = rsnd_mod_to_scu(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 flags = rsnd_scu_mode_flags(scu);
+       int ret;
+
+       /*
+        * SCU will be used if it has RSND_SCU_USB_HPBIF flags
+        */
+       if (!(flags & RSND_SCU_USB_HPBIF)) {
+               /* it use PIO transter */
+               dev_dbg(dev, "%s%d is not used\n",
+                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+               return 0;
+       }
+
+       /* it use DMA transter */
+       ret = rsnd_scu_set_route(priv, mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_scu_set_mode(priv, mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       ret = rsnd_scu_set_hpbif(priv, mod, rdai, io);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_scu_ops = {
+       .name   = "scu",
+       .start  = rsnd_scu_start,
+};
+
+struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id)
+{
+       BUG_ON(id < 0 || id >= rsnd_scu_nr(priv));
+
+       return &((struct rsnd_scu *)(priv->scu) + id)->mod;
+}
+
+int rsnd_scu_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_scu *scu;
+       int i, nr;
+
+       /*
+        * init SCU
+        */
+       nr      = info->scu_info_nr;
+       scu     = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL);
+       if (!scu) {
+               dev_err(dev, "SCU allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->scu_nr    = nr;
+       priv->scu       = scu;
+
+       for_each_rsnd_scu(scu, priv, i) {
+               rsnd_mod_init(priv, &scu->mod,
+                             &rsnd_scu_ops, i);
+               scu->info = &info->scu_info[i];
+
+               dev_dbg(dev, "SCU%d probed\n", i);
+       }
+       dev_dbg(dev, "scu probed\n");
+
+       return 0;
+}
+
+void rsnd_scu_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+}
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
new file mode 100644 (file)
index 0000000..fae26d3
--- /dev/null
@@ -0,0 +1,728 @@
+/*
+ * Renesas R-Car SSIU/SSI support
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * Based on fsi.c
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include "rsnd.h"
+#define RSND_SSI_NAME_SIZE 16
+
+/*
+ * SSICR
+ */
+#define        FORCE           (1 << 31)       /* Fixed */
+#define        DMEN            (1 << 28)       /* DMA Enable */
+#define        UIEN            (1 << 27)       /* Underflow Interrupt Enable */
+#define        OIEN            (1 << 26)       /* Overflow Interrupt Enable */
+#define        IIEN            (1 << 25)       /* Idle Mode Interrupt Enable */
+#define        DIEN            (1 << 24)       /* Data Interrupt Enable */
+
+#define        DWL_8           (0 << 19)       /* Data Word Length */
+#define        DWL_16          (1 << 19)       /* Data Word Length */
+#define        DWL_18          (2 << 19)       /* Data Word Length */
+#define        DWL_20          (3 << 19)       /* Data Word Length */
+#define        DWL_22          (4 << 19)       /* Data Word Length */
+#define        DWL_24          (5 << 19)       /* Data Word Length */
+#define        DWL_32          (6 << 19)       /* Data Word Length */
+
+#define        SWL_32          (3 << 16)       /* R/W System Word Length */
+#define        SCKD            (1 << 15)       /* Serial Bit Clock Direction */
+#define        SWSD            (1 << 14)       /* Serial WS Direction */
+#define        SCKP            (1 << 13)       /* Serial Bit Clock Polarity */
+#define        SWSP            (1 << 12)       /* Serial WS Polarity */
+#define        SDTA            (1 << 10)       /* Serial Data Alignment */
+#define        DEL             (1 <<  8)       /* Serial Data Delay */
+#define        CKDV(v)         (v <<  4)       /* Serial Clock Division Ratio */
+#define        TRMD            (1 <<  1)       /* Transmit/Receive Mode Select */
+#define        EN              (1 <<  0)       /* SSI Module Enable */
+
+/*
+ * SSISR
+ */
+#define        UIRQ            (1 << 27)       /* Underflow Error Interrupt Status */
+#define        OIRQ            (1 << 26)       /* Overflow Error Interrupt Status */
+#define        IIRQ            (1 << 25)       /* Idle Mode Interrupt Status */
+#define        DIRQ            (1 << 24)       /* Data Interrupt Status Flag */
+
+/*
+ * SSIWSR
+ */
+#define CONT           (1 << 8)        /* WS Continue Function */
+
+struct rsnd_ssi {
+       struct clk *clk;
+       struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
+       struct rsnd_ssi *parent;
+       struct rsnd_mod mod;
+
+       struct rsnd_dai *rdai;
+       struct rsnd_dai_stream *io;
+       u32 cr_own;
+       u32 cr_clk;
+       u32 cr_etc;
+       int err;
+       int dma_offset;
+       unsigned int usrcnt;
+       unsigned int rate;
+};
+
+struct rsnd_ssiu {
+       u32 ssi_mode0;
+       u32 ssi_mode1;
+
+       int ssi_nr;
+       struct rsnd_ssi *ssi;
+};
+
+#define for_each_rsnd_ssi(pos, priv, i)                                        \
+       for (i = 0;                                                     \
+            (i < rsnd_ssi_nr(priv)) &&                                 \
+               ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \
+            i++)
+
+#define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr)
+#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
+#define rsnd_dma_to_ssi(dma)  rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
+#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
+#define rsnd_ssi_dma_available(ssi) \
+       rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
+#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
+#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
+#define rsnd_ssi_mode_flags(p) ((p)->info->flags)
+#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id)
+#define rsnd_ssi_to_ssiu(ssi)\
+       (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1)
+
+static void rsnd_ssi_mode_init(struct rsnd_priv *priv,
+                              struct rsnd_ssiu *ssiu)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ssi *ssi;
+       u32 flags;
+       u32 val;
+       int i;
+
+       /*
+        * SSI_MODE0
+        */
+       ssiu->ssi_mode0 = 0;
+       for_each_rsnd_ssi(ssi, priv, i) {
+               flags = rsnd_ssi_mode_flags(ssi);
+
+               /* see also BUSIF_MODE */
+               if (!(flags & RSND_SSI_DEPENDENT)) {
+                       ssiu->ssi_mode0 |= (1 << i);
+                       dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", i);
+               } else {
+                       dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", i);
+               }
+       }
+
+       /*
+        * SSI_MODE1
+        */
+#define ssi_parent_set(p, sync, adg, ext)              \
+       do {                                            \
+               ssi->parent = ssiu->ssi + p;            \
+               if (flags & RSND_SSI_CLK_FROM_ADG)      \
+                       val = adg;                      \
+               else                                    \
+                       val = ext;                      \
+               if (flags & RSND_SSI_SYNC)              \
+                       val |= sync;                    \
+       } while (0)
+
+       ssiu->ssi_mode1 = 0;
+       for_each_rsnd_ssi(ssi, priv, i) {
+               flags = rsnd_ssi_mode_flags(ssi);
+
+               if (!(flags & RSND_SSI_CLK_PIN_SHARE))
+                       continue;
+
+               val = 0;
+               switch (i) {
+               case 1:
+                       ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0));
+                       break;
+               case 2:
+                       ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2));
+                       break;
+               case 4:
+                       ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16));
+                       break;
+               case 8:
+                       ssi_parent_set(7, 0, 0, 0);
+                       break;
+               }
+
+               ssiu->ssi_mode1 |= val;
+       }
+}
+
+static void rsnd_ssi_mode_set(struct rsnd_ssi *ssi)
+{
+       struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi);
+
+       rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0);
+       rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1);
+}
+
+static void rsnd_ssi_status_check(struct rsnd_mod *mod,
+                                 u32 bit)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 status;
+       int i;
+
+       for (i = 0; i < 1024; i++) {
+               status = rsnd_mod_read(mod, SSISR);
+               if (status & bit)
+                       return;
+
+               udelay(50);
+       }
+
+       dev_warn(dev, "status check failed\n");
+}
+
+static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
+                                    unsigned int rate)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int i, j, ret;
+       int adg_clk_div_table[] = {
+               1, 6, /* see adg.c */
+       };
+       int ssi_clk_mul_table[] = {
+               1, 2, 4, 8, 16, 6, 12,
+       };
+       unsigned int main_rate;
+
+       /*
+        * Find best clock, and try to start ADG
+        */
+       for (i = 0; i < ARRAY_SIZE(adg_clk_div_table); i++) {
+               for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
+
+                       /*
+                        * this driver is assuming that
+                        * system word is 64fs (= 2 x 32bit)
+                        * see rsnd_ssi_start()
+                        */
+                       main_rate = rate / adg_clk_div_table[i]
+                               * 32 * 2 * ssi_clk_mul_table[j];
+
+                       ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
+                       if (0 == ret) {
+                               ssi->rate       = rate;
+                               ssi->cr_clk     = FORCE | SWL_32 |
+                                                 SCKD | SWSD | CKDV(j);
+
+                               dev_dbg(dev, "ssi%d outputs %u Hz\n",
+                                       rsnd_mod_id(&ssi->mod), rate);
+
+                               return 0;
+                       }
+               }
+       }
+
+       dev_err(dev, "unsupported clock rate\n");
+       return -EIO;
+}
+
+static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
+{
+       ssi->rate = 0;
+       ssi->cr_clk = 0;
+       rsnd_adg_ssi_clk_stop(&ssi->mod);
+}
+
+static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 cr;
+
+       if (0 == ssi->usrcnt) {
+               clk_enable(ssi->clk);
+
+               if (rsnd_rdai_is_clk_master(rdai)) {
+                       struct snd_pcm_runtime *runtime;
+
+                       runtime = rsnd_io_to_runtime(io);
+
+                       if (rsnd_ssi_clk_from_parent(ssi))
+                               rsnd_ssi_hw_start(ssi->parent, rdai, io);
+                       else
+                               rsnd_ssi_master_clk_start(ssi, runtime->rate);
+               }
+       }
+
+       cr  =   ssi->cr_own     |
+               ssi->cr_clk     |
+               ssi->cr_etc     |
+               EN;
+
+       rsnd_mod_write(&ssi->mod, SSICR, cr);
+
+       ssi->usrcnt++;
+
+       dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod));
+}
+
+static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
+                            struct rsnd_dai *rdai)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 cr;
+
+       if (0 == ssi->usrcnt) /* stop might be called without start */
+               return;
+
+       ssi->usrcnt--;
+
+       if (0 == ssi->usrcnt) {
+               /*
+                * disable all IRQ,
+                * and, wait all data was sent
+                */
+               cr  =   ssi->cr_own     |
+                       ssi->cr_clk;
+
+               rsnd_mod_write(&ssi->mod, SSICR, cr | EN);
+               rsnd_ssi_status_check(&ssi->mod, DIRQ);
+
+               /*
+                * disable SSI,
+                * and, wait idle state
+                */
+               rsnd_mod_write(&ssi->mod, SSICR, cr);   /* disabled all */
+               rsnd_ssi_status_check(&ssi->mod, IIRQ);
+
+               if (rsnd_rdai_is_clk_master(rdai)) {
+                       if (rsnd_ssi_clk_from_parent(ssi))
+                               rsnd_ssi_hw_stop(ssi->parent, rdai);
+                       else
+                               rsnd_ssi_master_clk_stop(ssi);
+               }
+
+               clk_disable(ssi->clk);
+       }
+
+       dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
+}
+
+/*
+ *     SSI mod common functions
+ */
+static int rsnd_ssi_init(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 cr;
+
+       cr = FORCE;
+
+       /*
+        * always use 32bit system word for easy clock calculation.
+        * see also rsnd_ssi_master_clk_enable()
+        */
+       cr |= SWL_32;
+
+       /*
+        * init clock settings for SSICR
+        */
+       switch (runtime->sample_bits) {
+       case 16:
+               cr |= DWL_16;
+               break;
+       case 32:
+               cr |= DWL_24;
+               break;
+       default:
+               return -EIO;
+       }
+
+       if (rdai->bit_clk_inv)
+               cr |= SCKP;
+       if (rdai->frm_clk_inv)
+               cr |= SWSP;
+       if (rdai->data_alignment)
+               cr |= SDTA;
+       if (rdai->sys_delay)
+               cr |= DEL;
+       if (rsnd_dai_is_play(rdai, io))
+               cr |= TRMD;
+
+       /*
+        * set ssi parameter
+        */
+       ssi->rdai       = rdai;
+       ssi->io         = io;
+       ssi->cr_own     = cr;
+       ssi->err        = -1; /* ignore 1st error */
+
+       rsnd_ssi_mode_set(ssi);
+
+       dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_ssi_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai *rdai,
+                        struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       if (ssi->err > 0)
+               dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
+
+       ssi->rdai       = NULL;
+       ssi->io         = NULL;
+       ssi->cr_own     = 0;
+       ssi->err        = 0;
+
+       return 0;
+}
+
+static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
+{
+       /* under/over flow error */
+       if (status & (UIRQ | OIRQ)) {
+               ssi->err++;
+
+               /* clear error status */
+               rsnd_mod_write(&ssi->mod, SSISR, 0);
+       }
+}
+
+/*
+ *             SSI PIO
+ */
+static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
+{
+       struct rsnd_ssi *ssi = data;
+       struct rsnd_dai_stream *io = ssi->io;
+       u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+       irqreturn_t ret = IRQ_NONE;
+
+       if (io && (status & DIRQ)) {
+               struct rsnd_dai *rdai = ssi->rdai;
+               struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+               u32 *buf = (u32 *)(runtime->dma_area +
+                                  rsnd_dai_pointer_offset(io, 0));
+
+               rsnd_ssi_record_error(ssi, status);
+
+               /*
+                * 8/16/32 data can be assesse to TDR/RDR register
+                * directly as 32bit data
+                * see rsnd_ssi_init()
+                */
+               if (rsnd_dai_is_play(rdai, io))
+                       rsnd_mod_write(&ssi->mod, SSITDR, *buf);
+               else
+                       *buf = rsnd_mod_read(&ssi->mod, SSIRDR);
+
+               rsnd_dai_pointer_update(io, sizeof(*buf));
+
+               ret = IRQ_HANDLED;
+       }
+
+       return ret;
+}
+
+static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       /* enable PIO IRQ */
+       ssi->cr_etc = UIEN | OIEN | DIEN;
+
+       rsnd_ssi_hw_start(ssi, rdai, io);
+
+       dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return 0;
+}
+
+static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
+                            struct rsnd_dai *rdai,
+                            struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+       dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       ssi->cr_etc = 0;
+
+       rsnd_ssi_hw_stop(ssi, rdai);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
+       .name   = "ssi (pio)",
+       .init   = rsnd_ssi_init,
+       .quit   = rsnd_ssi_quit,
+       .start  = rsnd_ssi_pio_start,
+       .stop   = rsnd_ssi_pio_stop,
+};
+
+static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len)
+{
+       struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
+       struct rsnd_dai_stream *io = ssi->io;
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+       *len = io->byte_per_period;
+       *buf = runtime->dma_addr +
+               rsnd_dai_pointer_offset(io, ssi->dma_offset + *len);
+       ssi->dma_offset = *len; /* it cares A/B plane */
+
+       return 0;
+}
+
+static int rsnd_ssi_dma_complete(struct rsnd_dma *dma)
+{
+       struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma);
+       struct rsnd_dai_stream *io = ssi->io;
+       u32 status = rsnd_mod_read(&ssi->mod, SSISR);
+
+       rsnd_ssi_record_error(ssi, status);
+
+       rsnd_dai_pointer_update(ssi->io, io->byte_per_period);
+
+       return 0;
+}
+
+static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
+                             struct rsnd_dai *rdai,
+                             struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
+
+       /* enable DMA transfer */
+       ssi->cr_etc = DMEN;
+       ssi->dma_offset = 0;
+
+       rsnd_dma_start(dma);
+
+       rsnd_ssi_hw_start(ssi, ssi->rdai, io);
+
+       /* enable WS continue */
+       if (rsnd_rdai_is_clk_master(rdai))
+               rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+
+       return 0;
+}
+
+static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
+                            struct rsnd_dai *rdai,
+                            struct rsnd_dai_stream *io)
+{
+       struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+       struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
+
+       ssi->cr_etc = 0;
+
+       rsnd_ssi_hw_stop(ssi, rdai);
+
+       rsnd_dma_stop(dma);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
+       .name   = "ssi (dma)",
+       .init   = rsnd_ssi_init,
+       .quit   = rsnd_ssi_quit,
+       .start  = rsnd_ssi_dma_start,
+       .stop   = rsnd_ssi_dma_stop,
+};
+
+/*
+ *             Non SSI
+ */
+static int rsnd_ssi_non(struct rsnd_mod *mod,
+                       struct rsnd_dai *rdai,
+                       struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       dev_dbg(dev, "%s\n", __func__);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ssi_non_ops = {
+       .name   = "ssi (non)",
+       .init   = rsnd_ssi_non,
+       .quit   = rsnd_ssi_non,
+       .start  = rsnd_ssi_non,
+       .stop   = rsnd_ssi_non,
+};
+
+/*
+ *             ssi mod function
+ */
+struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv,
+                                         int dai_id, int is_play)
+{
+       struct rsnd_ssi *ssi;
+       int i, has_play;
+
+       is_play = !!is_play;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               if (rsnd_ssi_dai_id(ssi) != dai_id)
+                       continue;
+
+               has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY);
+
+               if (is_play == has_play)
+                       return &ssi->mod;
+       }
+
+       return NULL;
+}
+
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id)
+{
+       BUG_ON(id < 0 || id >= rsnd_ssi_nr(priv));
+
+       return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod;
+}
+
+int rsnd_ssi_probe(struct platform_device *pdev,
+                  struct rcar_snd_info *info,
+                  struct rsnd_priv *priv)
+{
+       struct rsnd_ssi_platform_info *pinfo;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mod_ops *ops;
+       struct clk *clk;
+       struct rsnd_ssiu *ssiu;
+       struct rsnd_ssi *ssi;
+       char name[RSND_SSI_NAME_SIZE];
+       int i, nr, ret;
+
+       /*
+        *      init SSI
+        */
+       nr      = info->ssi_info_nr;
+       ssiu    = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr),
+                              GFP_KERNEL);
+       if (!ssiu) {
+               dev_err(dev, "SSI allocate failed\n");
+               return -ENOMEM;
+       }
+
+       priv->ssiu      = ssiu;
+       ssiu->ssi       = (struct rsnd_ssi *)(ssiu + 1);
+       ssiu->ssi_nr    = nr;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               pinfo = &info->ssi_info[i];
+
+               snprintf(name, RSND_SSI_NAME_SIZE, "ssi.%d", i);
+
+               clk = clk_get(dev, name);
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+
+               ssi->info       = pinfo;
+               ssi->clk        = clk;
+
+               ops = &rsnd_ssi_non_ops;
+
+               /*
+                * SSI DMA case
+                */
+               if (pinfo->dma_id > 0) {
+                       ret = rsnd_dma_init(
+                               priv, rsnd_mod_to_dma(&ssi->mod),
+                               (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY),
+                               pinfo->dma_id,
+                               rsnd_ssi_dma_inquiry,
+                               rsnd_ssi_dma_complete);
+                       if (ret < 0)
+                               dev_info(dev, "SSI DMA failed. try PIO transter\n");
+                       else
+                               ops     = &rsnd_ssi_dma_ops;
+
+                       dev_dbg(dev, "SSI%d use DMA transfer\n", i);
+               }
+
+               /*
+                * SSI PIO case
+                */
+               if (!rsnd_ssi_dma_available(ssi) &&
+                    rsnd_ssi_pio_available(ssi)) {
+                       ret = devm_request_irq(dev, pinfo->pio_irq,
+                                              &rsnd_ssi_pio_interrupt,
+                                              IRQF_SHARED,
+                                              dev_name(dev), ssi);
+                       if (ret) {
+                               dev_err(dev, "SSI request interrupt failed\n");
+                               return ret;
+                       }
+
+                       ops     = &rsnd_ssi_pio_ops;
+
+                       dev_dbg(dev, "SSI%d use PIO transfer\n", i);
+               }
+
+               rsnd_mod_init(priv, &ssi->mod, ops, i);
+       }
+
+       rsnd_ssi_mode_init(priv, ssiu);
+
+       dev_dbg(dev, "ssi probed\n");
+
+       return 0;
+}
+
+void rsnd_ssi_remove(struct platform_device *pdev,
+                  struct rsnd_priv *priv)
+{
+       struct rsnd_ssi *ssi;
+       int i;
+
+       for_each_rsnd_ssi(ssi, priv, i) {
+               clk_put(ssi->clk);
+               if (rsnd_ssi_dma_available(ssi))
+                       rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod));
+       }
+
+}
index 06a8000..53c9ecd 100644 (file)
@@ -149,8 +149,9 @@ static int soc_compr_free(struct snd_compr_stream *cstream)
                                        SND_SOC_DAPM_STREAM_STOP);
                } else {
                        rtd->pop_wait = 1;
-                       schedule_delayed_work(&rtd->delayed_work,
-                               msecs_to_jiffies(rtd->pmdown_time));
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &rtd->delayed_work,
+                                          msecs_to_jiffies(rtd->pmdown_time));
                }
        } else {
                /* capture streams can be powered down now */
@@ -334,7 +335,7 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
        return ret;
 }
 
-static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
+static int soc_compr_set_metadata(struct snd_compr_stream *cstream,
                                struct snd_compr_metadata *metadata)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -347,7 +348,7 @@ static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
        return ret;
 }
 
-static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
+static int soc_compr_get_metadata(struct snd_compr_stream *cstream,
                                struct snd_compr_metadata *metadata)
 {
        struct snd_soc_pcm_runtime *rtd = cstream->private_data;
@@ -364,8 +365,8 @@ static struct snd_compr_ops soc_compr_ops = {
        .open           = soc_compr_open,
        .free           = soc_compr_free,
        .set_params     = soc_compr_set_params,
-       .set_metadata   = sst_compr_set_metadata,
-       .get_metadata   = sst_compr_get_metadata,
+       .set_metadata   = soc_compr_set_metadata,
+       .get_metadata   = soc_compr_get_metadata,
        .get_params     = soc_compr_get_params,
        .trigger        = soc_compr_trigger,
        .pointer        = soc_compr_pointer,
index d82ee38..528f870 100644 (file)
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
 #include <sound/ac97_codec.h>
 #include <sound/core.h>
 #include <sound/jack.h>
@@ -47,8 +50,6 @@
 
 #define NAME_SIZE      32
 
-static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
-
 #ifdef CONFIG_DEBUG_FS
 struct dentry *snd_soc_debugfs_root;
 EXPORT_SYMBOL_GPL(snd_soc_debugfs_root);
@@ -69,6 +70,16 @@ static int pmdown_time = 5000;
 module_param(pmdown_time, int, 0);
 MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
 
+struct snd_ac97_reset_cfg {
+       struct pinctrl *pctl;
+       struct pinctrl_state *pstate_reset;
+       struct pinctrl_state *pstate_warm_reset;
+       struct pinctrl_state *pstate_run;
+       int gpio_sdata;
+       int gpio_sync;
+       int gpio_reset;
+};
+
 /* returns the minimum number of bytes needed to represent
  * a particular given value */
 static int min_bytes_needed(unsigned long val)
@@ -530,6 +541,15 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec)
 }
 #endif
 
+static void codec2codec_close_delayed_work(struct work_struct *work)
+{
+       /* Currently nothing to do for c2c links
+        * Since c2c links are internal nodes in the DAPM graph and
+        * don't interface with the outside world or application layer
+        * we don't have to do any special handling on close.
+        */
+}
+
 #ifdef CONFIG_PM_SLEEP
 /* powers down audio subsystem for suspend */
 int snd_soc_suspend(struct device *dev)
@@ -1428,6 +1448,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
                                return ret;
                        }
                } else {
+                       INIT_DELAYED_WORK(&rtd->delayed_work,
+                                               codec2codec_close_delayed_work);
+
                        /* link the DAI widgets */
                        play_w = codec_dai->playback_widget;
                        capture_w = cpu_dai->capture_widget;
@@ -2080,6 +2103,117 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
 }
 EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
 
+static struct snd_ac97_reset_cfg snd_ac97_rst_cfg;
+
+static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+       struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
+
+       pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset);
+
+       gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1);
+
+       udelay(10);
+
+       gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
+
+       pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
+       msleep(2);
+}
+
+static void snd_soc_ac97_reset(struct snd_ac97 *ac97)
+{
+       struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
+
+       pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset);
+
+       gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
+       gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0);
+       gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0);
+
+       udelay(10);
+
+       gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1);
+
+       pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
+       msleep(2);
+}
+
+static int snd_soc_ac97_parse_pinctl(struct device *dev,
+               struct snd_ac97_reset_cfg *cfg)
+{
+       struct pinctrl *p;
+       struct pinctrl_state *state;
+       int gpio;
+       int ret;
+
+       p = devm_pinctrl_get(dev);
+       if (IS_ERR(p)) {
+               dev_err(dev, "Failed to get pinctrl\n");
+               return PTR_RET(p);
+       }
+       cfg->pctl = p;
+
+       state = pinctrl_lookup_state(p, "ac97-reset");
+       if (IS_ERR(state)) {
+               dev_err(dev, "Can't find pinctrl state ac97-reset\n");
+               return PTR_RET(state);
+       }
+       cfg->pstate_reset = state;
+
+       state = pinctrl_lookup_state(p, "ac97-warm-reset");
+       if (IS_ERR(state)) {
+               dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
+               return PTR_RET(state);
+       }
+       cfg->pstate_warm_reset = state;
+
+       state = pinctrl_lookup_state(p, "ac97-running");
+       if (IS_ERR(state)) {
+               dev_err(dev, "Can't find pinctrl state ac97-running\n");
+               return PTR_RET(state);
+       }
+       cfg->pstate_run = state;
+
+       gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0);
+       if (gpio < 0) {
+               dev_err(dev, "Can't find ac97-sync gpio\n");
+               return gpio;
+       }
+       ret = devm_gpio_request(dev, gpio, "AC97 link sync");
+       if (ret) {
+               dev_err(dev, "Failed requesting ac97-sync gpio\n");
+               return ret;
+       }
+       cfg->gpio_sync = gpio;
+
+       gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1);
+       if (gpio < 0) {
+               dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio);
+               return gpio;
+       }
+       ret = devm_gpio_request(dev, gpio, "AC97 link sdata");
+       if (ret) {
+               dev_err(dev, "Failed requesting ac97-sdata gpio\n");
+               return ret;
+       }
+       cfg->gpio_sdata = gpio;
+
+       gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
+       if (gpio < 0) {
+               dev_err(dev, "Can't find ac97-reset gpio\n");
+               return gpio;
+       }
+       ret = devm_gpio_request(dev, gpio, "AC97 link reset");
+       if (ret) {
+               dev_err(dev, "Failed requesting ac97-reset gpio\n");
+               return ret;
+       }
+       cfg->gpio_reset = gpio;
+
+       return 0;
+}
+
 struct snd_ac97_bus_ops *soc_ac97_ops;
 EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
@@ -2098,6 +2232,35 @@ int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
 EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
 
 /**
+ * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions
+ *
+ * This function sets the reset and warm_reset properties of ops and parses
+ * the device node of pdev to get pinctrl states and gpio numbers to use.
+ */
+int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+               struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct snd_ac97_reset_cfg cfg;
+       int ret;
+
+       ret = snd_soc_ac97_parse_pinctl(dev, &cfg);
+       if (ret)
+               return ret;
+
+       ret = snd_soc_set_ac97_ops(ops);
+       if (ret)
+               return ret;
+
+       ops->warm_reset = snd_soc_ac97_warm_reset;
+       ops->reset = snd_soc_ac97_reset;
+
+       snd_ac97_rst_cfg = cfg;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
+
+/**
  * snd_soc_free_ac97_codec - free AC97 codec device
  * @codec: audio codec
  *
@@ -2299,6 +2462,22 @@ static int snd_soc_add_controls(struct snd_card *card, struct device *dev,
        return 0;
 }
 
+struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
+                                              const char *name)
+{
+       struct snd_card *card = soc_card->snd_card;
+       struct snd_kcontrol *kctl;
+
+       if (unlikely(!name))
+               return NULL;
+
+       list_for_each_entry(kctl, &card->controls, list)
+               if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name)))
+                       return kctl;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_soc_card_get_kcontrol);
+
 /**
  * snd_soc_add_codec_controls - add an array of controls to a codec.
  * Convenience function to add a list of controls. Many codecs were
@@ -2541,59 +2720,6 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol,
 EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double);
 
 /**
- * snd_soc_info_enum_ext - external enumerated single mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about an external enumerated
- * single mixer.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo)
-{
-       struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = e->max;
-
-       if (uinfo->value.enumerated.item > e->max - 1)
-               uinfo->value.enumerated.item = e->max - 1;
-       strcpy(uinfo->value.enumerated.name,
-               e->texts[uinfo->value.enumerated.item]);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_enum_ext);
-
-/**
- * snd_soc_info_volsw_ext - external single mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about a single external mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_ext(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo)
-{
-       int max = kcontrol->private_value;
-
-       if (max == 1 && !strstr(kcontrol->id.name, " Volume"))
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       else
-               uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = max;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_ext);
-
-/**
  * snd_soc_info_volsw - single mixer info callback
  * @kcontrol: mixer control
  * @uinfo: control element information
index b941908..d84bd0f 100644 (file)
 
 #define DAPM_UPDATE_STAT(widget, val) widget->dapm->card->dapm_stats.val++;
 
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
+       const char *control,
+       int (*connected)(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink));
+static struct snd_soc_dapm_widget *
+snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
+                        const struct snd_soc_dapm_widget *widget);
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 0,
@@ -73,16 +82,18 @@ static int dapm_up_seq[] = {
        [snd_soc_dapm_hp] = 10,
        [snd_soc_dapm_spk] = 10,
        [snd_soc_dapm_line] = 10,
-       [snd_soc_dapm_post] = 11,
+       [snd_soc_dapm_kcontrol] = 11,
+       [snd_soc_dapm_post] = 12,
 };
 
 static int dapm_down_seq[] = {
        [snd_soc_dapm_pre] = 0,
-       [snd_soc_dapm_adc] = 1,
-       [snd_soc_dapm_hp] = 2,
-       [snd_soc_dapm_spk] = 2,
-       [snd_soc_dapm_line] = 2,
-       [snd_soc_dapm_out_drv] = 2,
+       [snd_soc_dapm_kcontrol] = 1,
+       [snd_soc_dapm_adc] = 2,
+       [snd_soc_dapm_hp] = 3,
+       [snd_soc_dapm_spk] = 3,
+       [snd_soc_dapm_line] = 3,
+       [snd_soc_dapm_out_drv] = 3,
        [snd_soc_dapm_pga] = 4,
        [snd_soc_dapm_switch] = 5,
        [snd_soc_dapm_mixer_named_ctl] = 5,
@@ -174,36 +185,176 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
        return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL);
 }
 
-/* get snd_card from DAPM context */
-static inline struct snd_card *dapm_get_snd_card(
-       struct snd_soc_dapm_context *dapm)
+struct dapm_kcontrol_data {
+       unsigned int value;
+       struct snd_soc_dapm_widget *widget;
+       struct list_head paths;
+       struct snd_soc_dapm_widget_list *wlist;
+};
+
+static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
+       struct snd_kcontrol *kcontrol)
 {
-       if (dapm->codec)
-               return dapm->codec->card->snd_card;
-       else if (dapm->platform)
-               return dapm->platform->card->snd_card;
-       else
-               BUG();
+       struct dapm_kcontrol_data *data;
+       struct soc_mixer_control *mc;
 
-       /* unreachable */
-       return NULL;
+       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               dev_err(widget->dapm->dev,
+                               "ASoC: can't allocate kcontrol data for %s\n",
+                               widget->name);
+               return -ENOMEM;
+       }
+
+       INIT_LIST_HEAD(&data->paths);
+
+       switch (widget->id) {
+       case snd_soc_dapm_switch:
+       case snd_soc_dapm_mixer:
+       case snd_soc_dapm_mixer_named_ctl:
+               mc = (struct soc_mixer_control *)kcontrol->private_value;
+
+               if (mc->autodisable) {
+                       struct snd_soc_dapm_widget template;
+
+                       memset(&template, 0, sizeof(template));
+                       template.reg = mc->reg;
+                       template.mask = (1 << fls(mc->max)) - 1;
+                       template.shift = mc->shift;
+                       if (mc->invert)
+                               template.off_val = mc->max;
+                       else
+                               template.off_val = 0;
+                       template.on_val = template.off_val;
+                       template.id = snd_soc_dapm_kcontrol;
+                       template.name = kcontrol->id.name;
+
+                       data->widget = snd_soc_dapm_new_control(widget->dapm,
+                               &template);
+                       if (!data->widget) {
+                               kfree(data);
+                               return -ENOMEM;
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+
+       kcontrol->private_data = data;
+
+       return 0;
 }
 
-/* get soc_card from DAPM context */
-static inline struct snd_soc_card *dapm_get_soc_card(
-               struct snd_soc_dapm_context *dapm)
+static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
 {
-       if (dapm->codec)
-               return dapm->codec->card;
-       else if (dapm->platform)
-               return dapm->platform->card;
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl);
+       kfree(data->widget);
+       kfree(data->wlist);
+       kfree(data);
+}
+
+static struct snd_soc_dapm_widget_list *dapm_kcontrol_get_wlist(
+       const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       return data->wlist;
+}
+
+static int dapm_kcontrol_add_widget(struct snd_kcontrol *kcontrol,
+       struct snd_soc_dapm_widget *widget)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+       struct snd_soc_dapm_widget_list *new_wlist;
+       unsigned int n;
+
+       if (data->wlist)
+               n = data->wlist->num_widgets + 1;
        else
-               BUG();
+               n = 1;
 
-       /* unreachable */
-       return NULL;
+       new_wlist = krealloc(data->wlist,
+                       sizeof(*new_wlist) + sizeof(widget) * n, GFP_KERNEL);
+       if (!new_wlist)
+               return -ENOMEM;
+
+       new_wlist->widgets[n - 1] = widget;
+       new_wlist->num_widgets = n;
+
+       data->wlist = new_wlist;
+
+       return 0;
+}
+
+static void dapm_kcontrol_add_path(const struct snd_kcontrol *kcontrol,
+       struct snd_soc_dapm_path *path)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       list_add_tail(&path->list_kcontrol, &data->paths);
+
+       if (data->widget) {
+               snd_soc_dapm_add_path(data->widget->dapm, data->widget,
+                   path->source, NULL, NULL);
+       }
+}
+
+static bool dapm_kcontrol_is_powered(const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       if (!data->widget)
+               return true;
+
+       return data->widget->power;
+}
+
+static struct list_head *dapm_kcontrol_get_path_list(
+       const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       return &data->paths;
 }
 
+#define dapm_kcontrol_for_each_path(path, kcontrol) \
+       list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \
+               list_kcontrol)
+
+static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       return data->value;
+}
+
+static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol,
+       unsigned int value)
+{
+       struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol);
+
+       if (data->value == value)
+               return false;
+
+       if (data->widget)
+               data->widget->on_val = value;
+
+       data->value = value;
+
+       return true;
+}
+
+/**
+ * snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
+ * @kcontrol: The kcontrol
+ */
+struct snd_soc_codec *snd_soc_dapm_kcontrol_codec(struct snd_kcontrol *kcontrol)
+{
+       return dapm_kcontrol_get_wlist(kcontrol)->widgets[0]->codec;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dapm_kcontrol_codec);
+
 static void dapm_reset(struct snd_soc_card *card)
 {
        struct snd_soc_dapm_widget *w;
@@ -211,6 +362,7 @@ static void dapm_reset(struct snd_soc_card *card)
        memset(&card->dapm_stats, 0, sizeof(card->dapm_stats));
 
        list_for_each_entry(w, &card->widgets, list) {
+               w->new_power = w->power;
                w->power_checked = false;
                w->inputs = -1;
                w->outputs = -1;
@@ -428,6 +580,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w,
        case snd_soc_dapm_spk:
        case snd_soc_dapm_line:
        case snd_soc_dapm_dai_link:
+       case snd_soc_dapm_kcontrol:
                p->connect = 1;
        break;
        /* does affect routing - dynamically connected */
@@ -507,17 +660,12 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
-static void dapm_kcontrol_free(struct snd_kcontrol *kctl)
-{
-       kfree(kctl->private_data);
-}
-
 /*
  * Determine if a kcontrol is shared. If it is, look it up. If it isn't,
  * create it. Either way, add the widget into the control's widget list
  */
 static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
-       int kci, struct snd_soc_dapm_path *path)
+       int kci)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_card *card = dapm->card->snd_card;
@@ -525,9 +673,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        size_t prefix_len;
        int shared;
        struct snd_kcontrol *kcontrol;
-       struct snd_soc_dapm_widget_list *wlist;
-       int wlistentries;
-       size_t wlistsize;
        bool wname_in_long_name, kcname_in_long_name;
        char *long_name;
        const char *name;
@@ -546,25 +691,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
        shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
                                         &kcontrol);
 
-       if (kcontrol) {
-               wlist = kcontrol->private_data;
-               wlistentries = wlist->num_widgets + 1;
-       } else {
-               wlist = NULL;
-               wlistentries = 1;
-       }
-
-       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
-                       wlistentries * sizeof(struct snd_soc_dapm_widget *);
-       wlist = krealloc(wlist, wlistsize, GFP_KERNEL);
-       if (wlist == NULL) {
-               dev_err(dapm->dev, "ASoC: can't allocate widget list for %s\n",
-                       w->name);
-               return -ENOMEM;
-       }
-       wlist->num_widgets = wlistentries;
-       wlist->widgets[wlistentries - 1] = w;
-
        if (!kcontrol) {
                if (shared) {
                        wname_in_long_name = false;
@@ -587,7 +713,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                                kcname_in_long_name = false;
                                break;
                        default:
-                               kfree(wlist);
                                return -EINVAL;
                        }
                }
@@ -602,10 +727,8 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                        long_name = kasprintf(GFP_KERNEL, "%s %s",
                                 w->name + prefix_len,
                                 w->kcontrol_news[kci].name);
-                       if (long_name == NULL) {
-                               kfree(wlist);
+                       if (long_name == NULL)
                                return -ENOMEM;
-                       }
 
                        name = long_name;
                } else if (wname_in_long_name) {
@@ -616,23 +739,33 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w,
                        name = w->kcontrol_news[kci].name;
                }
 
-               kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+               kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], NULL, name,
                                        prefix);
-               kcontrol->private_free = dapm_kcontrol_free;
                kfree(long_name);
+               if (!kcontrol)
+                       return -ENOMEM;
+               kcontrol->private_free = dapm_kcontrol_free;
+
+               ret = dapm_kcontrol_data_alloc(w, kcontrol);
+               if (ret) {
+                       snd_ctl_free_one(kcontrol);
+                       return ret;
+               }
+
                ret = snd_ctl_add(card, kcontrol);
                if (ret < 0) {
                        dev_err(dapm->dev,
                                "ASoC: failed to add widget %s dapm kcontrol %s: %d\n",
                                w->name, name, ret);
-                       kfree(wlist);
                        return ret;
                }
        }
 
-       kcontrol->private_data = wlist;
+       ret = dapm_kcontrol_add_widget(kcontrol, w);
+       if (ret)
+               return ret;
+
        w->kcontrols[kci] = kcontrol;
-       path->kcontrol = kcontrol;
 
        return 0;
 }
@@ -652,13 +785,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
                                continue;
 
                        if (w->kcontrols[i]) {
-                               path->kcontrol = w->kcontrols[i];
+                               dapm_kcontrol_add_path(w->kcontrols[i], path);
                                continue;
                        }
 
-                       ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
+                       ret = dapm_create_or_share_mixmux_kcontrol(w, i);
                        if (ret < 0)
                                return ret;
+
+                       dapm_kcontrol_add_path(w->kcontrols[i], path);
                }
        }
 
@@ -679,19 +814,17 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
                return -EINVAL;
        }
 
-       path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
-                               list_sink);
-       if (!path) {
+       if (list_empty(&w->sources)) {
                dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
                return -EINVAL;
        }
 
-       ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
+       ret = dapm_create_or_share_mixmux_kcontrol(w, 0);
        if (ret < 0)
                return ret;
 
        list_for_each_entry(path, &w->sources, list_sink)
-               path->kcontrol = w->kcontrols[0];
+               dapm_kcontrol_add_path(w->kcontrols[0], path);
 
        return 0;
 }
@@ -812,6 +945,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
        case snd_soc_dapm_clock_supply:
+       case snd_soc_dapm_kcontrol:
                return 0;
        default:
                break;
@@ -907,6 +1041,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
        case snd_soc_dapm_clock_supply:
+       case snd_soc_dapm_kcontrol:
                return 0;
        default:
                break;
@@ -1061,7 +1196,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
        int ret;
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
-               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+               if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, false);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
@@ -1071,7 +1206,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w,
 
                return regulator_enable(w->regulator);
        } else {
-               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+               if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
@@ -1243,10 +1378,9 @@ static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget,
        list_add_tail(&new_widget->power_list, list);
 }
 
-static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
+static void dapm_seq_check_event(struct snd_soc_card *card,
                                 struct snd_soc_dapm_widget *w, int event)
 {
-       struct snd_soc_card *card = dapm->card;
        const char *ev_name;
        int power, ret;
 
@@ -1280,55 +1414,50 @@ static void dapm_seq_check_event(struct snd_soc_dapm_context *dapm,
                return;
        }
 
-       if (w->power != power)
+       if (w->new_power != power)
                return;
 
        if (w->event && (w->event_flags & event)) {
-               pop_dbg(dapm->dev, card->pop_time, "pop test : %s %s\n",
+               pop_dbg(w->dapm->dev, card->pop_time, "pop test : %s %s\n",
                        w->name, ev_name);
                trace_snd_soc_dapm_widget_event_start(w, event);
                ret = w->event(w, NULL, event);
                trace_snd_soc_dapm_widget_event_done(w, event);
                if (ret < 0)
-                       dev_err(dapm->dev, "ASoC: %s: %s event failed: %d\n",
+                       dev_err(w->dapm->dev, "ASoC: %s: %s event failed: %d\n",
                               ev_name, w->name, ret);
        }
 }
 
 /* Apply the coalesced changes from a DAPM sequence */
-static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
+static void dapm_seq_run_coalesced(struct snd_soc_card *card,
                                   struct list_head *pending)
 {
-       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
-       int reg, power;
+       int reg;
        unsigned int value = 0;
        unsigned int mask = 0;
-       unsigned int cur_mask;
 
        reg = list_first_entry(pending, struct snd_soc_dapm_widget,
                               power_list)->reg;
 
        list_for_each_entry(w, pending, power_list) {
-               cur_mask = 1 << w->shift;
                BUG_ON(reg != w->reg);
+               w->power = w->new_power;
 
-               if (w->invert)
-                       power = !w->power;
+               mask |= w->mask << w->shift;
+               if (w->power)
+                       value |= w->on_val << w->shift;
                else
-                       power = w->power;
-
-               mask |= cur_mask;
-               if (power)
-                       value |= cur_mask;
+                       value |= w->off_val << w->shift;
 
-               pop_dbg(dapm->dev, card->pop_time,
+               pop_dbg(w->dapm->dev, card->pop_time,
                        "pop test : Queue %s: reg=0x%x, 0x%x/0x%x\n",
                        w->name, reg, value, mask);
 
                /* Check for events */
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMU);
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_PRE_PMD);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMU);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_PRE_PMD);
        }
 
        if (reg >= 0) {
@@ -1338,7 +1467,7 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
                w = list_first_entry(pending, struct snd_soc_dapm_widget,
                                     power_list);
 
-               pop_dbg(dapm->dev, card->pop_time,
+               pop_dbg(w->dapm->dev, card->pop_time,
                        "pop test : Applying 0x%x/0x%x to %x in %dms\n",
                        value, mask, reg, card->pop_time);
                pop_wait(card->pop_time);
@@ -1346,8 +1475,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
        }
 
        list_for_each_entry(w, pending, power_list) {
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMU);
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_POST_PMD);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMU);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_POST_PMD);
        }
 }
 
@@ -1359,8 +1488,8 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm,
  * Currently anything that requires more than a single write is not
  * handled.
  */
-static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
-                        struct list_head *list, int event, bool power_up)
+static void dapm_seq_run(struct snd_soc_card *card,
+       struct list_head *list, int event, bool power_up)
 {
        struct snd_soc_dapm_widget *w, *n;
        LIST_HEAD(pending);
@@ -1383,7 +1512,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
                if (sort[w->id] != cur_sort || w->reg != cur_reg ||
                    w->dapm != cur_dapm || w->subseq != cur_subseq) {
                        if (!list_empty(&pending))
-                               dapm_seq_run_coalesced(cur_dapm, &pending);
+                               dapm_seq_run_coalesced(card, &pending);
 
                        if (cur_dapm && cur_dapm->seq_notifier) {
                                for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
@@ -1443,7 +1572,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
        }
 
        if (!list_empty(&pending))
-               dapm_seq_run_coalesced(cur_dapm, &pending);
+               dapm_seq_run_coalesced(card, &pending);
 
        if (cur_dapm && cur_dapm->seq_notifier) {
                for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++)
@@ -1453,37 +1582,48 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm,
        }
 }
 
-static void dapm_widget_update(struct snd_soc_dapm_context *dapm)
+static void dapm_widget_update(struct snd_soc_card *card)
 {
-       struct snd_soc_dapm_update *update = dapm->update;
-       struct snd_soc_dapm_widget *w;
+       struct snd_soc_dapm_update *update = card->update;
+       struct snd_soc_dapm_widget_list *wlist;
+       struct snd_soc_dapm_widget *w = NULL;
+       unsigned int wi;
        int ret;
 
-       if (!update)
+       if (!update || !dapm_kcontrol_is_powered(update->kcontrol))
                return;
 
-       w = update->widget;
+       wlist = dapm_kcontrol_get_wlist(update->kcontrol);
 
-       if (w->event &&
-           (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
-               ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
-               if (ret != 0)
-                       dev_err(dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
-                              w->name, ret);
+       for (wi = 0; wi < wlist->num_widgets; wi++) {
+               w = wlist->widgets[wi];
+
+               if (w->event && (w->event_flags & SND_SOC_DAPM_PRE_REG)) {
+                       ret = w->event(w, update->kcontrol, SND_SOC_DAPM_PRE_REG);
+                       if (ret != 0)
+                               dev_err(w->dapm->dev, "ASoC: %s DAPM pre-event failed: %d\n",
+                                          w->name, ret);
+               }
        }
 
+       if (!w)
+               return;
+
        ret = soc_widget_update_bits_locked(w, update->reg, update->mask,
                                  update->val);
        if (ret < 0)
-               dev_err(dapm->dev, "ASoC: %s DAPM update failed: %d\n",
+               dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n",
                        w->name, ret);
 
-       if (w->event &&
-           (w->event_flags & SND_SOC_DAPM_POST_REG)) {
-               ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
-               if (ret != 0)
-                       dev_err(dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
-                              w->name, ret);
+       for (wi = 0; wi < wlist->num_widgets; wi++) {
+               w = wlist->widgets[wi];
+
+               if (w->event && (w->event_flags & SND_SOC_DAPM_POST_REG)) {
+                       ret = w->event(w, update->kcontrol, SND_SOC_DAPM_POST_REG);
+                       if (ret != 0)
+                               dev_err(w->dapm->dev, "ASoC: %s DAPM post-event failed: %d\n",
+                                          w->name, ret);
+               }
        }
 }
 
@@ -1595,6 +1735,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
        case snd_soc_dapm_clock_supply:
+       case snd_soc_dapm_kcontrol:
                /* Supplies can't affect their outputs, only their inputs */
                break;
        default:
@@ -1611,8 +1752,6 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
                dapm_seq_insert(w, up_list, true);
        else
                dapm_seq_insert(w, down_list, false);
-
-       w->power = power;
 }
 
 static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
@@ -1646,9 +1785,8 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w,
  *  o Input pin to Output pin (bypass, sidetone)
  *  o DAC to ADC (loopback).
  */
-static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
+static int dapm_power_widgets(struct snd_soc_card *card, int event)
 {
-       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
        struct snd_soc_dapm_context *d;
        LIST_HEAD(up_list);
@@ -1688,7 +1826,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                        break;
                }
 
-               if (w->power) {
+               if (w->new_power) {
                        d = w->dapm;
 
                        /* Supplies and micbiases only bring the
@@ -1730,29 +1868,29 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
        trace_snd_soc_dapm_walk_done(card);
 
        /* Run all the bias changes in parallel */
-       list_for_each_entry(d, &dapm->card->dapm_list, list)
+       list_for_each_entry(d, &card->dapm_list, list)
                async_schedule_domain(dapm_pre_sequence_async, d,
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
 
        list_for_each_entry(w, &down_list, power_list) {
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMD);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMD);
        }
 
        list_for_each_entry(w, &up_list, power_list) {
-               dapm_seq_check_event(dapm, w, SND_SOC_DAPM_WILL_PMU);
+               dapm_seq_check_event(card, w, SND_SOC_DAPM_WILL_PMU);
        }
 
        /* Power down widgets first; try to avoid amplifying pops. */
-       dapm_seq_run(dapm, &down_list, event, false);
+       dapm_seq_run(card, &down_list, event, false);
 
-       dapm_widget_update(dapm);
+       dapm_widget_update(card);
 
        /* Now power up. */
-       dapm_seq_run(dapm, &up_list, event, true);
+       dapm_seq_run(card, &up_list, event, true);
 
        /* Run all the bias changes in parallel */
-       list_for_each_entry(d, &dapm->card->dapm_list, list)
+       list_for_each_entry(d, &card->dapm_list, list)
                async_schedule_domain(dapm_post_sequence_async, d,
                                        &async_domain);
        async_synchronize_full_domain(&async_domain);
@@ -1763,7 +1901,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event)
                        d->stream_event(d, event);
        }
 
-       pop_dbg(dapm->dev, card->pop_time,
+       pop_dbg(card->dev, card->pop_time,
                "DAPM sequencing finished, waiting %dms\n", card->pop_time);
        pop_wait(card->pop_time);
 
@@ -1798,8 +1936,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
 
        if (w->reg >= 0)
                ret += snprintf(buf + ret, PAGE_SIZE - ret,
-                               " - R%d(0x%x) bit %d",
-                               w->reg, w->reg, w->shift);
+                               " - R%d(0x%x) mask 0x%x",
+                               w->reg, w->reg, w->mask << w->shift);
 
        ret += snprintf(buf + ret, PAGE_SIZE - ret, "\n");
 
@@ -1936,22 +2074,14 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
 #endif
 
 /* test and update the power status of a mux widget */
-static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mux_update_power(struct snd_soc_card *card,
                                 struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
 
-       if (widget->id != snd_soc_dapm_mux &&
-           widget->id != snd_soc_dapm_virt_mux &&
-           widget->id != snd_soc_dapm_value_mux)
-               return -ENODEV;
-
        /* find dapm widget path assoc with kcontrol */
-       list_for_each_entry(path, &widget->dapm->card->paths, list) {
-               if (path->kcontrol != kcontrol)
-                       continue;
-
+       dapm_kcontrol_for_each_path(path, kcontrol) {
                if (!path->name || !e->texts[mux])
                        continue;
 
@@ -1966,73 +2096,68 @@ static int soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
                                                "mux disconnection");
                        path->connect = 0; /* old connection must be powered down */
                }
+               dapm_mark_dirty(path->sink, "mux change");
        }
 
-       if (found) {
-               dapm_mark_dirty(widget, "mux change");
-               dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-       }
+       if (found)
+               dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
 
        return found;
 }
 
-int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_widget *widget,
-               struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
+int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
+       struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e,
+       struct snd_soc_dapm_update *update)
 {
-       struct snd_soc_card *card = widget->dapm->card;
+       struct snd_soc_card *card = dapm->card;
        int ret;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+       card->update = update;
+       ret = soc_dapm_mux_update_power(card, kcontrol, mux, e);
+       card->update = NULL;
        mutex_unlock(&card->dapm_mutex);
        if (ret > 0)
-               soc_dpcm_runtime_update(widget);
+               soc_dpcm_runtime_update(card);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
 
 /* test and update the power status of a mixer or switch widget */
-static int soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
+static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
                                   struct snd_kcontrol *kcontrol, int connect)
 {
        struct snd_soc_dapm_path *path;
        int found = 0;
 
-       if (widget->id != snd_soc_dapm_mixer &&
-           widget->id != snd_soc_dapm_mixer_named_ctl &&
-           widget->id != snd_soc_dapm_switch)
-               return -ENODEV;
-
        /* find dapm widget path assoc with kcontrol */
-       list_for_each_entry(path, &widget->dapm->card->paths, list) {
-               if (path->kcontrol != kcontrol)
-                       continue;
-
-               /* found, now check type */
+       dapm_kcontrol_for_each_path(path, kcontrol) {
                found = 1;
                path->connect = connect;
                dapm_mark_dirty(path->source, "mixer connection");
+               dapm_mark_dirty(path->sink, "mixer update");
        }
 
-       if (found) {
-               dapm_mark_dirty(widget, "mixer update");
-               dapm_power_widgets(widget->dapm, SND_SOC_DAPM_STREAM_NOP);
-       }
+       if (found)
+               dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
 
        return found;
 }
 
-int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_widget *widget,
-                               struct snd_kcontrol *kcontrol, int connect)
+int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
+       struct snd_kcontrol *kcontrol, int connect,
+       struct snd_soc_dapm_update *update)
 {
-       struct snd_soc_card *card = widget->dapm->card;
+       struct snd_soc_card *card = dapm->card;
        int ret;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = soc_dapm_mixer_update_power(widget, kcontrol, connect);
+       card->update = update;
+       ret = soc_dapm_mixer_update_power(card, kcontrol, connect);
+       card->update = NULL;
        mutex_unlock(&card->dapm_mutex);
        if (ret > 0)
-               soc_dpcm_runtime_update(widget);
+               soc_dpcm_runtime_update(card);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
@@ -2111,6 +2236,7 @@ static void dapm_free_path(struct snd_soc_dapm_path *path)
 {
        list_del(&path->list_sink);
        list_del(&path->list_source);
+       list_del(&path->list_kcontrol);
        list_del(&path->list);
        kfree(path);
 }
@@ -2205,70 +2331,20 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
                return 0;
 
        mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
-       ret = dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
+       ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP);
        mutex_unlock(&dapm->card->dapm_mutex);
        return ret;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
 
-static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
-                                 const struct snd_soc_dapm_route *route)
+static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
+       struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
+       const char *control,
+       int (*connected)(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink))
 {
        struct snd_soc_dapm_path *path;
-       struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
-       struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
-       const char *sink;
-       const char *control = route->control;
-       const char *source;
-       char prefixed_sink[80];
-       char prefixed_source[80];
-       int ret = 0;
-
-       if (dapm->codec && dapm->codec->name_prefix) {
-               snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
-                        dapm->codec->name_prefix, route->sink);
-               sink = prefixed_sink;
-               snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
-                        dapm->codec->name_prefix, route->source);
-               source = prefixed_source;
-       } else {
-               sink = route->sink;
-               source = route->source;
-       }
-
-       /*
-        * find src and dest widgets over all widgets but favor a widget from
-        * current DAPM context
-        */
-       list_for_each_entry(w, &dapm->card->widgets, list) {
-               if (!wsink && !(strcmp(w->name, sink))) {
-                       wtsink = w;
-                       if (w->dapm == dapm)
-                               wsink = w;
-                       continue;
-               }
-               if (!wsource && !(strcmp(w->name, source))) {
-                       wtsource = w;
-                       if (w->dapm == dapm)
-                               wsource = w;
-               }
-       }
-       /* use widget from another DAPM context if not found from this */
-       if (!wsink)
-               wsink = wtsink;
-       if (!wsource)
-               wsource = wtsource;
-
-       if (wsource == NULL) {
-               dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
-                       route->source);
-               return -ENODEV;
-       }
-       if (wsink == NULL) {
-               dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
-                       route->sink);
-               return -ENODEV;
-       }
+       int ret;
 
        path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
        if (!path)
@@ -2276,8 +2352,9 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
 
        path->source = wsource;
        path->sink = wsink;
-       path->connected = route->connected;
+       path->connected = connected;
        INIT_LIST_HEAD(&path->list);
+       INIT_LIST_HEAD(&path->list_kcontrol);
        INIT_LIST_HEAD(&path->list_source);
        INIT_LIST_HEAD(&path->list_sink);
 
@@ -2327,6 +2404,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_dai_in:
        case snd_soc_dapm_dai_out:
        case snd_soc_dapm_dai_link:
+       case snd_soc_dapm_kcontrol:
                list_add(&path->list, &dapm->card->paths);
                list_add(&path->list_sink, &wsink->sources);
                list_add(&path->list_source, &wsource->sinks);
@@ -2362,11 +2440,77 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
        dapm_mark_dirty(wsink, "Route added");
 
        return 0;
+err:
+       kfree(path);
+       return ret;
+}
+
+static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm,
+                                 const struct snd_soc_dapm_route *route)
+{
+       struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w;
+       struct snd_soc_dapm_widget *wtsource = NULL, *wtsink = NULL;
+       const char *sink;
+       const char *source;
+       char prefixed_sink[80];
+       char prefixed_source[80];
+       int ret;
+
+       if (dapm->codec && dapm->codec->name_prefix) {
+               snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s",
+                        dapm->codec->name_prefix, route->sink);
+               sink = prefixed_sink;
+               snprintf(prefixed_source, sizeof(prefixed_source), "%s %s",
+                        dapm->codec->name_prefix, route->source);
+               source = prefixed_source;
+       } else {
+               sink = route->sink;
+               source = route->source;
+       }
+
+       /*
+        * find src and dest widgets over all widgets but favor a widget from
+        * current DAPM context
+        */
+       list_for_each_entry(w, &dapm->card->widgets, list) {
+               if (!wsink && !(strcmp(w->name, sink))) {
+                       wtsink = w;
+                       if (w->dapm == dapm)
+                               wsink = w;
+                       continue;
+               }
+               if (!wsource && !(strcmp(w->name, source))) {
+                       wtsource = w;
+                       if (w->dapm == dapm)
+                               wsource = w;
+               }
+       }
+       /* use widget from another DAPM context if not found from this */
+       if (!wsink)
+               wsink = wtsink;
+       if (!wsource)
+               wsource = wtsource;
+
+       if (wsource == NULL) {
+               dev_err(dapm->dev, "ASoC: no source widget found for %s\n",
+                       route->source);
+               return -ENODEV;
+       }
+       if (wsink == NULL) {
+               dev_err(dapm->dev, "ASoC: no sink widget found for %s\n",
+                       route->sink);
+               return -ENODEV;
+       }
+
+       ret = snd_soc_dapm_add_path(dapm, wsource, wsink, route->control,
+               route->connected);
+       if (ret)
+               goto err;
 
+       return 0;
 err:
        dev_warn(dapm->dev, "ASoC: no dapm match for %s --> %s --> %s\n",
-                source, control, sink);
-       kfree(path);
+                source, route->control, sink);
        return ret;
 }
 
@@ -2570,12 +2714,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes);
  */
 int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 {
+       struct snd_soc_card *card = dapm->card;
        struct snd_soc_dapm_widget *w;
        unsigned int val;
 
-       mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT);
 
-       list_for_each_entry(w, &dapm->card->widgets, list)
+       list_for_each_entry(w, &card->widgets, list)
        {
                if (w->new)
                        continue;
@@ -2585,7 +2730,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                                                sizeof(struct snd_kcontrol *),
                                                GFP_KERNEL);
                        if (!w->kcontrols) {
-                               mutex_unlock(&dapm->card->dapm_mutex);
+                               mutex_unlock(&card->dapm_mutex);
                                return -ENOMEM;
                        }
                }
@@ -2611,12 +2756,9 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
 
                /* Read the initial power state from the device */
                if (w->reg >= 0) {
-                       val = soc_widget_read(w, w->reg);
-                       val &= 1 << w->shift;
-                       if (w->invert)
-                               val = !val;
-
-                       if (val)
+                       val = soc_widget_read(w, w->reg) >> w->shift;
+                       val &= w->mask;
+                       if (val == w->on_val)
                                w->power = 1;
                }
 
@@ -2626,8 +2768,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm)
                dapm_debugfs_add_widget(w);
        }
 
-       dapm_power_widgets(dapm, SND_SOC_DAPM_STREAM_NOP);
-       mutex_unlock(&dapm->card->dapm_mutex);
+       dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP);
+       mutex_unlock(&card->dapm_mutex);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
@@ -2644,8 +2786,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
 int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
+       struct snd_soc_card *card = codec->card;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int reg = mc->reg;
@@ -2653,17 +2795,24 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol,
        int max = mc->max;
        unsigned int mask = (1 << fls(max)) - 1;
        unsigned int invert = mc->invert;
+       unsigned int val;
 
        if (snd_soc_volsw_is_stereo(mc))
-               dev_warn(widget->dapm->dev,
+               dev_warn(codec->dapm.dev,
                         "ASoC: Control '%s' is stereo, which is not supported\n",
                         kcontrol->id.name);
 
-       ucontrol->value.integer.value[0] =
-               (snd_soc_read(widget->codec, reg) >> shift) & mask;
+       mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
+       if (dapm_kcontrol_is_powered(kcontrol))
+               val = (snd_soc_read(codec, reg) >> shift) & mask;
+       else
+               val = dapm_kcontrol_get_value(kcontrol);
+       mutex_unlock(&card->dapm_mutex);
+
        if (invert)
-               ucontrol->value.integer.value[0] =
-                       max - ucontrol->value.integer.value[0];
+               ucontrol->value.integer.value[0] = max - val;
+       else
+               ucontrol->value.integer.value[0] = val;
 
        return 0;
 }
@@ -2681,9 +2830,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw);
 int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
@@ -2695,10 +2842,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
        unsigned int val;
        int connect, change;
        struct snd_soc_dapm_update update;
-       int wi;
 
        if (snd_soc_volsw_is_stereo(mc))
-               dev_warn(widget->dapm->dev,
+               dev_warn(codec->dapm.dev,
                         "ASoC: Control '%s' is stereo, which is not supported\n",
                         kcontrol->id.name);
 
@@ -2707,33 +2853,30 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
 
        if (invert)
                val = max - val;
-       mask = mask << shift;
-       val = val << shift;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(widget->codec, reg, mask, val);
-       if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
+       dapm_kcontrol_set_value(kcontrol, val);
 
-                       widget->value = val;
+       mask = mask << shift;
+       val = val << shift;
 
-                       update.kcontrol = kcontrol;
-                       update.widget = widget;
-                       update.reg = reg;
-                       update.mask = mask;
-                       update.val = val;
-                       widget->dapm->update = &update;
+       change = snd_soc_test_bits(codec, reg, mask, val);
+       if (change) {
+               update.kcontrol = kcontrol;
+               update.reg = reg;
+               update.mask = mask;
+               update.val = val;
 
-                       soc_dapm_mixer_update_power(widget, kcontrol, connect);
+               card->update = &update;
 
-                       widget->dapm->update = NULL;
-               }
+               soc_dapm_mixer_update_power(card, kcontrol, connect);
+
+               card->update = NULL;
        }
 
        mutex_unlock(&card->dapm_mutex);
-       return 0;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 
@@ -2749,12 +2892,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_volsw);
 int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val;
 
-       val = snd_soc_read(widget->codec, e->reg);
+       val = snd_soc_read(codec, e->reg);
        ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask;
        if (e->shift_l != e->shift_r)
                ucontrol->value.enumerated.item[1] =
@@ -2776,15 +2918,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double);
 int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
        struct snd_soc_dapm_update update;
-       int wi;
 
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
@@ -2800,24 +2939,17 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       change = snd_soc_test_bits(codec, e->reg, mask, val);
        if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
-
-                       widget->value = val;
-
-                       update.kcontrol = kcontrol;
-                       update.widget = widget;
-                       update.reg = e->reg;
-                       update.mask = mask;
-                       update.val = val;
-                       widget->dapm->update = &update;
+               update.kcontrol = kcontrol;
+               update.reg = e->reg;
+               update.mask = mask;
+               update.val = val;
+               card->update = &update;
 
-                       soc_dapm_mux_update_power(widget, kcontrol, mux, e);
+               soc_dapm_mux_update_power(card, kcontrol, mux, e);
 
-                       widget->dapm->update = NULL;
-               }
+               card->update = NULL;
        }
 
        mutex_unlock(&card->dapm_mutex);
@@ -2835,11 +2967,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double);
 int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-
-       ucontrol->value.enumerated.item[0] = widget->value;
-
+       ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol);
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
@@ -2854,34 +2982,25 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt);
 int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
+       unsigned int value;
        struct soc_enum *e =
                (struct soc_enum *)kcontrol->private_value;
        int change;
-       int ret = 0;
-       int wi;
 
        if (ucontrol->value.enumerated.item[0] >= e->max)
                return -EINVAL;
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = widget->value != ucontrol->value.enumerated.item[0];
-       if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
-
-                       widget->value = ucontrol->value.enumerated.item[0];
-
-                       soc_dapm_mux_update_power(widget, kcontrol, widget->value, e);
-               }
-       }
+       value = ucontrol->value.enumerated.item[0];
+       change = dapm_kcontrol_set_value(kcontrol, value);
+       if (change)
+               soc_dapm_mux_update_power(card, kcontrol, value, e);
 
        mutex_unlock(&card->dapm_mutex);
-       return ret;
+       return change;
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 
@@ -2901,12 +3020,11 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt);
 int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int reg_val, val, mux;
 
-       reg_val = snd_soc_read(widget->codec, e->reg);
+       reg_val = snd_soc_read(codec, e->reg);
        val = (reg_val >> e->shift_l) & e->mask;
        for (mux = 0; mux < e->max; mux++) {
                if (val == e->values[mux])
@@ -2942,15 +3060,12 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double);
 int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
-       struct snd_soc_dapm_widget *widget = wlist->widgets[0];
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
        struct snd_soc_card *card = codec->card;
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int val, mux, change;
        unsigned int mask;
        struct snd_soc_dapm_update update;
-       int wi;
 
        if (ucontrol->value.enumerated.item[0] > e->max - 1)
                return -EINVAL;
@@ -2966,24 +3081,17 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol,
 
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
 
-       change = snd_soc_test_bits(widget->codec, e->reg, mask, val);
+       change = snd_soc_test_bits(codec, e->reg, mask, val);
        if (change) {
-               for (wi = 0; wi < wlist->num_widgets; wi++) {
-                       widget = wlist->widgets[wi];
-
-                       widget->value = val;
+               update.kcontrol = kcontrol;
+               update.reg = e->reg;
+               update.mask = mask;
+               update.val = val;
+               card->update = &update;
 
-                       update.kcontrol = kcontrol;
-                       update.widget = widget;
-                       update.reg = e->reg;
-                       update.mask = mask;
-                       update.val = val;
-                       widget->dapm->update = &update;
+               soc_dapm_mux_update_power(card, kcontrol, mux, e);
 
-                       soc_dapm_mux_update_power(widget, kcontrol, mux, e);
-
-                       widget->dapm->update = NULL;
-               }
+               card->update = NULL;
        }
 
        mutex_unlock(&card->dapm_mutex);
@@ -3080,7 +3188,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                        return NULL;
                }
 
-               if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
+               if (w->on_val & SND_SOC_DAPM_REGULATOR_BYPASS) {
                        ret = regulator_allow_bypass(w->regulator, true);
                        if (ret != 0)
                                dev_warn(w->dapm->dev,
@@ -3127,16 +3235,16 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_value_mux:
                w->power_check = dapm_generic_check_power;
                break;
-       case snd_soc_dapm_adc:
-       case snd_soc_dapm_aif_out:
        case snd_soc_dapm_dai_out:
                w->power_check = dapm_adc_check_power;
                break;
-       case snd_soc_dapm_dac:
-       case snd_soc_dapm_aif_in:
        case snd_soc_dapm_dai_in:
                w->power_check = dapm_dac_check_power;
                break;
+       case snd_soc_dapm_adc:
+       case snd_soc_dapm_aif_out:
+       case snd_soc_dapm_dac:
+       case snd_soc_dapm_aif_in:
        case snd_soc_dapm_pga:
        case snd_soc_dapm_out_drv:
        case snd_soc_dapm_input:
@@ -3152,6 +3260,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        case snd_soc_dapm_supply:
        case snd_soc_dapm_regulator_supply:
        case snd_soc_dapm_clock_supply:
+       case snd_soc_dapm_kcontrol:
                w->power_check = dapm_supply_check_power;
                break;
        default:
@@ -3416,9 +3525,6 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
 {
        struct snd_soc_dapm_widget *dai_w, *w;
        struct snd_soc_dai *dai;
-       struct snd_soc_dapm_route r;
-
-       memset(&r, 0, sizeof(r));
 
        /* For each DAI widget... */
        list_for_each_entry(dai_w, &card->widgets, list) {
@@ -3445,29 +3551,27 @@ int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card)
                                break;
                        }
 
-                       if (!w->sname)
+                       if (!w->sname || !strstr(w->sname, dai_w->name))
                                continue;
 
                        if (dai->driver->playback.stream_name &&
                            strstr(w->sname,
                                   dai->driver->playback.stream_name)) {
-                               r.source = dai->playback_widget->name;
-                               r.sink = w->name;
                                dev_dbg(dai->dev, "%s -> %s\n",
-                                        r.source, r.sink);
+                                        dai->playback_widget->name, w->name);
 
-                               snd_soc_dapm_add_route(w->dapm, &r);
+                               snd_soc_dapm_add_path(w->dapm,
+                                       dai->playback_widget, w, NULL, NULL);
                        }
 
                        if (dai->driver->capture.stream_name &&
                            strstr(w->sname,
                                   dai->driver->capture.stream_name)) {
-                               r.source = w->name;
-                               r.sink = dai->capture_widget->name;
                                dev_dbg(dai->dev, "%s -> %s\n",
-                                       r.source, r.sink);
+                                       w->name, dai->capture_widget->name);
 
-                               snd_soc_dapm_add_route(w->dapm, &r);
+                               snd_soc_dapm_add_path(w->dapm, w,
+                                       dai->capture_widget, NULL, NULL);
                        }
                }
        }
@@ -3529,7 +3633,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
                }
        }
 
-       dapm_power_widgets(&rtd->card->dapm, event);
+       dapm_power_widgets(rtd->card, event);
 }
 
 /**
@@ -3798,7 +3902,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm)
                if (dapm->bias_level == SND_SOC_BIAS_ON)
                        snd_soc_dapm_set_bias_level(dapm,
                                                    SND_SOC_BIAS_PREPARE);
-               dapm_seq_run(dapm, &down_list, 0, false);
+               dapm_seq_run(card, &down_list, 0, false);
                if (dapm->bias_level == SND_SOC_BIAS_PREPARE)
                        snd_soc_dapm_set_bias_level(dapm,
                                                    SND_SOC_BIAS_STANDBY);
index 0bb5ccc..7aa26b5 100644 (file)
@@ -263,7 +263,7 @@ static irqreturn_t gpio_handler(int irq, void *data)
        if (device_may_wakeup(dev))
                pm_wakeup_event(dev, gpio->debounce_time + 50);
 
-       schedule_delayed_work(&gpio->work,
+       queue_delayed_work(system_power_efficient_wq, &gpio->work,
                              msecs_to_jiffies(gpio->debounce_time));
 
        return IRQ_HANDLED;
index b6c6403..fb70fbe 100644 (file)
@@ -411,8 +411,9 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
                } else {
                        /* start delayed pop wq here for playback streams */
                        rtd->pop_wait = 1;
-                       schedule_delayed_work(&rtd->delayed_work,
-                               msecs_to_jiffies(rtd->pmdown_time));
+                       queue_delayed_work(system_power_efficient_wq,
+                                          &rtd->delayed_work,
+                                          msecs_to_jiffies(rtd->pmdown_time));
                }
        } else {
                /* capture streams can be powered down now */
@@ -1832,18 +1833,10 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream)
 /* Called by DAPM mixer/mux changes to update audio routing between PCMs and
  * any DAI links.
  */
-int soc_dpcm_runtime_update(struct snd_soc_dapm_widget *widget)
+int soc_dpcm_runtime_update(struct snd_soc_card *card)
 {
-       struct snd_soc_card *card;
        int i, old, new, paths;
 
-       if (widget->codec)
-               card = widget->codec->card;
-       else if (widget->platform)
-               card = widget->platform->card;
-       else
-               return -EINVAL;
-
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
        for (i = 0; i < card->num_rtd; i++) {
                struct snd_soc_dapm_widget_list *list;
index 3567d73..0a53053 100644 (file)
@@ -1,6 +1,6 @@
 config SND_SPEAR_SOC
        tristate
-       select SND_SOC_DMAENGINE_PCM
+       select SND_DMAENGINE_PCM
 
 config SND_SPEAR_SPDIF_OUT
        tristate
index 995b120..8fc653c 100644 (file)
@@ -1,8 +1,8 @@
 config SND_SOC_TEGRA
        tristate "SoC Audio for the Tegra System-on-Chip"
-       depends on ARCH_TEGRA && TEGRA20_APB_DMA
+       depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST
        select REGMAP_MMIO
-       select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
          Say Y or M here if you want support for SoC audio on Tegra.
 
@@ -61,7 +61,7 @@ config SND_SOC_TEGRA30_I2S
 
 config SND_SOC_TEGRA_RT5640
        tristate "SoC Audio support for Tegra boards using an RT5640 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_RT5640
@@ -71,7 +71,7 @@ config SND_SOC_TEGRA_RT5640
 
 config SND_SOC_TEGRA_WM8753
        tristate "SoC Audio support for Tegra boards using a WM8753 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_WM8753
@@ -81,7 +81,7 @@ config SND_SOC_TEGRA_WM8753
 
 config SND_SOC_TEGRA_WM8903
        tristate "SoC Audio support for Tegra boards using a WM8903 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
        select SND_SOC_WM8903
@@ -92,7 +92,7 @@ config SND_SOC_TEGRA_WM8903
 
 config SND_SOC_TEGRA_WM9712
        tristate "SoC Audio support for Tegra boards using a WM9712 codec"
-       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC
+       depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && GPIOLIB
        select SND_SOC_TEGRA20_AC97
        select SND_SOC_WM9712
        help
@@ -110,7 +110,7 @@ config SND_SOC_TEGRA_TRIMSLICE
 
 config SND_SOC_TEGRA_ALC5632
        tristate "SoC Audio support for Tegra boards using an ALC5632 codec"
-       depends on SND_SOC_TEGRA && I2C
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
        select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
        select SND_SOC_ALC5632
        help
index 6c48662..ae27bcd 100644 (file)
@@ -334,12 +334,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        }
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "No memory resource\n");
-               ret = -ENODEV;
-               goto err_clk_put;
-       }
-
        regs = devm_ioremap_resource(&pdev->dev, mem);
        if (IS_ERR(regs)) {
                ret = PTR_ERR(regs);
@@ -432,8 +426,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
 
        return 0;
 
-err_unregister_pcm:
-       tegra_pcm_platform_unregister(&pdev->dev);
 err_unregister_component:
        snd_soc_unregister_component(&pdev->dev);
 err_asoc_utils_fini:
index d04146c..47565fd 100644 (file)
@@ -228,7 +228,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream,
                reg = TEGRA30_I2S_CIF_RX_CTRL;
        } else {
                val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX;
-               reg = TEGRA30_I2S_CIF_RX_CTRL;
+               reg = TEGRA30_I2S_CIF_TX_CTRL;
        }
 
        regmap_write(i2s->regmap, reg, val);
index 48d05d9..c61ea3a 100644 (file)
@@ -13,8 +13,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 08794f9..4511c5a 100644 (file)
@@ -99,6 +99,7 @@ static struct snd_soc_jack_gpio tegra_rt5640_hp_jack_gpio = {
 static const struct snd_soc_dapm_widget tegra_rt5640_dapm_widgets[] = {
        SND_SOC_DAPM_HP("Headphones", NULL),
        SND_SOC_DAPM_SPK("Speakers", NULL),
+       SND_SOC_DAPM_MIC("Mic Jack", NULL),
 };
 
 static const struct snd_kcontrol_new tegra_rt5640_controls[] = {
index f87fc53..8e774d1 100644 (file)
@@ -28,8 +28,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 05c68aa..734bfcd 100644 (file)
@@ -24,8 +24,6 @@
  *
  */
 
-#include <asm/mach-types.h>
-
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
index 4bcce8a..e0305a1 100644 (file)
@@ -184,9 +184,6 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (irq < 0)
                return irq;
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -EBUSY;
-
        drvdata->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
index 8f5cd00..178d1ba 100644 (file)
@@ -52,6 +52,7 @@ static struct snd_soc_dai_link mop500_dai_links[] = {
 
 static struct snd_soc_card mop500_card = {
        .name = "MOP500-card",
+       .owner = THIS_MODULE,
        .probe = NULL,
        .dai_link = mop500_dai_links,
        .num_links = ARRAY_SIZE(mop500_dai_links),
index 9e6e3ff..23452ee 100644 (file)
@@ -110,19 +110,37 @@ static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
 static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
                u8 reg, u8 value)
 {
-       u8 buffer[13]; /* 13: maximum length of message */
+       u8 *buffer;
+       int ret;
+
+       /* 13: maximum length of message */
+       buffer = kmalloc(13, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
 
        usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
-       return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+       ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+
+       kfree(buffer);
+       return ret;
 }
 
 static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
                u8 reg, u8 vl, u8 vh)
 {
-       u8 buffer[13]; /* 13: maximum length of message */
+       u8 *buffer;
+       int ret;
+
+       /* 13: maximum length of message */
+       buffer = kmalloc(13, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
 
        usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
-       return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+       ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);
+
+       kfree(buffer);
+       return ret;
 }
 
 int usb6fire_comm_init(struct sfire_chip *chip)
@@ -135,6 +153,12 @@ int usb6fire_comm_init(struct sfire_chip *chip)
        if (!rt)
                return -ENOMEM;
 
+       rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);
+       if (!rt->receiver_buffer) {
+               kfree(rt);
+               return -ENOMEM;
+       }
+
        urb = &rt->receiver;
        rt->serial = 1;
        rt->chip = chip;
@@ -153,6 +177,7 @@ int usb6fire_comm_init(struct sfire_chip *chip)
        urb->interval = 1;
        ret = usb_submit_urb(urb, GFP_KERNEL);
        if (ret < 0) {
+               kfree(rt->receiver_buffer);
                kfree(rt);
                snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
                return ret;
@@ -171,6 +196,9 @@ void usb6fire_comm_abort(struct sfire_chip *chip)
 
 void usb6fire_comm_destroy(struct sfire_chip *chip)
 {
-       kfree(chip->comm);
+       struct comm_runtime *rt = chip->comm;
+
+       kfree(rt->receiver_buffer);
+       kfree(rt);
        chip->comm = NULL;
 }
index 6a0840b..780d5ed 100644 (file)
@@ -24,7 +24,7 @@ struct comm_runtime {
        struct sfire_chip *chip;
 
        struct urb receiver;
-       u8 receiver_buffer[COMM_RECEIVER_BUFSIZE];
+       u8 *receiver_buffer;
 
        u8 serial; /* urb serial */
 
index 2672242..f3dd726 100644 (file)
 #include "chip.h"
 #include "comm.h"
 
+enum {
+       MIDI_BUFSIZE = 64
+};
+
 static void usb6fire_midi_out_handler(struct urb *urb)
 {
        struct midi_runtime *rt = urb->context;
@@ -156,6 +160,12 @@ int usb6fire_midi_init(struct sfire_chip *chip)
        if (!rt)
                return -ENOMEM;
 
+       rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL);
+       if (!rt->out_buffer) {
+               kfree(rt);
+               return -ENOMEM;
+       }
+
        rt->chip = chip;
        rt->in_received = usb6fire_midi_in_received;
        rt->out_buffer[0] = 0x80; /* 'send midi' command */
@@ -169,6 +179,7 @@ int usb6fire_midi_init(struct sfire_chip *chip)
 
        ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance);
        if (ret < 0) {
+               kfree(rt->out_buffer);
                kfree(rt);
                snd_printk(KERN_ERR PREFIX "unable to create midi.\n");
                return ret;
@@ -197,6 +208,9 @@ void usb6fire_midi_abort(struct sfire_chip *chip)
 
 void usb6fire_midi_destroy(struct sfire_chip *chip)
 {
-       kfree(chip->midi);
+       struct midi_runtime *rt = chip->midi;
+
+       kfree(rt->out_buffer);
+       kfree(rt);
        chip->midi = NULL;
 }
index c321006..84851b9 100644 (file)
 
 #include "common.h"
 
-enum {
-       MIDI_BUFSIZE = 64
-};
-
 struct midi_runtime {
        struct sfire_chip *chip;
        struct snd_rawmidi *instance;
@@ -32,7 +28,7 @@ struct midi_runtime {
        struct snd_rawmidi_substream *out;
        struct urb out_urb;
        u8 out_serial; /* serial number of out packet */
-       u8 out_buffer[MIDI_BUFSIZE];
+       u8 *out_buffer;
        int buffer_offset;
 
        void (*in_received)(struct midi_runtime *rt, u8 *data, int length);
index 3d2551c..b5eb97f 100644 (file)
@@ -582,6 +582,33 @@ static void usb6fire_pcm_init_urb(struct pcm_urb *urb,
        urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
 }
 
+static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt)
+{
+       int i;
+
+       for (i = 0; i < PCM_N_URBS; i++) {
+               rt->out_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB
+                               * PCM_MAX_PACKET_SIZE, GFP_KERNEL);
+               if (!rt->out_urbs[i].buffer)
+                       return -ENOMEM;
+               rt->in_urbs[i].buffer = kzalloc(PCM_N_PACKETS_PER_URB
+                               * PCM_MAX_PACKET_SIZE, GFP_KERNEL);
+               if (!rt->in_urbs[i].buffer)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt)
+{
+       int i;
+
+       for (i = 0; i < PCM_N_URBS; i++) {
+               kfree(rt->out_urbs[i].buffer);
+               kfree(rt->in_urbs[i].buffer);
+       }
+}
+
 int usb6fire_pcm_init(struct sfire_chip *chip)
 {
        int i;
@@ -593,6 +620,13 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
        if (!rt)
                return -ENOMEM;
 
+       ret = usb6fire_pcm_buffers_init(rt);
+       if (ret) {
+               usb6fire_pcm_buffers_destroy(rt);
+               kfree(rt);
+               return ret;
+       }
+
        rt->chip = chip;
        rt->stream_state = STREAM_DISABLED;
        rt->rate = ARRAY_SIZE(rates);
@@ -614,6 +648,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
 
        ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);
        if (ret < 0) {
+               usb6fire_pcm_buffers_destroy(rt);
                kfree(rt);
                snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
                return ret;
@@ -625,6 +660,7 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
 
        if (ret) {
+               usb6fire_pcm_buffers_destroy(rt);
                kfree(rt);
                snd_printk(KERN_ERR PREFIX
                                "error preallocating pcm buffers.\n");
@@ -669,6 +705,9 @@ void usb6fire_pcm_abort(struct sfire_chip *chip)
 
 void usb6fire_pcm_destroy(struct sfire_chip *chip)
 {
-       kfree(chip->pcm);
+       struct pcm_runtime *rt = chip->pcm;
+
+       usb6fire_pcm_buffers_destroy(rt);
+       kfree(rt);
        chip->pcm = NULL;
 }
index 9b01133..f5779d6 100644 (file)
@@ -32,7 +32,7 @@ struct pcm_urb {
        struct urb instance;
        struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB];
        /* END DO NOT SEPARATE */
-       u8 buffer[PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE];
+       u8 *buffer;
 
        struct pcm_urb *peer;
 };
index 7a444b5..659950e 100644 (file)
@@ -591,17 +591,16 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep,
        ep->stride = frame_bits >> 3;
        ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
 
-       /* calculate max. frequency */
-       if (ep->maxpacksize) {
+       /* assume max. frequency is 25% higher than nominal */
+       ep->freqmax = ep->freqn + (ep->freqn >> 2);
+       maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
+                               >> (16 - ep->datainterval);
+       /* but wMaxPacketSize might reduce this */
+       if (ep->maxpacksize && ep->maxpacksize < maxsize) {
                /* whatever fits into a max. size packet */
                maxsize = ep->maxpacksize;
                ep->freqmax = (maxsize / (frame_bits >> 3))
                                << (16 - ep->datainterval);
-       } else {
-               /* no max. packet size: just take 25% higher than nominal */
-               ep->freqmax = ep->freqn + (ep->freqn >> 2);
-               maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3))
-                               >> (16 - ep->datainterval);
        }
 
        if (ep->fill_max)
index d543808..95558ef 100644 (file)
@@ -888,6 +888,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
        case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
        case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
        case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */
+       case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */
        case USB_ID(0x046d, 0x0991):
        /* Most audio usb devices lie about volume resolution.
         * Most Logitech webcams have res = 384.
index 1bc45e7..0df9ede 100644 (file)
@@ -319,19 +319,19 @@ static int create_auto_midi_quirk(struct snd_usb_audio *chip,
        if (altsd->bNumEndpoints < 1)
                return -ENODEV;
        epd = get_endpoint(alts, 0);
-       if (!usb_endpoint_xfer_bulk(epd) ||
+       if (!usb_endpoint_xfer_bulk(epd) &&
            !usb_endpoint_xfer_int(epd))
                return -ENODEV;
 
        switch (USB_ID_VENDOR(chip->usb_id)) {
        case 0x0499: /* Yamaha */
                err = create_yamaha_midi_quirk(chip, iface, driver, alts);
-               if (err < 0 && err != -ENODEV)
+               if (err != -ENODEV)
                        return err;
                break;
        case 0x0582: /* Roland */
                err = create_roland_midi_quirk(chip, iface, driver, alts);
-               if (err < 0 && err != -ENODEV)
+               if (err != -ENODEV)
                        return err;
                break;
        }