]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'asoc/topic/uda134x' into asoc-next
authorMark Brown <broonie@linaro.org>
Thu, 22 Aug 2013 13:28:55 +0000 (14:28 +0100)
committerMark Brown <broonie@linaro.org>
Thu, 22 Aug 2013 13:28:55 +0000 (14:28 +0100)
886 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/wm0010.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/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 3b8b9b33be380b75f9a4d19a4680723f3febfce7..7e9932e55475cef2891a790e391011b77b9ff666 100644 (file)
@@ -29,6 +29,7 @@ modules.builtin
 *.bz2
 *.lzma
 *.xz
+*.lz4
 *.lzo
 *.patch
 *.gcno
index cbfdf5486639a144c414cc46334144fccee8a1e5..fe397f90a34f50153f5936cfa13635ed7bc85b7b 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 6a8b7158697f9ae58b33e82d2f7becd772a6c4aa..9c92bb879b6dc7b1468e247ae0dbb026ad519f2f 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 a1ee681942ccc01aedbd335cc3e2aaa69b036489..6113f9275f42074d044199145b37d20feddf279e 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 38e51ad2e07e6b5665d6b35850734e5073d62bc0..a45ae08c8ed1d3fef886c34c2c07a501a0719520 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 d5a308629c5765093cf4111d8e42186cbe6b06d3..30b0581bb1ce63cbea673888e9fec22a5df72aa5 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 8608f747dcfe1869ae5061007a2fd583000ef545..ffd886d110bdcbc6aa79d2372149ae14867b2449 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";
+};
similarity index 87%
rename from Documentation/devicetree/bindings/powerpc/fsl/ssi.txt
rename to Documentation/devicetree/bindings/sound/fsl,ssi.txt
index 5ff76c9c57d27212d88723b85442e431cfa1aed4..4303b6ab6208e0856f81bc2fbc0ab8c4e81f519c 100644 (file)
@@ -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 215aa9817213e9ea8e469a94f19fcc251aa87352..f88a00e54c6351cca3972943482d14b620ba3671 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 05ffecb571037cb562778cb243a84555384345d1..8b8903ef0800069afdad90f10e5964f3bd2e20c9 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 d130818700b228a200e4c81c35e7406f6e792e3a..dc6224994d69d97f31614a308d71ba6cf2c9784c 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 3bf722deb722265422283b4b897c37ffc74d31ae..4b44dfb6ca0dcb08e5ad4468df6aeee853d3d56e 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 005bcb24d72dc1e5e359aeadf9842eda277d23e1..068a1141b06f19de0f5206e97de40f0af6793812 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 025e66b85a43905b3cb64b2e5590872d0a000b3e..7386d444ada1b4a7bcb7f29b29a5ef45b70ace48 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 f47c3f589fd03a8deb2485292116e33d17a0f7da..705a6b156c6c4fc00713443f5fa631996b259401 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 15f70048469bdde098a857c6f2566d94ce320d2a..236690e99b87fbc81c0cb5b1823981cf1e87ff4d 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 f102cbc426943370dad18b96f311827a86e39dad..94ec32c194bb1fc8f3dd4b6bbe10069008e4d673 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 1c15043aaee4c89bf2c76aca10633557c1327bd3..d569f2a424d511218f679258bbb246cae2438b25 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 a26b10e52aea18cf39b61095cc563cd940ff1dac..8c54609da16b86599730c005e15f5861a3f9922a 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 95a8e55feceb1830aa85061336e4e93423e22363..a5a55f4547c6e79fa17a0051dc5cce1daaec2a50 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 8d2ae24b9f4a815e253340c75c633be0a18fae9d..1feb169274fe613cc5f0360c797668bf84497c4b 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 8943c028d4bbe3ae2aea2875aae5c2d7e3dd2bda..df57611652e50b73322a6eaf7005598684208d4a 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 37c0f4e978d48c8e7928e0a9931b77b6fd4b6be5..43594d5116efce810798b763da8f3e7ea6891c93 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 e401a766c0bdaf633f9dd14977eb231d2b2656e9..583f4a00ec3210bf6cb3cf58dac4ae7ac8a2807c 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 c0ac0f5e5e5c0900c5e0e081390e0af900005738..6fd2ceae305a6a5cf6c5d2e766e4c91848b147f7 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 ef57277fc38fa4b79262dd056a896fe6c92c77cb..376090f07231919eb1348a5b58ede1ea7f0853cd 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 db2060c465404d81faab3cd8d2c8427588c1354f..9c1167b0459b6b3e4afd9f2a7e60f1f2f8584e1a 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 08b72678abff0cc4dbd9058fb95bf26c4b779b01..65d7b601651c390f78272602c79d6fb3b172ce4f 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 7321403cab8a2eaf6811bc93c8ee78b181afbe08..f5b9898d9c6e60330417abc3cfad494d27474d75 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 2fcb3f2ca160411f12575672e0cdd68319605865..5592be6f2f7a7ad58cf9eb3cf0cd17cd38e207f8 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 8c25dc4e98514d85db8ce77f4d9e7fa8f828262d..9672e978d50df67d94c3dd86d23f3bcdd187c54d 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 38050b1c4800b90b190a415b7d173e9948e20b97..56211f2084ef871841215a0c4adfec6f778689d3 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 e3d55547e75592a9eb98fa1704ee8df9e872c2c5..6f18da09668b5f324ad8c32e6fd6058e5b837e2a 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 b5792b7fd8d3149c94c87f5650410b3ece3a2bd2..9b32f76bb0ddaa6d6e485d79cc9f2bdfeb24d776 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 6363f3d1d505292c57a26fbd3585b3f147738771..4355f0ec44d62e9b5d7c40132f28f0ff6710f387 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 06e7d509eaac218864cc9d089ce9e6f4177c22f9..413f3876341cd6fd2e7bc4b1c6a71873cadaa887 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 6462a721ebd4cc52105fec3e8f6970614ca1d82e..a252c0bfacf50e5adb09d339e42ed0bedfd1ac08 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 f8b8965666e9b14842786742f48ccdef49000802..b07c09e5a0ac86c6ddd5f7bc9ba25425c784e147 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 214d4158089afce9c04102604fe07c5257c454e5..2b8114fcba09a3c5b9d6aceefbc6e456a8c9050a 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 46e7cfb3e7219d2ac4db9013d5dc673c155167ed..0baf7f0d939484264b089c772112657cb9f15c75 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 fdbb9e369745c4b09d776a4568caa52702b7e9a7..f467e9b3f8d5d5b35c1d6fce386c718eb1b21e8f 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 50af92bac7373eb7fbc01c8f38c4d7dfd6ccb05d..4371f45c578401c7f233e565dbb5fd36d9d59d52 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 47bcb2d254af8e4fdb3bacee96131d88a0e4f37e..18d76fd5a2afb2bf27b91980f29c77094e6638c0 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 a39cfc2a1f905f7a4e09d9db8810dcd4ce8ac995..9cbe70c8b0ef7b8d16a806602608fba205966d31 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
  */
@@ -1081,6 +1101,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
  *-----------------------------------------------------------------------------
@@ -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 e00621f1403f7c44765103591cbefd6e3315702f..52b26432c9a9941e8281a4483dd7aed148a99995 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 2adda11f712fe02fa2fdaa63e944e17199bd3748..fc7920288a3d90a3f9c3ca38be03ff845f84515a 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 b361de143756d4a3412f4512d794eebc173e25e8..14235ba64a90736ecebad575f5d88ea4568e8eaf 100644 (file)
@@ -87,6 +87,7 @@ ENTRY(stext)
 ENDPROC(stext)
 
 #ifdef CONFIG_SMP
+       .text
 ENTRY(secondary_startup)
        /*
         * Common entry point for secondary CPUs.
index 9cf6063020ae99ce68afb617bf88905ec5f6212f..2c7cc1e03473aee9463e86d7dbedfc999f6e51f7 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 4910232c48330d4dc857d6bf32754bfd781008b5..797b1a6a4906da0f8ca3f942186ac0e033250ce6 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 4fb074c446bf901df288b3878341a169dacb843b..d7c82df692436df0248fa1a00502cf74b7fca23c 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[];
@@ -38,6 +39,14 @@ int machine_kexec_prepare(struct kimage *image)
        __be32 header;
        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 d9f5cd4e533fef948f68510e3a6fb3b4996b750b..e186ee1e63f6c85261f96844a594080e719c2e07 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 d3ca4f6915af746d5f13c4427cb42bacbd61b694..94f6b05f9e24e8cd1d79063f03a9b2dd16791c67 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 63af9a7ae5124f82484feb8b33a88114b915753d..afc2489ee13bc098523f92549baa4a69728c1ced 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 1c16c35c271af5a3cb4de53736344a9ed286d7d9..ab330422527203417472a21727b1062c8a38e70f 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 c2b4f8f0be9a31b20126cc76ba69b14f2d22b585..2dc19349eb19fc23feafa1a2b93db17eb5e6394a 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 a98b62dca2faf9bbce7fbcb786d4c325513f7231..c2edfff573c2c9e2e68193cf729a98f460ac1a2d 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 cab094c234ee85d646b9534d2044010c10c727ee..ab517fcce21b8308dc957bc5b6809039c2e5f1fe 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 fa25e4e425f6070c0a6055de98271f865dde3823..7bcee5c9b6049c2723df9e3e9fc9b0b088b5fe0b 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 00247c7713135a1f403eeaa9a0ea196895efaea3..304f069ebf5001dd31a791a6a7377fb437c97cd7 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 e9238b5567eeba8e1ac2df9402d53859b27b7879..1663de090984535dfac2f6dcae4647644b563704 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 614e41e7881b538b77bc4c5ab0b5430de7175bea..905efc8cac797d5d30ae0db0ff0e28eba7fa140d 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 8e82f41a89235e4fbef3f7f2b7e0b7c26c84dbfc..4410d7766f93be5995c620c1c36cf2be8ce23877 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 393aeefaebb05ebe28f903083501de2461b2eaf3..043e5705f2a60ce3c6ffecf70fad28be592ec214 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 5cc92874be7e6f22d81767c0f75e141376ab83d6..f99f68e1e85bd3748c5965a0bd27c47d0f6d538e 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 7341eff63f56df8f58d5b72d8db9a71feb86112d..7f4db12b1459881ddc2fcbf66d404bab28d89792 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 aab33fd814c0329e178cbfe265fdf9ff5ffb766c..e1482a9b3bc22f7cd7de82ac9f66474e1efbccc8 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 d05fc7b54567f0dbb6597a1d641ce130caf7ee9b..56cebb05509e15c0054f342e158a21214b7a6603 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 28bbd56346a93ab67fc377eb1ea066a8be8280f7..eb2f3b93b51c9a4d7ce32eed8f23d63cb3083d33 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 f7a3df2fb579613a761f9a484dbb0254cadcda9c..0c3a427da5445a5d2f990e05f2f3fcec50634143 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 d04b5e60fdbec74c6accf27c349a79f07a8c01fb..9c3b504477d7b341b4492ec350bb3404769fa219 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 f37ae96b70a1a9e2c67085b2a0a466992358a4e6..3c70f5c1860fc2b96401fe6ad1256c1a975539e0 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 3a674de6cb632d21dade993c9e0cb3ca2c7babd8..a388f8c1bcb3cb2c69a199613ee3710eeb333c7b 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 e115f67421078cd7390cc2cc92a6b0ae43c4b36c..c5be60d85e4b95fa1339f64492d28097ac3763dc 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 d5554646916c34a962a9e1790653fc22d8beefd0..3354a85c90f7091c776ab248df641d9dddb3990d 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 d73e21d3ea8ad9cf036483262a2010334ec0e062..8d6bd5c5efb9cd092fe4dd857057a1e6f59b9420 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 78ebc7559f5309e025c3796ff90017293570bc6e..4c09bae86edf02cb4f9408821fea25cd84d9dddb 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 6cacdc8dd654dd11ecbfb45f7576f1ead0a1062e..db5c2cab8fda4251bb636aa5567afafe5cfdb406 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 b55b1015724b56931c57ad7b2920d760b80529e8..4a0544492f10e4cd63d490f61d3cff3e54adbd19 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 4f56617a2392d58e52f96582a3631c4c49a4f5f2..53cdbd39ec8e23c1facab667f56fa9441aa870c6 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 f64afb9f1bd595a9fb1b9c0cd8bb442c9fda0337..bdd3be4be77aa50c93dcc20c8afdaa3af3c0cf5f 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 c36ac69488c8fa60b17d91d085d1f8efcae42cb6..01a719e18bb047c655694c336d5a42e1388d1062 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 5c6d5a3050eac65f1f2f89465d8398c971f866e4..73398bcf9bd8ea8d7293803828cb837306742fb7 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 8e11e96eab5ef6dbb07f79c3dd747252401d5a52..c83f27b6bdda0eac2c566d40b4d99e5428be650b 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 f71c37edca263a88038199514995cf92d8b79d9e..c9770ba5c7df5c3b68c909c32db7fa2fb7be39f1 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 46b3beb4b773c85cd381f72301b8f2e9dfdc7a97..717031a762c27966aabc7786f6d2a900034b0b08 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 f9143196345271698a674b360769cf05c8173de4..7de083d19b7ee0b5cf9f63a14f953b7311a1564e 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 33a97929d055ca9d1131ffce9c517b3a4597bb38..77d442ab28c8625860c1787df12ac9dd74d7f004 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 7913695b2fcbe5605830b9e1da6441188a591b8b..efbd2929aeb75c563b5ccbf4b267be596ce921e2 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 f8e91336542392236c878276ad8abcef4d786166..f64980dd20c3f3851174c25c63152578910f255d 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 a5a9e02e60a05c94e9b9a4c6c35a6cf78eecf429..0f4e9e41f130623baae948b022dbd01468869331 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 37b9b422caadf9c89196aa63781d9cdb2a05830d..b025acfde5c1dc4fff39be616007fd7391f11276 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 ef3a9de01954511a352fa5b24285136789425e21..bc5efc7c3f3f8ead3608780ba5e2f5b9e212e20c 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 2291a7d69d49a27c541a4746492d7be01ba17727..fa277aecfb78f1256dae50e30b0d873afbb72949 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 444ea8a09e9f3386434e89d502c41d1f4107302e..ef881cfbbca90987bf0e93c9271537317c15886c 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 d22a4ecffff422f542e96f81527b45a4e3f9c6c2..4fab52294d9874b5b07558682ec5160a470c1092 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 c3abed332301fe70572e8de451eda0d70f51eadd..e12764c2a9d08163e7d066f276f4b8b87e16e208 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 ba611927749b9f81def164126a2b2b1d00bf42c5..2b8b118398c458573652c5b9e058a302ddcaf766 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 1dc086087a723fd9c90c427d05f4eb3c8ca919f6..fa44f3ec530214f5014664cda4611b1a5a027251 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 5b2f2e68e57f08210be7d4a98370cb3895111adf..9488fa5f886603fdef1ac258182bf82d61004faf 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 b7a23064841f2171173dbaca04027381000e02d4..88e292b7719e99963f74692f0ffbd36e60e79c83 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 f739aedcb509ada01eb9f579b98bc5c1752e03de..bd79c4f9bff403eeb2e320343b83d81d70855852 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 c0bb4d59076a79bdc85cf59caf57fd2b2c87303c..126da74d4c5559faf40962b80bddef9a39721757 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 e4b1140cdae060dca0de8bfdd6a5985b1429de58..3a2b6e9f25cfb95ab0f2f5ee1eeccf069bde8f22 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 d22dc0d6f28922e0f6beefbc2cabad28da0d70e1..2b7e837dc2e2c275e698e101eb1fd961bc44d7ee 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 9f64c23878082c7e5622733486652381af0315b4..0238af1ba50383689138a929c268a1a592a1464d 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 99dbab1c59ac2ef78d4f4566da9c47b3e3a6350f..d60bf98fa5cf399430d5beaaed9e3cd9c7188e67 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 9afdad6c2ffb81db7f8ffb68dd003bd3b5cd4980..eaf4dc1c729440688a169bd11fe81b250b8c776f 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 2e65aa54bd101b7dc5600297858929687e90d549..c035673209f732f0850aaa4dc98d2d49eee3b74c 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 3295ef4a185d06327c84b806276f31ac4c7cdaab..f0b6722fc706169b37a407a1fad6b063984722e8 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 940188d1942caeb993ffc58aa7148fea50c91683..07349b00268750581d1badb79b2c2487732831b8 100644 (file)
  * this. */
 #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 33eca1b04926ad09184d703e9c2fcb55cd127069..6c6a271a6140e639183334a70a470860f906d7bf 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 a134ff4da12ee1e4ad39a78e514328f578573ca3..bb9f3b64de55b2583f9fc930b6a1fa368237fd49 100644 (file)
@@ -42,8 +42,6 @@
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
-#include "sys32.h"
-
 #undef DEBUG
 
 #ifdef DEBUG
index 3bf72cd2c8fcbf0f8feebe915d4dc2aca3f44f28..dbd9d3c991e86ca61e16fff87047bd6956b21420 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 c86fcb92358e27bc93bd723375d04c9e1c247071..0e8cfd09da2f65dd95197c2e8ca86d5ae6dfbf24 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 4b20f76172e2efb2f2d3d1e1c5a8c8bdbc6656dc..0085dc4642c5bb107b61bcbe80c9935449d64b8d 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 bea8587c3af509b1540fe6138614f73dcbf97c9c..1d4b9763895df77dafcfd61bb4eea7bed6a18621 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 2dd7bfc459bed73eba9f1be705acf44d7fb36c3d..8b24926447544c2fed3eb44de6464071a20f15dc 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 47a35b08b9635ce375e266a6c12fd3b02869302b..e378cccfca55bb20db094f12a2009ad3ba7bf1a4 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 a6840e4e24f7abe68d918d6dc576bcab18d0183d..99222e27f1739c543faa916d3d766be5f99e5fbd 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 ffbaabebcdca71eb1130ccaf12cfcf36c82501c4..48cfc858abd6dfa70c4c95172a5e4003fa62c53d 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 49a13e0ef2344fb83c6dd89ed4ab8fd179d34c01..294c2cedcf7a622b478b748a1c5c3ddb8f537674 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 5182c8622b54eea94ba18cfad7236872ae056865..48be855ef37b294cf034db138842cf56526ff4ea 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 c7e8afc2ead0cde5d75b68244990092a0dea5bc3..8207459efe5619e4b9e2d824221104d111507e67 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 ea9414c8088d01289411eded7d67315c9a2e8661..55593ee2d5aacfee6ef9e86c5adfd4057c5cab10 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 ab15b8d057ad361f609b06277eb0a993574098cd..2bd0b885b0fe901328d9ae44f7703cca0a159676 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 4e00d223b2e30924dba5e82370d5bae09e7b56dc..902ca3c6b4b6496d8e606623187c9f1da1500f2a 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 2e51cde616d2de1fc93cdb75547debab72cf66c2..c69440cef7af43413987f3cd4b2c936cd0e8f788 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 c517dbe705fdd5fd5944ae693c04aaaf52510e85..8083be20fe5ec2c6608ab979f988cc0d31eb6862 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 51be8fb2480313610b5971b6ef70a89f58f794a2..0554d1f6d70dae8eeb964806ccd869b9e2a5e89f 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 bf33c22e38a40848221762497ca1a7b704a27f9f..e435bc089ea3ccccb98d0acbc490071e9d75bb18 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 2efa9dde741a1aad3ed206481e9c272a94eb7cdf..7629cd3eb91ad69e9460204a7f7c2e8d081a1084 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 19498a567a81f25c67c7f1b3f010182fcb680e2b..c6e13d9a9e15b0be5f2b75a1151c7eea4b93b8e5 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 08397217e8ace2d6ce3abc1a09a4fcc14977413f..5850798826cde0be9570368cb7968a9ea279b1e1 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 24a45f91c65f69480119055e6d8820f52f07582b..eeae308cf98253888a1af8792dd150e4410b08ef 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 7466374d2787cca701ecef97da54b723dee09026..2ee4a707f0df85c37dba15c6ab5f4e7f84e553fc 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 9f8671a44551481b25a8c5b1404dd152c9f6df02..6a5f2b1f32ca167d3ec6b39b0dfd69067d6b37d2 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 22f75b504f7f9bb8ef91ef80e8a1433995e6c6dc..8a4cae78f03c91e510f307d25e8f5467211725c3 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 3ad8f61c99852c3fe7183a15aacfcd96ace3535a..866ecbe670e499632ef59d514dd04a280f46b890 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 c4c6a1cf221bde749673b59dccb6e3c6113a0b4c..57cbaff1f39778b98b1de870e34f99cc14043687 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 4d8604e311f3aaf6b1799bd78760bcc52a5befab..7d46767587337c3874bd61c43e01a0a72f965303 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 b75d7d686684975278e1881a9aaf74590a6949ed..6d6d92b4ea113fbc692cf4dda3cac36d803128fc 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 a6fc037671b11d0a2e96226256f9e36cd8e4d65d..500aa1029bcb2d2ed12ae352a91cec068322615b 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 497451ec5e267f3be025b9b719cf4f2278262d97..aeed8a61fa0d4f1b4862a98cab44e29beda63699 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 ba694d2ba51e36a2933ad722db76b00e09735f37..34c1c9a90be288d9080d93373660d020bedf2a90 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 0da3e6eb6be6cec4d55780b838492e52d093f08d..4cdc54e63ebcb366786347de18437f327ee8e2b2 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 ce36ea80e4f9157f5c754b51c1ff9c700106d689..ad446b0c55b6076d5aaf7f095f1ddc91b5e38bf4 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 ffeb17ce7f313d914a38de3ee21dad5867991b9d..930783d2c99beb305b2346a220f414d98a4ba406 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 c8def8bc90209578a5a6d5cfaf8f9f258c4ec7fb..5fc237581caf3a6f3b40c41246f4d39d28f8ee55 100644 (file)
@@ -87,6 +87,8 @@ config STACKTRACE_SUPPORT
 
 source "init/Kconfig"
 
+source "kernel/Kconfig.freezer"
+
 config MMU
        def_bool y
 
index 2051821724c6db6d33ac89b333bc5214b61b68ea..0cf4097b71e8d02051a3976d86b63226ab2b8924 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 e61d43d9f689c0ef61bc0e1e5e43b3826b66a760..362192ed12fef1789d2c23d21c654f19632006a0 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 4febacd1a8a1a3dee2c24e3b3447081e7ca94ebb..29b0301c18aab26f2a613d397da9856a8d1eec3b 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 d606463aa6d63bfdab5641e6bd7e6b68545e32d9..b7388a425f0994ba87a30a27fe8ba57d7e3e5457 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 f2b489cf1602349092d26d6ea68109cca3589c4d..3bf2dd0cf61fec9615253fe3b70d3c3764a35e93 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 4cc9f2b7cdc35a854f185b2ab91d49a9fcd1be4f..81bb91b49a88fa22b2c07fae620e76d674692419 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 7dc305a46058a230ad5eef2df9f5e54b66ac0017..1c00631164c29c1d2d676f8c384141931483363b 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 c98ac63aae487580727cac5d9f194ef04d9913cb..f4843e031131d224280c4c0d845def9a094f3082 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 33692eaabab58619c7481cbfc7c6f01be929e5e9..e3ddd7db723f666a98c1baefce55282632fd711b 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 e2703520d1208539d21447d6f570a767b7e51f48..c370e1c4468ba1a82d98eaef03d7100c05922eeb 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 fbc9210b45bcbe62fd2c1b765a46701c2eb21212..a45d8d4ace1016b2ea7903569c6cacb43884df20 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 cad791dbde9540840185c3509d04c74f8859598b..1fb6c72717bd9e721a19e634852dc06d0af6f485 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 94ab6b90dd3fabdaf2856a5d7fc2abfd4ed2af88..63bdb29b25497edfb0a97ec7cfb9aa5b746d200a 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 202d24f0f7e70546a2020212b97fb450e41cc9c5..5d576ab344030832617450ac2330d63f135596a4 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 47ebb1dbfbcb2413ddaf9d4cc86b7d8558eb3c72..7a0adb7ee43397aa9a9fcbf733c3b1c9308f2b71 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 dbded5aedb818d511a46967ccb1d26d77233110f..48f8375e4c6b07edfbcefd819a8210f6e0839dfe 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 62c29a5bfe26aeb67bf63fb545294b79765e445f..f63778cb2363981ad8f98d0e068e4d789c2136b0 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 643b8b5eee86b3eee7edb2cf99dfa31ad7f9318d..8244f5ec2f4c7520284ff2388c328a17c10e3440 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 d21167bfc86564b480f21c9b690fe263a0609a73..dc34a5b8bceeea2d9dfac6ccccee6bb7ed64c0e2 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 fd6c51cc3acb52fb49adf5c7885f6ecd318fa2e3..5a74a9c1e42c85a6999f9a4ef780728f8bdc5bcb 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 082b4dd252a82ab17f7fe7249913e1f7030d35fd..d405fbad406ac75cc9bb41c8734a457d60e14222 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 f68095756fb7465bc034ca5335f9345a806dd97d..408f6b2a5fa8ee5c6578cd9e555a8386e112e370 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 aa1227a7e3f23e349ed5050680d4fef8c135cfc8..04a13784dd20a4a7e42b15b98eedcff90cb67299 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 0ec434d2586da29d65003aed0b7d9c7dd244944e..e1284b8dc6eef9b800f997ecbf6bc5e60214eacc 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 4ec7c04b3f8279dff1f2e39f356106e92815e39f..26386f0b89a8f4583c397ca9da154a9c499c6d2f 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 e69102696533e7224b74a1237f64c478eeb2ab18..3455f833e473c8a053898c4e96e540612dd1d10e 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 99cb944a002dc4dfd5f2010a6f2de9d75c09ebc8..4d45dba7fb8f9f1c6e97d8fa4192ff4e63d6230d 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 11f467c00d0ac836a1c6509bffd31e49b891a844..a12b923bbaca91f14b923e0b271b00ebc1be8d28 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 de4cf4daa2f4cefa3a270ccaf8e4e8fb22af1015..8e16f0af6358872606fbe102bddc9ade2c6ab470 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 bf5d2477cb77c296dac3a63b3aea2e8a2ec5ce0a..15f2e7025b78e20abcdafc61dee7718800ff1824 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 1b456fe9b87a12f98e8a6d691487c252271cb3e6..fc45567ad3acef079db496c9a2f495e19e5b5bba 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 1bdb882c845bd48a96597bb8f65c2cbe2a3c03c2..4e5739773c33a25f6bf5503e9261b18a11a473d2 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 5c205b60a82a21aa7bd780f17133c9d6a00bcf5c..089d3e30e2216e44b20067fdaf9ded66708d0bb2 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 a4ad7339588d7122fee7f4f86271c74629980709..f0a5e2b0eb8a9584f1e1d55ffac92bfd2800fbba 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 0ceb2eff5a7e7044adfcf37a5522b131017d6088..f97cb3d8c5a232a60f319e04da5c0616624925d4 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 7b839a8db2a7ae6f0bc647e249c326a70623b62a..e59afaa9da23af0dfd826751e817ab6b41e94a0b 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 6663ec3b30565ac7efb6a7b5842e301ad2160bba..d5f12b4b11b8af09c608bd6f74f01601e0a91f2d 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 93eb5cbcc1f639bf1ec52479a169a49deecd72f5..c087347d66884f03a4f1b2a94bf4fcbaceeda7a0 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 bb838b98507747a02ade005d99074a4c2a1d95a8..9536852c504a559865bc023a2d75ebed22a0ffd9 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 fe343a06b7da3278ba68c9c15c261ea14afde685..bc580b67a65298a8bf65e699d562dfd6f237b697 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 ce3dc3e9688c86ea30e3be7757094b78749a6ec9..0bbdea5059f3b693a8929a4d6ee82db24c90b768 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 593827b3fdd4fd8556724da998934a7c191b8d49..fa645d8250091943ba8d47aa42852b99b74ca1ce 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 b67f45f5c2712a8c16be7afad085bd745649a708..5039fbc88254eabd570e9da6d50d51ed0cff8240 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 7ef316fdc4d964cc8d1f87bd7be0cb9995223612..ac1b43a0428531273c4fdaefd56a0b83f1545ce2 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 9e1db6490b9a3bb497b7911d94c42d9fc6190be7..afb701ec90cabd50ceb03b1298beba38e97717b4 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 eb760a218da4292f7c208ddc145deffb833df7ab..232fa8fce26a5d0ffddf5fdc3ee01ed3c63eed7f 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 e3ceaacde45c111990c534c887a47cda3a5ec61e..73b73969d361c10a42968ee5eaaa142f72894ef6 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 c57244ef428b1db249e82917a55870bc17774f27..dfeb3a3a8f20949098b5dc0e703ffe1ea944f245 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 98d670825a1a115a43fd5c6d49bd494ce839c94b..6e8887fe6c1b44fb83d09df82d10d50483924de5 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 0047012045c27cff7cfa8dbd386ca239d850e4be..69fd8f1ac8df192729c89f4dd981a5bb5b7611db 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 8bcce7866d368e12df7c86edb17ff235ba58f4a7..f92da0a32f0d30d02fe8afeb09f5272a16b8a060 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 95c75edef01a0440303a36f2692ce963fe6a135e..30ef41bcd7b8fa5ed0554adf8bc3332cf19a1320 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-#include <linux/module.h>
 
 
 #include "exynos_drm_drv.h"
index 61b094f689a72c56666decd1b6b4361d12be6291..6e047bd53e2f00dd8f0d494194be7cda4f02ceda 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 3e106beca5b6c132f1dea2407652deac449fcc59..1c263dac3c1c8ddcbee197d13143a428ac4b01a2 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 42a5a5466075a7d2d25b8ab30fa6155383a0befa..eddea4941483228a68530513e4f04aa94cb0f84e 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 472e3b25e7f2cc6f5e05c1db002e5117bfca8685..90b8a1a5344cef0528b3bad82ab4b0b993002415 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 aaa550d622f03c047ca2ecf7c19fec8722f52747..8d3bc01d6834f7b8fca2c2320e67b151a4df3d0c 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 b1ef8e7ff9c91fff7ecc11fc21cf25f7f20fbb3b..d2b6ab4def93ab7421d30fea9c9f86880a0b0e10 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 427640aa51481777976391fa51d856f7bbc7512f..49669aa24c4510168d003b4677b3da5548ef2b94 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 41cc74d83e4ec885bab33adf02182402938d27d3..c57c56519adda3d2240d57aa1fe6d90900efe680 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 62ef5971ac3c6c40f2d269251a1d098386e024c4..2f5c6942c968bd7a1f9ed4e16adcb8f4c7a99d35 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 ef04255076c7f30bd293aa97f95fdaa7d6c5fdcd..6e320ae9afedc758b4a61282e030c099adf152db 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 42ffb71c63bca254fd5ac753b1d6dcd84c284371..c9a137caea41108a18b8c179a39110c3d64e6a5b 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 66c63808fa35e5834a876e59dd49735fdb6f82ac..f4669802a0fb35a6a1ae99b6f7c7cdaeb21d9df5 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 d2ee3343c9439cbcf306ce443b9fbe57e53e534a..1929bffc1c77f645a920c9b4037f0b5eb646a145 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 f2326fc60ac93d4a2f1c760333945fb33bbe0524..6f514297c4837882a64f9480b9f944c3913f7b0c 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 5fb305840db89ecd80b5cd42b69ff9c35dd9432b..e38b457866535925acaf054b549f5bb07ce180f7 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 67e2c1f1c9a8309b809c35f32395e26e67236992..5950888ae1d00bd7cf70ebb18d5595ee0ee8446e 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 51a2a60f5bfc2b08fc2151f35e27c67477c2bf9c..b0e4a0bd1313c0dafac84df1b6af56e7ccced950 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 251784aa22259a44baec12749d21c9b1e2163f35..503a414cbdad2ef83db8f10c9eaadd80522c515d 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 3acb2b044c7b2d626c4efb9741c39a89f92a5ebc..d70e4a92773bfda96079b1406ffffa9a2f65a0e7 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 373dbcc523b23a1cc5c16e3aa5d1c8ca271e8e98..a19e7d79b847b2447d7254c1c77aeac623fb44cc 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 dc57e24fc1df955253d1f447d8404c4d43d29fc6..717639386ced2c3e881dbf102ba39e24a5737293 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 ab1e918469a822f76bc09f4c09eb215f97a56990..526b75242899fb6e97e0abc3bd48cd228affe151 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 49ecbb859b251974eefd6c5767d1b31ae2b624dc..c19004301309ea0c039fe8336d7fffdb906b24e7 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 f7c581ad1991b880b3abe6590f0250b68261a9d2..dd6196072e9c7f58062c7e500ea8c57ba19cb580 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 0639bc59d0a513725195ea64be7af30ed2dadbf0..5f6ede7c48928a799e3a2084371e5bb86a2388d4 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 f2e87b105666f344c46e0c96c9870a062dd76340..fcf57fa309bfd54bbcbba86bdfc53ef5fcc481f6 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 6c974dd83e8bcbe43daf5ac6e44f6b9690180e91..db9d6ddde52c31cc7395de7cca70ceaf0671d015 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 af5aa7ee8ad954a465f4b6ec3183e7091731afdb..903baff77fddcc20e8e2f18a6df808d66c0d316d 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 9c3634acbb9d8e3c404a8e251470636552d4fc6d..cf97c4de4a6b2911722da3b1799487f217cfb560 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 bf489dcf46e2796fed5e0e1b1f109ae2dcfe015b..c4c1d415e7feb871329c275e894558f44c60aff8 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 0cb322a5e72cdaab4f29dc7f2e6306963c110ba0..f25fc5fc7dd11a773e6743a3df5d3ae5e1235532 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 67fcb6c852ac008539548f8271889998b64043d5..ef3133e7575c8eaf937520cf750bd51effcd7505 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 4e7ee5f4155c96bce6b1091fdf432a6d46140eab..af20fba3a1a47ae441f8c587d79670d445ed6374 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 4c1bc061fae2cab668f5d5f2bd24f1ab5febbc62..8f6d63d7edd314c4f6a6ff7e492c3b37be88930e 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 8e47a9bae8c301e1ac205a0140ef650ed9d7aa5f..22aa9963ea6fd46b36f28b457fa7cfeecac0372b 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 f9701e567db89793136c52e02bf11d59baba4ce4..0ee363840035b1e67bd3e6c6b8bb63afbf4d8ea3 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 fb441a790f3dc5a56fa6c65bf4384f2d098906fb..15da7ef344a4e55fa11d604c21269e97ab361386 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 0bfd55e088201d79e3499b8c98585895f2c736c8..9953e1fbc46d74e53adf50eab2eb05e602287f54 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 6dacec4e20901bd1f12e428a387434a8db8a91a8..8928bd109c1647b684293cb49ed91198419eb33c 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 9bcdd174780f2a8ec618cf255ad2c37690a2237f..7e5d0b570a30531a8752e6b4f29bb732528bb7fe 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 038dcac7670cf540950d4ce64a26830da6325e0d..d5b49e33315e299aa4b2a2085d0fdd3d1c8a99bc 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 b0d3fb341417342cd06b3454fe17527cbb581e48..b0e280058b9b09ea22eb75f5c13ab6395e1698ba 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 a7baf67aef6cae99eacdd958b1aa00e2fd925841..0d582ac1dc31841b0844df7cfe4b186bd7b6da0e 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 56bd4f3be4febfe75522deb222a0218c7792b248..ccb4f8b548524b46900f6d88444179c9f6a3069f 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 559cf24d51af8dbe7304caa443e7e15118c750ca..f0f5f748938ad6c30292d2b109bef4c3a2f8fc29 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 10f712e37003030e81a7770e94ca696c4c8f2c08..e66e7207735036e2ffab5e18f37854384595bf80 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 f48240bb8c5640badff804e97dce556e31f86bd9..f264df5470f7fd6bd0ba0cabf3d31e7396829c2b 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 8e3fe815edab3224492e126bf7e47d5193be448f..7c780839a7f43858395bdb4ec309bc6a9b1e37fd 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 2f08219c39b617d67ab07f83e7aaff7072bd51b7..274b8e1b889fd0fbbe1dde2a71492e975f00a711 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 902479fa737ff62c1b2917b4d0bfce0c34176d74..3d61d5aac18ff4e01d3f89934807d9abb261dcdc 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 e3f3e8841789a5c7a0234f73fb089dc0cf204687..4ccd61f60eb6cd23849940c3c25ed0e9eec675fd 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 82335e38ec4f268e05f9d4bc1cbd875eae8523a5..63398ae1dbf51fb682fe7e51623de255c58ae0c7 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 7ddb0efe2408cadc2de230109689a159cdbf0fbd..ddb8f8e04eb549f4fd264b2f704cdd407bcc65e0 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 6a51d943ccf44d8301758a4b99e3aba35e4c2668..b990b1a2bd50af523e93a7715050a534ba84d987 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 f374c467aacaf57c9a46c7c655250ef91a44516c..c557850cd3450a5b0f363f24315d3051cb96cf3c 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 414fd145d20eee458ebf8e0a5c1dfb1940ae2589..f1c15754e73ca6d933d6ea1e0877b839cecab4b6 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 363018c60412c1d7374ee60a176abe2f5c49dce7..bdd888b4db2bbc7bf4f6f2cc718512fa999e223f 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 30ea14e8854c465add9148cb4099142a3295fbd0..bcc68ec204adeb7582a536cd3125ab28d00bce6d 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 2d347925f77d6d116c95c01cc3045c148ac446b1..094c67a29d0deb7789d6b0d38a1d0a718515b81b 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 96b1b2a62a8a2a0d5950574788d0936aba6ec730..9244effc6b59e2e69c6882b0d4dc35dd2517379c 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 d325280e2f9ffcc94b2260e802f6533c242f6546..daa8d2df8ec502ca72a5b9897be75ae59a9a797c 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 73aaa2e4c31272b6f4a28341f05e700e0c7bf42c..88699e3cd868047555ce426ecb2251c7f9f3850e 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 5207591a598c05944a348be2252c4a346e0e5cfa..cd33084c78602146d42efca60e358d08f00da219 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 fd28a5e0ca3b84b8407791421b25f8b17bf7815a..4a4000340ce1ed8cf6be1f81ee8e0f21d8ba5f5a 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 ecbc74923d063d6494aaa4648f08d91a6c44e686..87fbe2924cfac3852ee8b202b8aaeb8500de0080 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 a7451632ceb46bad87845c444fc1897973e94ef9..6f1feb2c2e97b5defb0628d92bfc98a719449685 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 0f34bca9f5e577c1f1e04d43908bc9a7a91f4bce..6099f50b28aaa80f74e9ac69373f73efe4e852f1 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 328fb0353c171a1b879af1040185afa1be109ea4..a41b5f3fc5069596d7c9a0c0c164dcefefc7e621 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 ccec916bc3eb58f9b6376ff109965cd1529f5d7c..af8f65fb1c050192e7a21234dd6dc855ca55c923 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 df8ff5aea5b5b2b4aea8191f66b18f45408fd6ea..e2e9a0dade9665ec0d89598754c5734d2480c09c 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 0ad208a69c298aef50bb4b0ff6744b60753e9a08..3ceac3e91dde4cd30339bc3c61feb4ad570a03c7 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 ea8a4146620de5c6ad551644facb278654ab1c1c..0dd9bb8731301e755dc29ef2851371f70deb819d 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 f1c279fabe646f80d3962f3354475087f9c37bf8..7c0f9535fb7d443bf2c4b1647b3494816292020a 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 dc3fd1e8af07f0f8f4c6da455c38e315074a8e1e..4c837e66516b894f88f689d93c9a84c501fa6b47 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 e87f2201b220673030ca18a3957642b623d065a7..d2283837d45168070707eba5ac11aab4c2fe9c5e 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 232040447e8a23803cc73e64c203734d36492c2e..a4975e1654a639960b214114648593564fcb0b27 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 4d599cedbb0b1ccceab997a4945be0d8d6e89fde..f2a3f48107e71e1d53b0abb61757f1f0ba38bb59 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 8000fff4d4444168ac4091a78112593d11b212dd..3f831de9a4d8a901607afc26c81827cc5c1e3bd5 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 16ac54c9819f24c113ad02f594a47608a004a828..045f8cdbd303deba81e60c5f1f52330b536b9617 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 418004c93feb772c641dde6b102620fc2be45900..90200245c5ebfd5fe71000d17b78e52bfa8d4734 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 8f67fe2e91e623a87878a8790ff9f2e28db0c0b8..5b53ca5a22840c14e31ddb0d7e978dfac5c179b7 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 a877a8ed79077dbd085d28d1fd834b3f1e01d019..f4c587c68f648055546deafce7f8708798f4d109 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 dcfbab177faa63eee063a428ac7848e5763f8125..f36630e4b6be182c735b7aa81d357b4207266c82 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 21e8b09d4bf87687a9c569ac87dae42108b7cd8a..016e7429adf66b9ffb945cb4fed168e358c57742 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 32162d355370f95b56970b19da33783052c24c36..9b5322d8cd5accca85737745ba06973ca7212efe 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 2cfa76f5d99eac87bf788eb41bb2a7c3815ec700..196b1d13cbcbc09548e92a4be6c9a18cdc6aae36 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 b6e049a3c7a853b92d5c9d126c61a2d850f290cb..c6f71a88c55ca9649b6098cc81d64de229857055 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 74685936c9482be96c09a09e5af6f314bdc2b741..f81abe16cf093d6c74ad31dd179f03f7dc90b997 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 0b9a79b2f48aaded2397762ce500b032f25f77e1..82fc86a90c1a436d94ab8500334b62f4cce47dbc 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 efdc873e58d122d322d53a3876f88a46f4ddb04f..a9857022f71d424a02baa2aaf84652781db58fa7 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 df4ada880e4215519b33cc81ab3cdb5d2c8e6dce..bd9405df1bd67abf3a8051d0cefabe3a7ad0c362 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 553d87e5ceab41b9d2d081c6fc55dbe4b17db1ed..fd6289d60cde2c8a25450f6cb6d24c18923f0e81 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 5296385153d5d17ce0a3c3d6f6bf0d8513bb10f4..4f6dd42c9adb06755eebbc520ba57124f77a5e35 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 2549967b2f8589bb46007b8282520250392287b7..59e56f4c8ce34ded878308537b5de1a57595acf1 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 4851cc2e4a4d3227b59df97c8020298b41796c77..c4ff9739a7ae8cb099b21637dc23723e5e170d1b 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 cb694055ba7d103ad75bfd73b2f41a0b0cb1e315..6e5070774dc2ca480fe3970c75bb79c0a893e47b 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 8864436464bf2d9e6aaf3199fb58a5d9e10294ab..7c5b86006ee627c43a52003fb816c7fceb10b6f4 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 bf43f874685e2e5ba6acf97e891b8a09a7676432..91650173941ad5629a56cae9bacff0a4072002f1 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 a746ba272f04b5e3b77a4e45f65809a398c73585..a956053608f9f6a9fdb94c877917150e6a25680e 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 07f257d44a1e00a67b84a58685c5a2e490ce5ca8..e48cb339c0c6e5b71eb4ec24bef6d4f8238ea665 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 6aa7b3266c80904d8d2f2106869085a8b19d5248..ac6177d3befca611242f26906a9168f11ad3c23c 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 25723d8ee20130b19ad95b885a99e5c1ba019517..925ab8ec9329b5bbfadb6e94faa12de0b7f91ceb 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 cbd388eea68271c8ab7eaa2581ffb9145a4be429..8becd3d838b5eab2a520be8835c9fba3f3703482 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 53ad213e865ba350176ac8b59d83bac0dc58ca09..d8d95d4cd45a9ef00ffa7c9c919188bc66d39465 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 f1b121ee5525bfa974010663da5807e9b4d038e5..55d79cb53a79637bb09297d49f1cf1d1ed533147 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 b2bf324631dc89f7902f9d7322c549331daa1c78..0f0556526ba90bff7f764c4005d6f6e850220dd7 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 786a87483298ea400733b987da389144e297824b..a36a760ada28af64272a5132a60648c543963bed 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 dedbd76c033ede4d695e3c7498f99ff263ca860b..ce9b387b5a1962949582354f7b0dcfecb621a08d 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 ee350bde1818cc38c4a20a0db70a466bf158ee2e..f2d1ff10054b28ccaa9b7baddfa408821c7409af 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 0c94df47e0e8ee46d273488413be3d56d9c29ef6..f9122f2d6b657d0e674c7b036635b60e97586609 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 5018e52ae2ad8fac5a194b0f137b66d5b8aaf0b4..32767f6aa33f473a126259e4877fa608ed51b3bf 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 e5da07858a2f0d5dca0747e1b7fe58992b799d5e..955d6cfd9cb7c48179b587a7bf5239a572b7e9e8 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 95861efb505187f07bd1a176640e4f44af14a5de..44104fb27947fba144575a33a0be3cf1343fe39d 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 98366abd02bda520cf1876189cced5926175288f..d63d1327b051e4a80c76027b03e723c332d0a317 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 d964f302ac94163f32780c4d1ed6667d4fb4165f..0da2214ef1b9e895903612809b21ed070cf32fa3 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 687ec4a8bb48de001cfa9d39ef233ee7c69a5d96..9c89dc8fe1057dc1c410728bd252f135f9a80879 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 6e6e0a117ee2fe16061ae8e0b77a51aaacd3336b..8ec5d74ad44d75e4fb9d7c871b0ddd95654c74d1 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 5228d88c5a024e8e20be18e4f9fec69de7865e42..1b3b9e886412ddd689a0abbee536e6ba0d4ad50c 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 2b0a0ea4f8e7eab210535c703b2a3d4987546d1d..ae236009f1a8c5dc857326751ce28ea68b2a4681 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 d3ad5ea711d316e1455cbe7d8eab61ecad8cb3d4..77ea0db0bbfc3e326d8137a26623de8fba1c4945 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 6a0c1b66ce54116b88a8aaf33bcf0518a7ef7ca3..c1d72c03cb5932f83e9f8a397a55227fee981d9f 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 7be725cdfea8d3b3c7f414a500dd83b965f24d99..a6494e5daffe9d4b26171b570251b9a97d78991d 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 ac780770863dfb3a338f3dfe4550f5bd87d2e66e..7a77f37a7cbcbd6b7b5b87dd78e9e50b677e778c 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 bad8f14b194107b7d77ac5f89f194998c4c0f514..be4b1fb3d0d2c38b62bcabdb2dc80a8332634cba 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 712779fb12b7d80416db0a4349257f046ae0d11d..b017818bccae1a06bc0c85e88d29733f9a1365e6 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 c896079728e1312893fdf03f0b0e111f2a6676cc..ef94a591f9e550ed31d654c2cc1fa2ba7bc1bef9 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 727874f575cedc80e65d52d4918007151feb3c09..a28cd801a236e5a674de67009a5b872ed29e9e71 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 5eac871399d8ecedf4fcffff06ed4372753df77f..fa37b7a612133c739263346a5d6f372af0fd9dda 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 8873d6802c80dd8c5359f7c1e19834236f2c9ae6..6fc6dabc78d542a3fbe9c6b470913e6744e5d196 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 e85af922dcdcc237ea5e7c7f227088fe77e90802..36be3208786a69ac5ae40ddd5111f79116db3f95 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 35fb60e2320c2a896e8b241c2c9dbbe575a2dd02..5e0aa569306aab2f6c8185cd1574cdd4abeb4aab 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 205753a04cfcb22e8904dbe2e3e203d82df32552..5472cbd34028d9038539824c4167a0c3010a3a01 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 c02cbcfd0fb83a4b10d198888c88f67fc4670cc9..443cc4d7b024c02d2cc77861868e1c1b17ee2524 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 72a5222447f558b3e4a118ccaac70de358af8c64..f012658b6a927baf1fca6a2d39d806346c61a1a6 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 748f10a155c42e4923850f718df8b2142eeff01b..3e6670c4a7cd215998bf2302f2573acb8540ffb7 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 12242de2b0e3ec7950a01f966def239e4b1ce74f..b47739b0b5f6dfb34139ad74e02ac10db1d4fbbd 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 f0bf46339b2805d745c89eca8a413a5cd002efb8..3a2408d448203623754d0aa87e35c16e809da43f 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 71d4a39372009847b7d03b11c58e8ccf695e61b3..68f5d9c77c7b13b9038cf5bc4e920e09ac3c33a9 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 cb22341a14a8c03fd7627c0d2d2a31f9f68ce126..a588ffde970041def37cae92b215011d88b6eea6 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 b00cf5665eabee735b1e218e6aeda7111380fe69..221645e9f182052fc7641155e1db37ef5044cb2f 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 0913c623a67efd238e7d989d50cb2b1c7238cefa..9d4bb7f839041967eaed1ef6fd0fd51b40f6ec6d 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 2548d1403d75a7668434d53db5013f3969dd8f78..272f56a2e14b10b14ff97714c063b3f62ba4c7f8 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 f41dfab1e9a35d3fc4b3d72c820b2d5db84f59e0..345d987aede491b8d5daf0e1e268b0ed8a9f2a51 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 0581a484ceb519dc8e6b11b6d08b06e4461bab46..d09389b33474d7c9ae730385e6fa3478fd77c832 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 700a46324d09230b8d8ba6e6fc820bc0e56b9526..7aac23ab31d1bb26b9ac3c069580a114b5dff299 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 5b5d2edf125d9f93920b13d83fbfa802c96140fc..4d5f59b2d153f55579bd3c3f2a64f3c96b9ca66e 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 2c22504f57aac090b5cfecf9ec819f876b2ef6ed..4a71b28effcb041421d1332cf3dc810a3b9fe8ae 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 d28336fc65abe5752f4a295ae54708edf9d3b0ae..974d62607e138c792fb44224cf5a06b5f0794130 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 d3f8797efcc3d7a6012ea56ddb4feda210727f22..6946d354f44f76c1e6e990a092cc043a21cf7e09 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 4528f8ec333bb50d01c116958cb1a86c7392ef7c..bc05d016c85943834b687e0b2221495c88ea7190 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 ab8a6744d402f43e794007db16ee218916051675..79e54efe07b921cc2d7e1986c7d45e16ee9e7ecb 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 62380ce8990555a2b120fd768cae0f2192508a8e..5d40045b3ceaa47038593dfffc52c986f18cef21 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 ee0c1d307966d842d824c3ed64449690946b7d76..eb49cd65378cdcf5feec210a2812d3d09ef8f0cb 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 10ed82b3baca0970f65ce9797a18fc35cf76b1e3..660c3f5b22377a956c0caed68e59e6761d282239 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 e6acb9fa5767687d8565596adc11328f55e2a12b..d2e591955bdde3fd03b40dac1c9c22e3d013c23d 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 4106a743ca74c16e0dcf02b1d9b9bc10b76e79a9..b5eb4195fc9927a8b88493c7b1f783926928dc8c 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 b74a60ab9ac79913111a4f79d4a5a8ca1c723862..2a469b27a5061641a07a8502ecf63736953070a2 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 eb4aea3fe793a8372292023877eecae57c5b5acd..f5d7ad75e47903ce2156864c6dabd1444ae27baf 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 c9d942a5c335d022a3eb8bd59ebe5345d655d557..1ef9d8a555aa33100d2103fd0d8e3a48f403a735 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 f2ccb36e868590917a4cea295eb93dc20cb9ea8c..0a9bb9d30c3f0b78e28f9233e1775392d260aff4 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 05a1674e204f772f84eb3d4ff70633942ba7c256..22a7a43362113c60d251a0daa85b536bcebd3648 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 07b176bcf929706a7f3c3974e49becd346a2dc27..1a222bce4bd7bb4e84ce8a845a81c27440b4f863 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 1d6dc41f755dba00edfbc83d07c1d898c05020cf..d01cacf8a7c279ee892b703715e84707214c186e 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 18373b6ae37d78543cf925e2d86efab1578f3019..16b43bf544b74dd3ee72599f56f429ca2dea8851 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 a98fb0ed6aef7b9be00c4ed21ecc1b79793f9459..b51db2abfe442cd95fdbcb97e17aec702ec0d2c5 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 61d3f4ebf52e5590f41b260aa7a354e2ac4b862a..7f25e49ae37f21167bebda2f8051dc4da6c6ba0c 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 db690a372260786b395186dffb38ea24e58d45ee..71af122edf2d639c0a87099d83998a0706bfd433 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 1e3c302d94fe338dec36ba934fc90a79bfb00e0d..2bc87e3a8141d259502bcfbfccc9e0a5b649800b 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 ee13f9eb740c0bf18b793b308194675e9967a317..11c51f275366a15999ad7684330bb644de76b557 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 852392269718e1892119a3c42d45c635f768a77f..2df2f4fb42a7c381fb68275bfab10052b7a71363 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 75409748c77470da8cc5bcc7390e9f4c5a94ea6a..66ebbacf066f6692ba21d2fa07538535827074b9 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 da866523cf20097d57550c7357020e937782fd37..eee1f19ef1e9397469e343133490ec6972b4bbdc 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 a5ba8dd7e6bea33d060e9d5306b9eab6bb2095da..767f7af3bd40385ae18823ab579fff1709f79d7b 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 cde58fe962543dff415d45f2be2ae06d0d7ceb91..82e8088ca9b4944e5cb13c3fb3c2b14c7af27efe 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 81b686c6a3764111e8c8e969a90d36d6ced054ea..40825d43322edb511862c90bd2587395745852e7 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 d1acfe98918a2a50689c2760ed6455cf2c239b2a..1576d58291d457612ddeadf0933904bf6f552d3a 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 9e582e14da74609361b689e5f5741d425fd14659..5205a3625e849f3f6d3d775bb7b4b8f866aebca4 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 71a183ffc77faf04f590b3d9454d1fb3c798ccaf..c3676bf1d6c45ab92d8a161d18ad5f3f0c586d18 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 c59ae43b9b35aeba9356f499a83f73ae02e96a8b..9279927326203d02f421233b9456f074cb92e5ec 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 e8308ec309704958b1754c06dbeb7b3fef9f452b..ab636767fbde098ce41bd952aa7d950b6932cb28 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 8e8975562ec3b819ff20b32de938a3b012b6671b..80099016d21f4a04cb22b5e3b98ccd84608e658a 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 f0d9f7f6c83d70fbd677175b43ebe70f306795eb..29b1f24c2d0f92c86a55dade5e0e61a943004608 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 277b37ae71267a194d6ebcc541b93cc786ef9078..7fa71f73cfe89c5bfb5f2fca8e1e83c4d7124045 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 7365674366f4426fb79b74cadb4be87bbd07b7a1..010b252be584237c7f6b4e71f5d375332176f586 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 5862c373d7148851816a5b16bfeb9c1acaebb191..e824d4d4a18d7e1d385d9d95f8fea195766a3ae8 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 b9b2bb51e60590ab7dfb91d4e284a6a0c6c259a7..f2ed62e373408d3882a3e463af81b88f3a83b7b1 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 3195aad440ddf6317b1b9b34d2e2f57e773755c3..b03e22ef5462d929ea20ffad72a4a01ff067c4a4 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 3952ddf2ddb2bb596ffca3d0ff951238774bdb98..1531a4fc09601bd101fde1e20a528d7631f8baf8 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 ff8cc75c189d4d842abf8611fb8c5e7c7a63bf38..a70c7b9d9bad897345fb1e1e89d5c421e0d8a3da 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 7e5e5c2f9f87316f5319605b1d9c6814c2940dc0..83da884cf3032564df37a96be42c1601496fbc52 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 e56ed2a848886ce6c9001ef9a69a12d54c5f102b..c24a744910acd447c0b7376670e5e97b038cb09c 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 b60d14151721da3cb141b9b74ac0e3aee2d43a92..365095a0c3b3101e3c87b76036dbd82b352b9deb 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 e08683b2053183f7e7ea9df370a37bdb4b70c2e4..f19baf0dea6b9c84dac1a86d393c8ddb68aa5f53 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)
@@ -506,6 +511,27 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
        if (ret)
                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
@@ -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 d40d7db185d6cdbb22ca2a2d1fefef0794970971..420e82d379d9826690d297de690c3e84a2307f87 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 2157b0f8ced5cc7c314a246d758a869128e57c59..acdff6b67e0460e669e5c25192af245df93ac4b5 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 62fe5209093bf7637cb024b2c81dfd301cfd4649..563f559b902da8560f7cbdd06726872d7849b34b 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 81f3ea5b09a4b7f26d0f4bb7877e50dedea6cd38..ff13458efc27096343f17e5c408465d9dce1253a 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 fd848cd1583ebeb3372792911849a0eec25d9667..f600e68a410a1abe454170bd65d29b5937df41a9 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 826c15602c469a524b857c135f7b38cb4e5782a1..96cfcdd390794060ee6c72c3951984f33da5ff38 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 ef5fa890a28628666398f39624f83e1bfe6aa1f5..89459db4c53b9f1468f832f4e3d0be0200b7ec22 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 988552dece75d49ab3af4628dec68bd6a9627030..5178c4630d89310e17a5db810977fa5aad8ca525 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 caaf4bd56b3062ea4c9a11028233c1517f69296c..2cf8b964e966c5dec94b37ca9a826799d73f4dee 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 1c8a771e8e8127e666265d10447b88f884a4c5fa..12e778159ec58f5be70ab8c3e9d515beab28b48a 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 e15ab72fb03ddc1ad6eab8e54aded37de3143253..1753431de361b807890ec8bcb177760f457faa07 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 3da73d36acdf5e9a5ebe30ce75333704d98a00c0..253e0bd38e25e22ce911e6e49b4d99261afe596d 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 5ee5ed02eccd56645c94f8b4972962130f5b305b..09185c9632483b324d63953652ac6acc93a36752 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 6d51dfdd8251a515c3f6a17e94029b5c10f6672a..532ae0ac4dfb3e40bb12592db32ec94e702a4c2b 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 206c3e03807235425ee3c0ad12676cc7c187cad7..8af97abf71088589b61cbc847fdc494a616de7c7 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 9b915d3a44bee4c7d585ca79d8209415c40d7c01..3e60a31582f8b3b15f359a5325a8031de96f4427 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 6c0a91ff963c6833bb7d325cac7954c7c10b41fc..aa95c6cf3545432bf93b0743af97900a91f55ec9 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 7253de3d8c6671c78e732b001e7270731465d039..c2ffce7a907c90cf3fcc01400f50f2850d371533 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 ff02b874f8d87dfd15ff0205a6036e65c0b9ad5c..d56f023a4b90dfadabf45670b2f5c8d0ca1fa46d 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 9d558ac77b0c78b36ad6f6a31a49cf5aa4aae765..7651f5acc14bcccdc179fc09450af258f9d30e23 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 8576bc34b03289ef077db41f5700e3a2eea5bf21..0e5fe0902daf6eb180a1da431ce54477e49486cb 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 ee84844be0080c2e1bcef681f7e53a7f42f93125..733b7ce7f0e2a981f442cd9cdadd8f40a6426558 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 7d52d3d7769f0e357be0900ec0423dac70cb390c..76e2086e137e5f0356325887ecccc5c768d17f6c 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 9e3894178e7773b3d6aca8a4cca70fc518fd6a96..838a1ed3f1942b9f3d56a122c2840548b38103c9 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 c97e9d327331c8b25624327ec4d672c7289f4492..703f839af6ca0b4abefcfc754dc21eb3d13b2dac 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 884bceae38a91d2b9ce4e07cf70c5c040e844df4..298b615964e861acb23c9ccd85e7b154854e9cda 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 4d682b753f503df0f61b5e58b98e871f58c31029..88bd76ea88f7621dd92cb4ff495ee22e9dc53912 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 a3532e0778710ff5975a3c3fec4e21299e45e301..e56778cac9bfce39e56d5aa239e34f2fb1135ffb 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 e79e006eb9abc4eab4722aa483d2c6fb38a8c455..9ee04b4b68bf39569acd6dd360c62a6cb4e4b76e 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 13a633b1612e1786b9cdcb7f2eebece8b0a70dde..7bf3926aecc0d765af64f166cbeb871ea66ac127 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 bb7ebb22db01e39a66840ba4684f811e7d89e075..d85009de713d647b9e3a81024776b6bdaf312754 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 aac7a40e4a4ac9205441d9c6918a080531117571..0e0d0f7f63fdd83aa551549d38b174cdca8d034d 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 dbdc5f7e2b294fad4adfe3ae676e258c5af6abbe..01e264fb50e0ebf09a1c4b9b49e1e5e0da3bc7ff 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 569f82fc9e22bb826fbfca36ba74b891cc15b0d8..3b94cfcfa03bee1dd1a1d319f9d038a46b07b834 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 d254e237953382bb99768c7cca79b65c3b9aded8..64a7de22d9afe0edb548b3b20f96d7c288e53273 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 f4f30af2df68c682744cc125ede61da5f87eb4d1..2e8a20cac58848cdd0e2afa6201f3f82f4a88e84 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 767fee2ab340efb2d5ce647637053028c38b4aec..26019531db15a2f481dc87da6e6c76e085e1a06c 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 02faf3c4e0d51d13cd6fd7c55b2de4f09776f08f..c2e80d7ca5e26b618a19bfc5aac45e8497651082 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 17150a77898433c27e58b2a8ac9ccb81bd228ddb..451bf99582ff09948c04e6634ca2d381c0d6a45a 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 b6d1f92ed33cc17e67ff4cbe1b3c424f5f75bd0e..c18c68150e9f17c8965b80159ecb2c2ddf1b0060 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 5f09d1814d2685e86b06d9c6d697659d06cade07..42e15ee6e1bb73fceac4bd8aaf8ded5ad06ecf1e 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 0177295599e0cd976e14982b5991fef567cbe52a..1f0ca68409d43a09ae24bd98a1703d34ec2ba2cc 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 3b1ea34e1f5a8ea5812a7feecd6ad7c40cd9fe04..eaa808e6ba91c78f13748a6ab3977c9c174c20f9 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 2168258fb2c3a2cf5374a3592a302062d75bb305..74b88efde6ad408123de6a9b96ec37460195fe82 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 222d3e37fc283b95dc5932570c1dec874cec78e2..707966bd56103181d31887b53cca01c1d9bd9776 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 dcceed29d31ae415818d1fceecc6518cbc017845..81972fa47bebab17ad635a4d855d5cd691f5daad 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 bb91b4713ebdb8c7ba8849cba643d046c5bc9973..2e3ea1a70d7b90768f33f26a39f098eed7df2c12 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 cbf1d155b7b2a8c80ef782443edbf77c0e7f5595..22f280aa4f2c521b5829a6ea5e72b8c05f2265d9 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 4f5f161896a139852e46f93f30239be979838bda..f85b8e6d0346fc472fbc835b0451a706ce46aab3 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 121aeb9393e1172e75fe5972a7c4b8ab4640557f..f597e88a705d1fa8e65cf36ae98a61f84f20b9a3 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 eb2aa2e5a842f48eae096d29e279572982e215b8..d1bd8ef1f9c1d48b7e0566220149deaf0de10da4 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 aefa0261220c048322a62059ddc35f9df047e7bb..1b23e354f9fb371f5851206b58944b0221109600 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 609dbc2f7151d52a08cf2f7b62d229637491ce55..83b4ef4dfcf80c71248555c5378c082182235bcf 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 4a8a1d68002c0fa1695078c6566c616bf764fa35..558313de49111025e03c1b6b6d015a2688800498 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 a63598895077ff8c984c0ed473d5ee90afa52086..5b44cd47da5b28b30046bead355aa54eda3eec0f 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 f48712ffe261470487f7be0476ad7d89d8a808cf..c1c113ef950c86d9c4170cebaa47a91426cf74fa 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 1bf26e9f38cd3c4573331ff77d6a9caa55a0be7e..eb3aa817a662616810a4c9d9c6232c1e8f2a2e2f 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 032b96a51ce4e06a517f35070542067a002275e2..2a1ebefd8f9eb31318fc861fbc010214148db18d 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 c28ac9872030ab1487a4dd74ffb5ee54af950d67..13e25f80fc201f347784ace2f35c7003850f381a 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 f80d0330d548d36564e9332d60392c9671360263..8e3c878f38cf57e64cb24c25a992b59e184ce322 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 df6978abd7e6f756c6d81ebeef324473e7f36a87..6f8c2fd47675dc2432902f5fbf8b4cfec8a306de 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 41eb4fc33453525422b95218b6d51b34aaa617b5..9478caa2f71fb12912ddea1bfa06f37580e7c3ce 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 eb3c8c142fa988de1aaaee07d036e93554bb48a3..eeb27208c0d153de863f16ba12e62d0222e8c5d3 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 6708a3b78ad8b3d06130dabefe2c2e11e78fa106..f44e8b5e00c94b3b22ddf06b632041e0c462b060 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 2c06a8969a9f793153d6f6f0546be9d5eb1ff8a0..6f8a9ca96ae753f31b637d0f0c08c1d27a550699 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 8c3a42ea910cd1d6ef7b503bf4a753f7f521e343..7eef9b33fde66c78405509adf6ca8b461f8045c7 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 f7130114488f8b95a4ee1c8570c61417cfcdb97b..a14a870d993fe3bc1ea60001c9f1dcb6637c620a 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 7260ec66034715e7a065d0f5fe6441f49a37f6b4..b65e657c641da56a1545be79e22a13a9fdad653c 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 6dd79253205dd7ec54278ddb078f08346cdbb4f8..1b8af461b522c65a111983226ba1e704f012ac8c 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 5a979729f8ec4695a1fa4e4395b86a430184e1c9..58c17fdc85eb77ea40718e7791475d341d34d0d8 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 51da424327b0f7c1f64ac90fe482df9e063548ea..b01300164fc03cd26cbc81d62afd5a647c04d8be 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 603fb70dde8005ddfcf9743e2f3f8d0acd616bb5..3bac4693c03829c9d5ca23d280e8c9b580548e66 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 375b5a400b6fb8a63b0aaa83272299a15aef6e83..5c9f9b1d7736d0b7fade9780920d8916477c81fa 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 8257d30c40720f348de427ef4d04ea3d1835d03a..85365784040b28a2c8c92a23ff4f4d5fe758834e 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 16968c899493db24a40481e151b0da591405c1bf..d3493ca0525d4c727ed8d0fb86223fde6cb001e7 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 c5179e269df64ade2de20a384b6732a6922c9bcf..cef6002acbd49aa078568fe2fe9ea4511230e861 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 c488da5db7c7f1b0bda8e3b7559971ebfba0c442..842f4507883e1b1d10c99d343e35e450abf56db0 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 a89c15de9f45c885f3dc7fe76bad22bde184013d..9b0f12c5c2842f783501821d7c6bb4a9527f936f 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 3ba37713b1f97795c875ded477e5dfe37b2259b7..dc09ebe4aba53d078881b28e123bc072142f423c 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 8c527e5b293cbe5bf91718f5c1f68b0ffbcc4c44..796e5112ceeeb1f139bf947197e96ea2af42ee60 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 5338f362293b27a9d6050e856fd878f5c88b4684..1b60698f141ed983e2661743f2a5c79f471a02a6 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 b2a8912f6435ac504e4b09361c12dbe8b7d01bc6..a9ac3ce2d0e9de56aaab9f836b0037fe62651596 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 a8c6c43a4658565c8b21fa38a3baaf1c5bd82e36..1265b25f9f99993efd8d094716acb65563d8570f 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 830ded45fd4758a9a3d9ba6c6640653ac9b32490..2827333703d96d151b86952470c590a5d2820636 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 f3d4a69e1e4e9058c4c4cc605705f1d62d923a48..6629b29a820221eedfe774a1cd4c62163bd29bb1 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 9e02d60a364b00d271efb0b4d4eda046a25fbf08..23eae5cb69c21e16d2f71ce2c29e1b307ba3c05c 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 eabd0ee1c2bc2f298d0938515e204b42430e9852..14fe79d8634abfe2307d53e65e151f403c86bcad 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 8feecf01d55c95c9241080cf36823f197b3b2d5c..b6165e047f48083c5a254dc66a6f4bc3e6e9ddb9 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 6ed8a9df4472edc36b91b70ca3a0f463f237108d..34b20bfa4e8c3cf813194a45c4545e01c1d88eb1 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 eaf133384a8f97497098ab82cc94a67862116705..8bc5e8ccb091852dd53f262eb556fe5578a419a3 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 5bf4c39e2ad625f2e90bfbbc765fd4e13db47a2b..ed504607d8ecc9e7e492b9c0f2d88ce02ae1d32b 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 583d98bd065ed83ca979a2786b59ae4342380c47..fe443fece85111d69b833f9cac4e2bbb85b6ea80 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 a005fe2c072ad0751254adba0fa4e04db10cc996..8e686a427ce2e8e5e824419321f1f8f2dfe19acb 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 6d1b93c8aafb8a4d7b832cab8585ebf1ac1ced42..021694c081814828272ff03a8b9e1f64732a46cc 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 d58cce77fc6c581625c3dd0449c83b6836bf4894..af1931a5960d9d602688fe8bb89242d752b71c5f 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 005b0375d18cfc6131a4480a9e67e0cbe44ed46a..defbc426989787e405e69f6e360fa82b3dc26556 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 2c6791493637250423ac2c9bc21d9ca3f752ed11..ff60d8978ae264d95709d83342e1c309113521f0 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 45e57cc38200448da67b1ce2c896efff555f0e73..fc6f4f3a1a9d6c4c2f8b0c7afa1eb20d8029febf 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 4bdd547dbf6fb3d10a2b2b962b710b722d0b9685..85ea98d139fc5643b0606b67959bb1f320037d80 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 1fdc370410576e1a3f5a36a133245468160ae4b4..52ca861ed35e4fe3fbf78ec387ff401fb0e8fb94 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 f7e584d047e202e0185f4936a71ef189e1a2781a..b29a012bed33a24b6ba45b17f95c70303e3e3014 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 fa68813396b5acb7e7a2e5a65e1202d740688cbb..d67c550c49806254da76ca6f7dd32d29144c3c16 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 1e57f36ea1b2f84ac43c486cf6aa9cff4b2280a0..7e36ae34e9479b2614d61c919d393291593ef28f 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 b83c3f5646bde6e21e80806541a00987198a5ce1..562044f700e56bf27997bf7ef7490bddf6bc1c91 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 ab877846939499c18cb454c83ed26c43dc60040c..69d2c826a23badc552bb686b518beaea297b473c 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 79358e341fd2ea63cff42e6d608c58f65b5f9804..08dd37bb23aac8ea04fe979743f8c963990a80f7 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 6457690731a220b58fa2be3f55bd6bf430f27b8b..60943978aec35bb06360adb7e060802d5775bee1 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 301b191270b9bcf09edbea5ad47100267f32e859..4f2300d020c7e517a6fa89be5d955fa4b12753da 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 4888cb3fdef76037b7af5f9db898bdcb82ce48c2..c7c83ff0f752ce6a86d6e42a420e34ed996ae8ca 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 911649a47dd5ae5b000bfabb2b73b0c71a95ec52..812149119fa3c36291508af6fc33a7646c84155f 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 9c73def87642fc8f36624b7fa525504541a59a04..fd774c7cb4831be8817799ed6cab355a368fa19f 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 b577e45425b0ac921ae1f0904b6ef84b7ace8fb3..0ab26fbf33808c565ae9ef4449d6836e4cb01fae 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 72a3600aedbdffe48b5f2756bb0ad863f120a7b8..17ac112ab1012bd88ff32d145f27a29f025efdde 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 a61873808f7659aafefa103f96f1f51f564ece04..72ba4705d4fa40e12edd1097f0815381688df7e6 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 6f4cc567c382b7289e2b35a7038756a581b4cd95..319c9d26279a94fa7039dc2f8730747fe2404697 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 f03598c6ffd3a48282193a13ff30ab6e412e471b..8bf5999875ee454c67899dad4c49ed2ec9445ffc 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 ba33c67d6e48a8b035cc9113ce05b916c535350c..c2ca04e67a4fce6a40316550215e2b2fbe107d01 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 9491ac0590f746b9abe56e484e7646022a0bd1c3..c0427e2f66481a13f3018b4630901688fdd6646e 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 bca26f34edf4ca55dadc3ac9c5447d916dcbe4fa..b59373b625e9bcacaf3a63e409b21b1ef6212dfa 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 6599222536eb20e9deb22884bdc305efcf2cf1ae..65343c3741ff86876418deb9d18e3f72f5872898 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 a3f868ae3fd48f043f91a059ede274b20b431c3b..34423978b17083d73b038d360d72b47dc08c6693 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 01bfe76627516d836241b249bdeac7b0a02b0f97..41e491b8e5d7e40164e0e51d90534c9d8660a94e 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 9760ecb9b60f6ae39471ea09fd8f286ca0285da7..acd3947163497b802544a632aa02512c37b88d9d 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 8b61d103a8a7a15b0c5e8eab070e92f940a64b88..89a612e392ebb28e9a00bfa1c2c8562d8a3fb7c6 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 af6e806044d7cee5d8047a56de6693388fc8d34f..941246f2b43d266827666dee7fec5051c2289586 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 cf11799297c42d50dc33aca126e6da11f033ce4b..108a774095f7ef6a53fc04366aec3caa3bfea717 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 71fdc0dfa0d28d9e293cbb58729d63395af7cc99..f6db66d8f647069a4cffde4e609bc7f23e3a2da0 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 0d4c410e45893c2ae00064c5a8ae3384e00848b4..419572f33b72dafaf04a770fb53e29e250e5f42b 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 280acef6f0dc45e29365b197a8242f7d26bb22f7..43f42290e5df096fe7eced0266759b45264a61a1 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 0c0f3ea90de59f9c9e0c21aebd46e8b07b2f45f9..c2a4701d7286478cca66cda986565a7b3105504c 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 79736a28d84f911dd66acca86c844912284ad9fa..2abf97b2a592b7dafaad4e2cfc0f9a6f7442f475 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 eb760d8acd500c96bd45195ce2a2c79fb0942ed5..30544ce8e9f78cc66cc0eb61387f84b21cef4309 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 41000f223ca42bb855a57f1cc27f08a28ecccba9..3261d71319eeb27d3a569aeccf4f3f6e27a95496 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 96f9ac237e86dbc301339c07b882bbff508f9143..0a992737dcaf8e76d0b57b18dcb21b57d5ed6479 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 f1fc172175b6c47454cfbb4f10bfd239102e92a9..452068b45749a7545002543f0b0b450b52612dec 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 998b17eda09d807b2b1d2ccc0b94cdc2a45974a1..a70d604593b61c0ffbce761a92b1207148f3b346 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 7754608c83a47b1b44425c8f9c5e13a2adc65675..6422bbcdb52506b1631ce495ddf4524a4ae71c92 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 d53e29895082306747de0998c730159b73d08528..7931f76acc2beede0298747df1d505b30cd225b4 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 dbf61f6174f0f473d3d9a19311a09170f8dab9f3..107d026f5d6e0cbebc068fce65f201f167c425c5 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 33532f79b4f714923ec951fa5fb75d1758fbfda3..a958444a75fc310627d56de6a37e28a15a99273a 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 f8a23c3078f87d5eda59c30d55cea7ecc94b9273..e2e202a07b317cff5c84d8b51e3b66efafd689ea 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 56e6b68c8d2fcb36fae154ebe6bb687f9e74760d..94383a70c1a3d738413e06389cc6937909554823 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 2f47ade1b5678f325faea455656a9578839b8638..0807ddf97b058fb04b1eedfd82c34b76e4253335 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 13821c339a4151912b88f2e4de04cbf99653a612..5672d7ea1fa066175b33c8f4c19457fcdc0614ed 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 f5e1168c76473d3c1180cbcac654eac67ee2373f..d639049a613dfdb264650f8ee938836e6ed28e10 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 deb0ae58b99bb3724bee4376b0a376b563c29cff..66a0e5384edd6090ae3793082c8a4f56fb6ea74d 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 3b0e820375ab90c2e0f9a05ffaa94f7a36f76abd..5d7782e42b8f22f81df12652348ff9a21aebc7e4 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 4372658c73ae5eddd3dd6570d4dfac8c5d8825c8..120d57a1c3a5dcb452a75d4fd21a6d338b128a0d 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 3869c525b052171fff8bbe3000d61d5999bae7ee..369cf2cd51448b690cb812e6310cbd450ab83386 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 3bef14c6586bc9d7d875e6579352a62e53e13c6a..482ad2d84a32dae333c74cccb2d1394b247d5ae8 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 8d73fe29796a9bc1ce8687c9e18e6963cc278c62..db1791bb997ae495d65637e506b6f13ab4945b6d 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 8de8d8f22384b9abcd83ce0f76898c7afdf7ded9..68029b30c3dc89e2d2620fd41101b2ab05069344 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 f22e4419839b372b9cf6b6535b27cacf721ba9fc..8888381fc150b8f3f852077407ee8187a54cb7aa 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 b62d4af6c667c27bbbd3620fde9813c9d6b529b8..45e921401b067b68c9912f82af1c19a1a8c6d048 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 0741a1e919a542c53e50003560d01ed06322e658..9a4156845e9348cb4fe4b803a64041d1db5de377 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 88272591a8951d09fb18d8b7967ed3e885ca8855..9efc04dd255aa59799c69e4bba791551825023e8 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 467cc6307b621adf71fd94e0dc6f1d3aae409741..49444203328ad8546b4299fb702d0155897bc0d0 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 75981d0b57dccd4b6a3b5e9833557973f33d9404..580a5320cc96afd21807cddaaa40bdff47694d5d 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/list.h>
 #include <linux/rbtree.h>
+#include <linux/err.h>
 
 struct module;
 struct device;
index 50d04b92cedaf900532f72d1acef35d04d7ecb69..e9995eb5985cd50b28aaae49f528487acf3f018c 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 5afefa01a13c892e1fe9eb7ce6fc3f047e5880ba..3b71a4e8364200d85afe94b120e09e74edf35d32 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 7d537ced949aa83b33b4c20e32c991d2123ca5a5..75f34949d9ab998adf5941c0321ea45005cc7d62 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 6d870353674ac274a3f27e0f454749f7e5c18485..1821445708d62d81bb1176ecb20f8480fa4799fa 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 c5fd30d2a415a48964eb1fb2aaaac0db255656e1..8d4fa82bfb913d0021d93c49e71dab940804fdf7 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 4147d700a293623b63615b987c797f14d380a7a1..84662ecc7b51468233175959ddd5c04bd0efac0d 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 9180f4b85e6deedd827fa071add91940c3ac48e5..62bd8b72873c0bed1702d41a2a8982831d01564b 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 b6b215f13b453091ff2be0fae11b37a5a51c0c84..14105c26a83618da5d91ae09331fb83ba8f8ad6b 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 76be077340ea5c7c4d96f1299bea48b9aa40a98d..7dc17e2456de141ef3241a73af02fbec9b9c1ee5 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 7343a27fe81966372c3ee8dc72241f2822891543..47ada23345a195973c3942681566244d50c7f34d 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 a14339c2985ff0f24e259861fa39dcf335f601b5..8a358a2c97e6a82cb98dd6b9586133828306f961 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 2a601e7da1bfc8b97490075531975dcdfebc8370..48ec25a7fcb60a09a2c323c70221a31853a82261 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 781b3cf86a2f534ff71e03037b7984a0e84a8c8e..a354db5b7662f1bce43af7edc97471cdef3421bb 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 949d77528f2f9cd87839029b424bded13cb52136..6fea32340ae8a5c697a18b7909c9b44d86cddeaf 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 0af851c3b038186357b8576ec4025bb5193ee1fd..b64b7bce4b94302a8edb923bc54bc1e4b2c8b997 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 0e353f1658bb46e638b287ee2bbfdbd33b37a584..5f286b726bb691b3f62e3b6800870ea940a3d65f 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 6eab63363e59fe82dc3fc6119633e5583b663dd1..e5ae0c50fa9c5c481f991de92efd5e862d5bca67 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 95a5a2c6925ab0745b563f7f04663721465460e7..31d5cfbb51ec9f52b57c0c339b9b5e92804701cb 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 2fd3d251d9a54e4896453508fcd3bcd86ebfbf26..56e818e4a1cbf90270d21c3a67e44ff3a0f32d73 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 3e479f4e15f5e3469ef0c7f72f6e88174f36ceba..c728d28ae9a581143bbcabd2da3b179274034090 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 04598f1efd771f9f05e6f051edf975bd510700ce..047d657c331ce77b6c54f51ca38f18cfdc24a1d1 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 6eabee7ec15a90197ff3024f827d47cfaad91095..8e2ad52078b613ec853c2a6637f8a118674e8814 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 d500369534972c2dede7208ba69d7815e389f299..1db453e4b550ebc84b10ca27f32dd4fdc2ecffd7 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 caed0f324d5ffc6fd88a59dda72f51636af0707a..8137dd8d2adffd1c91d4caf76dfa08b47501408a 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 dbd71b0c7d8c93edbc80ae50ad7223db3665f00a..09d62b9228ffa061de1b5cb8ee80e20ef470db5c 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 af0a674cc677f570bf5d5e04683957605d5e9ea1..a1356d3b54df4bd7f68fa26e3436fd7ff2dbcb71 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 470839d1a30ed72f68789df711bfa78bdc60e5f4..35ef1185e359457323d5513b578185ad16435bc2 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 789ec4683db3b73f83e455891bdb319124215f97..781845a013ab23c8f99f2c2153c70c9fd679c45d 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 e5657788feddfefaaed5f7ce3ce2ac26ca80a9c1..010a0083c0ae4cfa222e2d51f2e951893bac28c4 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 403d2bb8a96865ec2b62da44e48f77e3a7ae3e0c..e23bb19e2a3e23c9d3ad3c68e0f49acb214d3e51 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 8b2afc1c9df0c698eccd86664d25c33ed647fea7..b462fa197517b6176701fa860cdb966bc44a69ba 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 ff05f4bd86eb6acf10ff49307e448ddb8b00916a..a52ee7bb830d3fa9db3cf898a34c8212664ac8b7 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 fc0df84864495f8c44261961cb6909e66d24a21e..06ec8869dbf1629f2c7cabc63f2edc96426ea87d 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 06fe28589e9c9e88b014315dfab33a9e6cdfd0eb..a394297f8b2f94ea806a545c6e92e4b7221d2f7e 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 69b0890ed7e54aa0679d1154056a7d26454fb7bd..5b5a7080e2a5f2822dfd93190c05302be74b1784 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 4041f5747e73bf70f8d8dbb412f8e7b7067a8017..a146ee327f6ac15029b64424f0abd07e8d316f67 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 b7c32cb7bfebbd5912f06a421decb87b15c34bf9..05c39f030314698730349de8eb9346c1437d9aba 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 1095e878a46fdbe4a7224eb07a68cf1fc90c2530..8b836b376d9129760066326eabf5040f72b2e4f3 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 bb456f44b7b1cdbfc6b4e6be3b04cd6f22da6b4d..68f1609ca149e259fab8db2fdb6bc3d18587a049 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 ac09d98490aabc0729eb1a4691e8d2b1ec10a34c..07f6fc468e1732734e7fcf5f73982a93670e4194 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 e80183f4a6c4f3d6abea4b6d7720e381381259e0..e77edc97e036b4e8216ae8b54fe0e6cafaa2fe71 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 8ce9eefc5bb4f6aae3ffa520152a51eb033adb1e..a6d098c6df3f47f960004019fb48468ecea64410 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 882ec1dd15155233f89c8c7bad0d2a6dbf58c45f..496f94d57698294966d2c0c9bd10de34854b34a5 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 898f868833f2d4df0d80838f9461385b5eedcd77..29a7ebcfb42621d05cb9a74a7bcf291515b38461 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 0c7b75a8acc8f9ccad53d75bc6a3fe0da425ae9f..97daa8cf958df8e73c9fa8090f89cbaf4e63893e 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 3811487e7a7a1d58f23b6e04b49fda0dbf06c9b0..243f6834d02675c9c1101e1eabe18e56eb7d3244 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 a23d2d71188e61f6ad3b706730b2a70d8c773103..272261b5f94ff84e3291be05aaa3b1a8c1ca00ca 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 d8c30db06c5b75456098fe2f1a26785e9a9110ee..9064b919a4066fe9fca676581479e9162de56717 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 0b72e816b8d0126f0a3e72c1f3a2496fc3545030..7f5d4be220345b0899d38ced692f2458b9278ce7 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 87da3590c61e20287b4854e8212c178f96cb73c6..5bff0814776870e2974e6e436ad99f99f264e05a 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 243e710c6039a287f93ec9f303639c7316dbdf0e..a92012a71702e7156baba919e636bcfcce8971f2 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 83aff0a4d0938e308619a703dfca17265419e628..b60f33080a28f0a078f8186e65ab8d878fced928 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 00a7a664b9c16b92769f98fec8117e7c712e6ab1..c5792a5d87cede8cf2c5474156c1596f51f5ba61 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 1ce2e2a734fc2b0812845279a69cb87f48588d3e..af84bc0ec17c213054b023815ae197fefde7ffb6 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 74310017296ee02317b79a2c28b25ef303fc7720..4baf12e534d19031d28ddc5eba5335f72de54099 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 fbad7b091090d12ba0b101815fdc8699b092ee0d..f9c97d10b873ae4a896c3a22266707653d941c90 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 cd356df4f71ab5aa0514e7685b4cce50eafceb6e..b2e29acd7e3d6267a626f7bde5656c4f7fd49640 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 a87990cf9f94019c70d7263d247c1c94945aee5b..8335dbd3fc358ed1fe9d6521785ecee1dc031313 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 2b02d666bf63aee43e60e17fab4544e31730383c..e3ba1f2cf60cc0caa5dd7ed059dbe583b477e073 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 4a1d0d2c52fa4ab4ca66ff4a2025e093521556c9..62b78a6e224f2f10682e9fa11f28b8d01da1c324 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 36af6eeaa67eaa0532442706e668e9a268596c90..6cf2e60983b7c36c5dea0b745e6aadd907c01532 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 736a6011c2c88606cc7908fe429b14823be18625..0c1e37d829fa026a9fc61ef93b569087939867c5 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 9bb4710e35898b61c6824253501107898db76f36..ad1e781284fdd48492e7bac46c245fae5d578f95 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 4a78c4de9f200831c75e5c87bad683bbf669bbfb..6ee48aac776fbe84db68a503d9aca10ca45b0081 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 37702491abe98eedd91738408851c56d3a8ea3a5..2b406608a1a4a42606e6ca3eb583f5f1b136176a 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 e14531f1ce1c5258ccc816f9a739ed464b6c364f..264de88db3208290b940cc27b09e44f79e1616c9 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 f105219f4a4b120810973e0ae8cb31a8c4e2aca1..7614af31daff3678eb2bb75447810c0e27850f88 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 039902dca4a691074856d7846c59ad89f0bd8b8e..1037d75da51f35c1867cee72cc64bafd2859e3a8 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 700d0b49742da54d0a1280b84c87416977d7d721..0f04e1c302b4a7bf12aa4da04fc84a4d0c2a0f20 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 dc8b5d4dd636d3d5ed982a5d93c2783f203ac4f5..688a0419756bfc6ce2a9f632f6e84a6ed42debcf 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 e3a349977595f2aff6bd27f49e2ee9ee00164470..cc27297da5a9f9094e3079ef43e207dbd9848b68 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 2ef66781fedb3a9211448fa3db73eedab2c7d8a2..69363bd37f64ae016441df793e0f66ea3487bbb8 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 1b8b8b824cd766b05665e1d89f0e1394abdfbe2f..8c561c0aa636e49615b13e267c98e4e5bdce1a23 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 69af490cce4437bdc107f8b5b1216780b4c126af..08e576ada0b2699922b85c9e2783773baee404dc 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 3be89b3ce17b5a314215609790cadec6e5453727..2f7da41851bffc64d20c0de3db6977a800718747 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 394bb96b608707aa1ab943f66bc52fa173859706..3b9637fb7939a146e8a172a1e009e84c6ca4e841 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *     Sysfs attributes of bridge ports
+ *     Sysfs attributes of bridge
  *     Linux ethernet bridge
  *
  *     Authors:
index 00ee068efc1c2374bc0195d9458eca00392359c6..b84a1b155bc133e39d0f118b61be85fb1d2ed02f 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 b7de821f98df2875dd5c4c7b08f32b2f3d7f98a2..60533db8b72db4bafa73d336d697575ba3138c90 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 3de740834d1ffcfa35fe31735b41d5a0dcb58c3a..ca198c1d1d3047baededa2c1f2c6284b07010bfb 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 20e02d2605ecb2f10f5f74ab6f00cbd8fb852615..2c3d0f53d198c5915669a967f273c5f5b13b12af 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 548d716c5f62ac8c9d90d0959d19022714f9585d..2c097c5a35dd8550d8a3041ae41e6afec35bf48b 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 6609686166379765233cdbfab0e3d580a3d23051..31107abd278391dfe6752a46fea03ec22978b604 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 8d48c392adccec6dc1f2ca8e3c8fd5a6750283e5..34ca6d5a3a4b48f5dc8282a514115a278642f344 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 ab3d814bc80af8f377da971af189a49ae4f2f094..109ee89f123e5e51714cae1fa9097e6ec65f0627 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 49616fed9340265b203c7b1fbf10390f92c38020..3df6d3edb2a15a98cb0e90a4e5ed935f42f15f1c 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 1f6eab66f7cee5f94e1a5cfd6b6ea919184b5d35..8d6939eeb49247b1c2ee8659cc190814d64eb4e5 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 7167b08977df582bd38565cf960568a8553f29d4..850525b34899f3a50d0e19f6bd326821b0c2423a 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 6577a1149a47c17853e8c7e0e3daa267ef16d1cd..463bd1273346d72cad00a42a5852f95cef490c19 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 b2c123c44d6947afe1f6d588808643c5db3be9b8..610e324348d1cc5acdd861d8af916331d49244d7 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 a9077f441cb27b693d8ad1d710e4dba67aa93ebb..b6ae92a51f58607f7c32be2d0762a49380205012 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 cfdcf7b2daf68ff681608351e0bca7202923824b..da4241c8c7dafe0004a53ed85dfc270cd3be16ba 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 40ffd72243a4f2d1ec9e5da494b3f2650dd027a6..aeac0dc3635d98458a1f70ec84103c89a3f5a648 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 5fc9c7a68d8d102aef37b7b13ab1dd772553a9cb..c4ff5bbb45c44a1bda8eee4f5d7728338de88a47 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 583e8d435f9a2c47437d3897b7167ac4a4025a40..03986d31fa417a357b72e529e28fea0de0294a9e 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 24c03396e0083b751d2a924b69b2dc731f1b957f..79aa9652ed86d9cac754366c075800fbbe4aca1b 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 a8c891aa24645e9a45d2f8e47712b0698a29b216..b70f8979003b5e23c4b1e78e44713ba3d3520de9 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 9da862070dd84fe596f77582c82af6eec8ad660c..ab8bd2cabfa090a4fa50524e7a76064891e535d6 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 8184d121ff0904a285529ff234f75c3f15f522e5..43dd7525bfcba54c02dbd9dde2bd89cfc2d29c97 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 3b7bfc01ee36e922927958be79e1ec7414c8a3d6..22290a929b94595445865baecdb692aff5e0be9c 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 ae31968d42d3b855eebe05dcf0e660b4d367ff8f..cc9e02d79b550106ee07b6aca48ffa9e18081a45 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 7fc5d0d8149a53f2a20377499841657dd9a97c7c..340126204343a063902bb205675cc14bea743a4c 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 ac7ef5414bdede030d289a81946eaabc7b5d7a88..e6512e2ffd200223cd5cb75090802a98f544bb7d 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 5b2d3012b9830aef8d9101c26ba761402993b382..f5aed963b22e62cd997872d1068bfb6c45eeda7a 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 23dbcfc69b3b7f09ffc35c81d03dddc38d36da5a..2c5a79bd3777f5c313d3205a1154ef6b714a8d4d 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 c63b618cd619eb01d0fe99413162a84edd09ac3c..4fd1ca94fd4a140b374385ded878af60b503b529 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 7dcc376eea5f9205d1abf76f62a8d58eb54bc788..2f8010707d015dc62348ca758390c194388d7a8b 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 962e9792e3179997db98a448a76fc909432d841f..d92cc317bf8b25a0c371b770688c860169c9dea8 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 971ea145ab3ea33a2d42ad0cf66e7025c1457832..8a703c3dd318b660c5e02b326495dbbc7b9f5b3e 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 7011c71646f0266eb75c856bc49fea7b5030bd52..6113cc7efffcd782cee9d8c2e07ffc399f6e67c4 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 b68fa191710fe02bdb1b09f825ee6330c9bf570b..625fa1d636a01ccacb43c2fcae902d65a466b9db 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 f8b71911037ab172f3df8f6a82cb8d22191ab1d6..20b15916f40363ff789d2d7312dd5fe4dedf69ab 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 c15042f987bd8f5697338b88cc77ed6553a0d609..a1100640495d3d3b106e850e9af6a9cc4e1ed547 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 6bb1d42f0fac04c02a69ee1790d40baf7af53824..85d842e6e43187998232441f5e2228244cb1cb95 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 90872c4ca30f4ba9aad89089eff5dadfdff42717..b9be0eed89801ab194b8f6a97899e7bbf9c50ec3 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 7c94aedd0912777d6d0956f0f5b048f0f62ab97d..96a458e12f60ada2186c08ebbafe22c6e68ba06e 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 c5384ffc61469a422f1e5f4a9519131d95b56236..dd1c37d7acbcfa6d126a8056360b8d6a56985035 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 af3531926ee0c0339c6cc73725c50a1d7ec2a18d..8f0897407a2cf950240082cfde9ab07969f96404 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 2fd6dbea327a8b39d2ec0ed10b927d74bcdab408..f85f8a2ad6cf002fa438bef15597496897d00483 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 dc96a83aa6abb6659311e11ef13f97dc81c3b494..1d074dd1650ff2fd326dd141eedb828d812a12e6 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 7b1c186736ebf924977ed8eb9040357ab88f3c3c..fe66908401f55ed5f608a75b559e5fad1ff15548 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 2a2416080b4fbfcf2127a4cab2abc755b5188c06..a4f1e42e34818c91eeb2b527c7b547a718454459 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 b05ad909778fe5978677f3f81a31360220f98eb7..f16fd59d41607d80aeeae916ae3d43153a0a5b4e 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 ee85a1fc1b2443d88982ca6985574936b0359292..820a7850c36ac7e49012869a88472a96358e2220 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 22c5f399f1cf8119f13064559099ad7c30aae93d..ab101f715447921b01829c493d1cdef195b4400f 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 f7e3a0d84c40488cd6744dce31c90bd0d942bd3b..f2ed7600084e896c34d7f5c137a286fd3a05b986 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 5c519b121e1be0ba26c40e136ace7b8eba42f62e..1aa84dc58777b589f80f84f04554a981502bed2c 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 281c1bded1f60f94934e406c9cafe076e4e2706d..51b968d3febb477be1e4183c8a94258c97fdcd18 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 ca8e0a57d945dabeb51147f338cef363672040d5..1f9c31411f1998dec927fccf05362f09408558b4 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 71a568862557c26cb9fd97bfbd26531b55ad4283..7a42c81a19ebe55f0b6a137f89c55b46314f8cd7 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 4626cef4b76ea631e32d082d34828ffd2e465459..48be3d5c0d9246117c03b0174da16a637129640c 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 c2124ea29f4594304c3b7ecb02af411ed62fbebe..c2178b15ca6e0bb0ed60eb885cc94177fd5b8e95 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 bce5b79662a62b8bdc5e7c895a6ea4bcd147ed86..ab67efc64b2490efba497e93db105bf9ed25b117 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 bdbbc3fd7c14e9fa2c31d4faf7de9b7b64540292..8fdd16046d668b0c6cf927e5e87754f2ebfaf583 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 829b460acb87e61e88928f596589b51b0947411d..b2d7c629eeb9f2de785600ed189080af9be02a3e 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 d304f41260f2d8be4822631be5deb86612b63860..af7ffd447fee2af42a642c3e608536a8459ecbe5 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 357f613df7ff49d3460e37d3f338cb89c7029a69..3c85d1c8a0288db543fdb5cbec9d9ef5bd0f2f22 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 d0347d148b34320fb2a12a3ed20c6a2e5222352c..09fb638bcaa42ea88ff1bc7a6d34b6605f34a0c7 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 74f6a704e37418cc9b8d4a9b6679f3dd8825da21..ecbc4e3d83ad3f816caa51b6ec942461dac9f090 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 74d948f5d5a1d399d13061ee5c910c2cacc6f720..779742cfc1ffe3178fc0c320b6d0832e0f420d64 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 3df764dc330cbdb398e7dbbd5c6558d894bfc386..1891a1022c17e9d7d4c1686ff30c2ef13ebbf7b8 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 305374d4fb985ec4942040447f91e8d8277ea10d..7762b9f8a8b72581f00003ad266ab060754f43b9 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 cb29ef7ba2f0b1d285c079d87ddf8c5a07c118af..609c30c808165191a69899e750439666addc29f8 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 19da5abe0fa6fb1ebcf185357bd46489310d9dc7..fd3fa57a410e18393aa6cc20136fcaa28c0f7e22 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 593071dabd1cc7477169b24bc31979d8590465b6..4d9334683f8409c3e064c44a25235ea48e65b38b 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 4f9f216665e9d4d6753172f3c14d7bbdd3f53154..a8c29fa4f1b3b90539f5370b9084056c5774812a 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 1cc47aca7f05baee3e7ffdf18a4e002b2d62279d..3fcba69817e579244e836b2e2d39a1aab14cc210 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 5a24c986f34be27e61613f0deb421a35efc61533..de06d5d1287f97b6f6c8a1fd6b3e59371d80ae3e 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 1d3cfb1a3f28b3a74a32c1c629ddbcba7fb30def..81c8a10d743c04fb76981498b42588f9b821f33f 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 3f7682a387b730b9c75fc6e547de98d512b46dbb..eefbd10e408f18b87d35c35d729fabf088734d65 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 ce431e6e07cfc7df27e8320d6da1b13516310df9..5066a3768b2841a4f46d8cbb8116b4d8276334da 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 823359ed95e16a0969ee6c28843a4777387d3561..a61d7a9a995e86daaeea8b8243c93f9fbfe911d2 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 26422a3584ea6684e934f66b33a7f9aad8b5b762..69a2455b447210d42c2bf2c37b23fbe9035eada9 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 65f86b56ba422a2c28c6d0c70c731c6250df7c63..2a8fc08d52a173686fa9e946f2f3932179a64812 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 c0c2f57a0d6f332b6143c3eaa6850921c1dde485..313f22e9d929d8f5dbd039d224a529788b22c635 100644 (file)
@@ -6,6 +6,9 @@ config SND_PCM
        tristate
        select SND_TIMER
 
+config SND_DMAENGINE_PCM
+       tristate
+
 config SND_HWDEP
        tristate
 
index 43d4117428ac9d551391f0f89d1edfd3b2665c6b..5e890cfed42363e1aa1b1ebfbfba76d0d16f0326 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 99db892d7299056568e5432bdd660ea14d3143c6..98969541cbcc9c62ff81afb9818d2399dd6e7eb0 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 7c11d46b84d3b3b0fd26b8bca560f6fb3017a8fc..48a9d004d6d938ac5365b52a83c6b67b7b18dcaa 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 8e77cbbad871dd4ff10263824d016487b1479813..e3c7ba8d7582643f9d1f52681251e16e3835d042 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 8bd2261498680676c0b62b7861fbd5be2aa4daac..f303cd898515d5f20000ec5138400bfd93e63d85 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 92b9b4324372e8f9d15aba987c3a55a4cb6945c0..6d1924c19abfdb41d1dddc27e119630c24995abc 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 45eeaa9f7fec49f035cf8faa54fdfdb5a8ea9df5..5138b8493051fd54c674fe26ea87d9d5fd1411c6 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 bc0261476d7afc78767856683398ec1bd7bc463e..61a64d281905e4b8997bc2ae3eb42ce387de9e7c 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 3fdd87fa18a970db151fdadcc578ca61c87d3241..e48d38a1b95c6d6b13d3eef9bb09efed5d970964 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 41967ccb6f41e3968753d4922ad03f2439ad81b9..5baabc8bde3abfa4dfcb833c1c3fbcb858bf7ced 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 d12826526798fc47620e4cb613df9e95da8a8f7c..06082e5e5dcb7d726e2bdba6e5f2d7f816dcf262 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 f3fdfa07fcb9fafa76d913b64be070b54d31486e..0ecf356027f6c1fcc91693e4c7063152fe3ac706 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 d6f7694fcad4f78ae1cb300d8d9fe3a4ef3b11d1..c8a2de103c5f3b6b0cb5172f858c687795154d19 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 a497a0cfeba153aa70630b0dfadc7e69bf2d0e7c..decba87a074c6267eb1bd93265fc8fc96787db7a 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 a822ab822bb7ba40f5f1ead77a04a7caa7069233..986dcec79fa02e1552fb631456878cb9dbe5f940 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 efb1daecd0dd6136122aa8595c145630ff102b22..e82eb373a731402cb60699881aca15a84577f72f 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 15c635e33f4d99a42b6386cbc7e7c54e2bf807ef..a680fdc9bb42012f72366a4a09f7ece684a06ce1 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 04491f0e8d1bde2636f8772e3b7d3bb65284d44a..efa75b5086a4b00e83802d476c87aae0a6914d0e 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 17ad70bca9fe5828d4a8b3b5327dfc6b30bdb260..f23f331e9a974409adf876356a2f766cb81ac812 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 badb6fbacaa66222bea9cef708c1379783746c7f..15106c045478e644719a73e76edb6ea795909ff1 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 70fd8066f546e9cfc39dcb024f1efa6e5ea6bf1f..bc126764a44d02cb38b50f3ae74900a9ce490da2 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 ec7351803c245b7ba209a582e0d82fc958effb24..8d9ba4ba4bfe0b2fece2dc5c30f955fd5d6dcc00 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 89fcf7d6e7b8fdfb94bac498c935ad9bf3646fcc..7257a8885f426d7cf05b017fbda1aa3f01abe236 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 b1f2baf42b48233678ae051bea1bd2b9fb747327..5fac8adbc1367a8b01d1243e9768a25b2b015643 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 d1124a5b34713c688d92846e25cca563ed9c20ff..ebff1128be595ca7ff63f5ca049d2f30342dee45 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 3c839cc4e00ecb48a5e3948567c14dbede7706a3..15b012d0f226c48a4178b1c9f4d10468708dcd1d 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 506d474c4d2227372b6b8e4a6743ca8f67ef7da3..8f388edff5864632bf1eb9f8382bdeedf4267486 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 c7cfdf957e4dac91c04ffad2f9e2d2dc1e2434aa..71059c07ae7be5abc3a9c70fd5443bce27493ced 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 1f303983ae02ddaf0a433ff32c188046d3da68a7..72e953b2cb41d8e4e7611b4f3141c59caf68041a 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 de625813c0e65c7aff7807d6904c53d2c581249d..657808ba1418d5588e961081c5e1578cbb671400 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 b60b08ccc1d06e54bf09579ec1ffff3640cb2d15..9e81b6392692cbd78e7e9ad7b263fcd00c214a1d 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 a081d9fcb1668ed8393429d60d3cecac63ea7ae5..c4cf0699e77fe4cc98182f3fa877eb02960a9235 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 8e4779812b96c03d11f07ca6a4c47ca628b3295b..83c835d9fd884b18a87cdbb5420838b8fd9229f0 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 03036b326732ddfec0fad5b390806d9000a58589..a20f1bb8f0715011dad1a710cf038a80121e30b9 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 987f728718c52cad7ee2a5f1c5dd8dc2fc6d3f02..be2ba1b6fe4a3a344b062a7f693f8b1f83cce0ae 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 2bcae2b40c92cd48a35aaf59ad333bb689851ff2..68342b121c966aa7c90ace1384bbfbefe4737ab7 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 9f9f59573f721344995233da13ddf875f43436fc..0e5743ea79dfdf6c4a4191694955883fbede59ca 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 a6ac2313047def253ddc0ff4ebddde4947803c1b..31f91560e9f6df0fb115ea862b712e9863cad9dd 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 ad5313f98f286b8f95223b56ef88ae4718f7a73d..0569a4c3ae00e7ce8b8fb27952387d87913f4098 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 6b6c74cd83e2bcc2d9e5292cca7c2b70618eaa18..29549cdbf4c1c6138e825e3372644aa9e3008f90 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 5402dfbbb7162f668d8841a83ad3c04db5d2516f..4d3c8fd8c5db5aeec4632e958d3737a0d59adc0f 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 f2a6282b41f4e07a1627463222b4ba9d091a7cf1..b6618c4a7597fee9d0bf11528f5997f7548a747f 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 ce585e37e38a8f8edda36a0146ed477ec61224bc..4db7314baabcab95feb9f1b0a1e5e2ab83d7a54a 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 6c8a9e7bee25c837cd35dc260847e1c778a811b6..1f4093f3f3a19219318eb0f3c407d8f302ce34d3 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 73e205c892a0d087b4cfc8a6cd0a7de5c26873f3..38f3b105c17dc2da0809c903190dd37644f2508d 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 e9d7881ed2c8272c2c64c7255e60728356aab009..e3501f40c7b3d866f965131e64ce2ae1227e1b77 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 18280499fd554ee13ca7f9c17d86c8594a40d8bb..a078aa31052a589e2ee4115f6657806b62ba0418 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 cfb55fe35e98691cbaf7b18404b93e02c1cce73c..06edb396e733f1ad2ef26698a41b4eb1fdc18ea6 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 b1f6982c7c9c2615cc187649501f231098d1696c..7b8f3d965f43c814b9b5f5f918ddc6c8778129d4 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 e5b926883131180c71cfe6239d1bca3be8fcf674..6e3f269243e050fe5149e60807c0e41cbf6e4147 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 8e6e5b0160219ef140748a3dbf31bc7561b9a8d1..1e3884d6b3fbc7202cedb6fe478e5d00e71da49b 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 44621ddc332d881b5e4b05a58507060259446e55..3c79dbb6c32323b36bc974616c5ff1157498f281 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 f5e835662cdca30477738e39ffe7d57f6305db78..10adc4145d4639e5e44d3c587a595f476650b6fa 100644 (file)
@@ -410,6 +410,16 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        rec->command, rec->length);
                len = rec->length + 8;
 
+               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
+               if (!xfer) {
+                       dev_err(codec->dev, "Failed to allocate xfer\n");
+                       ret = -ENOMEM;
+                       goto abort;
+               }
+
+               xfer->codec = codec;
+               list_add_tail(&xfer->list, &xfer_list);
+
                out = kzalloc(len, GFP_KERNEL);
                if (!out) {
                        dev_err(codec->dev,
@@ -417,6 +427,7 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        ret = -ENOMEM;
                        goto abort1;
                }
+               xfer->t.rx_buf = out;
 
                img = kzalloc(len, GFP_KERNEL);
                if (!img) {
@@ -425,24 +436,13 @@ static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
                        ret = -ENOMEM;
                        goto abort1;
                }
+               xfer->t.tx_buf = img;
 
                byte_swap_64((u64 *)&rec->command, img, len);
 
-               xfer = kzalloc(sizeof(*xfer), GFP_KERNEL);
-               if (!xfer) {
-                       dev_err(codec->dev, "Failed to allocate xfer\n");
-                       ret = -ENOMEM;
-                       goto abort1;
-               }
-
-               xfer->codec = codec;
-               list_add_tail(&xfer->list, &xfer_list);
-
                spi_message_init(&xfer->m);
                xfer->m.complete = wm0010_boot_xfer_complete;
                xfer->m.context = xfer;
-               xfer->t.tx_buf = img;
-               xfer->t.rx_buf = out;
                xfer->t.len = len;
                xfer->t.bits_per_word = 8;
 
index 282fd232cdf7cf62ce6d836578e3c518cd839d59..8bbddc151aa842eed14cae97cdabdcbbd9d8e469 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 2e7cb4ba161a5fa2a6980ec59eae33eb9c49ad18..bbd64384ca1ce9b76f8efc63f8ead2e3bc8a1c0c 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 fa24cedee68769f2b723e2fb8b25c03869ee286a..eebcb1da3b7b10769f0e265f95c90a6638266f71 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 0a4ffdd1d2a70eb19c22445365d0acc5cc854dee..5e5af898f7f837164c4b1df775fafda5bb1cfafa 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 ba832b77c543af1cbdd13f2618836186c399f789..eee2a01f26912771b5d1bcf49816d97468bb8ad5 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 90a65c427541fb9290616379f7b53bc17c01d0ea..da2899e6c4018fae6cd0a2411b58027f4048b6e4 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 05252ac936a369cb210a9043105d9d95cb614679..b38f3506418ff0d43dc927fe45424e3d9d998d75 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 9f922c82536c52f8939db5834bbcfda80e1c5b59..d018dea6254de44c5997813fcb9b958eeca09706 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 2d9e099415a58cbe353c99f32f6f089a200db2de..8b50e5958de5a43030ac854d18c046cf903e5841 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 aa438546c91271f69c26beb1646b85f4b34357cf..cd088cc8c866f1559b2945e5b8df6932eb56856a 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 d4b4aa8b5649d3ccefdedc6a51852dafacf2286f..4b5970e014ddde0243dbee0e0c24445988b63200 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 2f2d837df07f078e5b60da38308cbdb8d53b9969..5cf626c4dc96f7615f92bae6ef28c25b2ced500c 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 e260f1f899dbb132135cb6745376f5dad8891fb9..ab17381cc9812a7e0538f30ea44496bfdd944c6d 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 b8ff44b9dafaaaeecd1a5c9fbc0ab4efd0e69b6b..38a4209af7c6f6e43e5ebe4cd74aae9895e09896 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 9df173c091a66b4fbb676036b9a66cacfe2eff17..a3d60d4bea4ce8ace84d2860921b5c46d3f00895 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 fde4d2ea68c88afb32275963ae0b51e81be9112a..4dc1296688e9210531f904366dcc19603e0022ce 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 310d90290320c751b572f2a409f8c4800f6c60b2..34043c55f2a62f048232b09ff2f6165fd3726116 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 67f656c7c320744334d4ca5d8233d36eacbe6d4d..5d5b73303e1169b7f6c2254e06d66a87409050cc 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 3f726e4f88db8c2900840819e5d86ede5e9415d1..389cbfa6dca79d6100b34e64f57d6bc2514d20f8 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 51be3772cba901bc17d245ab0077ec744fcf64b2..f58bcd85c07fbd8b302c0c3bcd97fd3cf6ed4d0c 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 d5003cefca8decee028d937a9a9a975bb703102d..fb1616ba8c5967e1892b4ff6c7e180b2b9447047 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 52a36a90f4f4eb19c4739fda1714f48e715d1c68..1d70e278e9154e7f21d1ba230b4f573ad5b31f95 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 c62d715235e29ac5fa20639271d79958a57fd853..9e1970c44e86148b0ae0b4396977d0691b84adc6 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 3e62ae9e7bbeadc0924b05447cc41a01d894dd5b..9e781385cb88be80d8b4eb3da2b2090ca92f3a15 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 a9f14530c3db6a5eb9d3425f7bd6ef5ba4106add..b238434f92b099db8bf3ba613fc596b7006ec96d 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 4c9dad3263c5f7b754d108b3bf66a3ebdb6d67f3..e5f3f7a9ea269cc0d4ef28868ac8148fe8d90013 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 b979c7154715a0ee9407c908f76f9f1ca9f91748..025be0e97164283cbd4ed7516a477bb15bee404b 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 1d0ed6f8add7ba5a7236f428476ab6f981522ab6..27545b0c48561470e787c3c167c60514172f10aa 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 4d92637ddb3fd878f86e4d4525fbd024d94b2618..f8e1ccc1c58cc76f8ce2a314a1c8a0fcc5e998a5 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 78d321cbe8b44ab0b06c9142da04d47d725dedf4..219235c022125d84a7565a4c9c962dd5098990d0 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 54511c5e6a7ce8a75a2bc5897dd6a7d6085e007d..b56b8a0e8deb43b6fdca0668fb43677bb1ce47ba 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 1b134d72f120a60b5956032986b964c6f659ab0e..ce084eb10c49f2f826fac137a14e0ba48e98db6b 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 f4c2417a8730bcf0ae99c37fe1bfcc76a685cb51..8987bf987e584f6ba7a53b93516056dfbf5bc9b5 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 9f5d55e6b17a53d7e50f2a3c392f565b0fb2e014..daa78a0095facf5ff35d1eb0b6ca61836b7c9210 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 70cd5c7b2e145622b031ffd320786599738091de..ebb13906b3a0b41b4d3c20509c613378da5ae248 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 4db1f8e6e17268e042555fcae6f732d17fed7946..12e566be3793e61eb4fdd7d9ac47a23d638bc260 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 7483efb6dc674e9bdb90e9ea3bd39a7505a9c34b..6c19bba2357004903477a7300582d193b26f2962 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 a49dc52f8abc03fac075a56c879aa2bdcaaa5568..90d2a7cd2563d06170d450b5bb6a9cc8a6615210 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 b3580946754702b87a883220d547aeee26b04388..4db74a083db1ef792f90dde317ee9e7556eb4e1d 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 4ad76099dd43fdec0d9e7262db77f1e07cd20713..5b7d969f89a96eebd418687ef5b7abc79d74ee97 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 97b711e12821e02c2b62c6ceb377fb4a942ee71f..bbea7780eac640630803a024d3d0670b01c3c1eb 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 5d57e071cdf522e8f8b11670c32a47595b5d6e92..8235e231d89c013dd957f08b3336a0d3d3a941e4 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 62142ce367c7e68fcffbe7b34b92b7364d7a0af3..41752a5fe3b07148c5402b2ea66d6f292fdc3133 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 6f4dd7543e829db8e73577f1184c667a596c89d0..a3119a00d8fac8ef8295ef3593f16a60c2603aab 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 1475515712e65616b345f3d7e56ddedf954f6b4a..f1059d999de6d4128791861d2325cd8bf68371dd 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 f7ca716641126bdb65ff5815823a500719bbeba8..d5340a088858eff3f8a8b578a38a2ea3e7476bf1 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 ecff116cb7b034484cd3c420ae483d576ef0db95..806da27b8b671ed8596484856ec59f8092c75e8d 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 f4ea4f6663a2c0d396997d7aef5cc1871f6ea6e5..13c9ee0cb83b988b06cb9b84963128b1cd703032 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 58cfb1eb7dd3aece2e20b7c45421b0aa5cab5533..945e8abdc10fbf9579a1f89bd9a6a0610980256f 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 2dd623fa3882b8fe17ceab2c6a86f45f54059f9d..2acf987844e8089704a4bf6d0ccde5ece2cc39e3 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 21b79262010ecb3774d8a5ad5ad7f8f87707549c..a0c67f60f594cdcc1af41958d3c8efa199b9c98d 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 189a7a6d5020c637d1523ba8261ac9a421882c14..0e86315a3eaf11859d32ab78b1327ce1a60e39c4 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 c0e6d9a19efc72562c31157acf776f1e24e57085..821a502310024ba221a2dee4fa33d7937ebe4828 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 959c702235c8c6028d0946f29b622266f043ab2f..b302f3b7a587f3e480586419affc8e300c80ad8d 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 1566afe9ef525097ee45ce737af33bc63b47fba7..e54256fc4b2c6d35faa47f8c3a1d42ddb3f5c74e 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 47e23864ea72f762deea79ee195ae0b633f8c6db..ea885cb9f76c300645228a9b9daa75e81a560d82 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 8b3414551a6231ffe6556989570831dd46c15dc7..9c8ebd872fac2ac67bcaecae2aca1c9e0a051e3b 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 581ea4a06fc684d1e3f677477326426d7334b427..5fd7a05a9b9e2fe9730a962bcdca73482a9e5d71 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 2e5ebb2f1982c2e849e8a8adc7924034a6931675..28487dcc4538b939bd86a82395bb7299c2a5d243 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 6bcb1164d599d61bec029fdb94d3f00495b8f66c..56d8ff6a402d2eaffdb4aeb5bc65faa5b815678a 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 849b387d17d99a7d91b21bd1f64adc228341cfb9..aaf3dcd1ee2a197fae36c1f577443a386e8371a1 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 06a8000aa07bedd1c47beb401d26e9052512fc54..53c9ecdd119f14fa7a33832d11a88746e257307a 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 d82ee386eab564d352eccd4209dff767b222e6f3..528f8708221d4cdc9ac3877fc818c7d558b7ad70 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);
 
@@ -2097,6 +2231,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
@@ -2540,59 +2719,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
index b94190820e8cfa1b6c24e925f176196cc5efff98..d84bd0f167b684e69bd93ef9c3205e93eca39d99 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 0bb5cccd77663a4d819a67731245e51564af3224..7aa26b5178aa60ac68d7f2c281b515ecf35ef979 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 b6c640332a1722c95c27fa8aa99b4d8b135d456f..fb70fbe26862f63ef879b5fde3c58e49e2fd49a6 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 3567d73b218ed9273a7b617ae3f91c5411f83cf3..0a53053495f3d39cf6363b2255bfa4ad629c6be0 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 995b120c2cd0a49a90a191e1e06649cb52396839..8fc653ca3ab40b3ef04d1a58723a2466086ab8ff 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 6c486625321bebb78b6f66370fda54a49a300fcb..ae27bcd586d25428458c305c16448395b9f74d88 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 d04146cad61f4f2dd0227815d0f25970e22e4cae..47565fd045057344390592bb2a8d7a5374cc2209 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 48d05d9e1002b3f13529f386d543c0b59803874e..c61ea3a1030f7a683f55bd087049392fe4867bfb 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 08794f915a9433a1fdaa91842c74c16279e7f9f2..4511c5a875ecd8567e58c3f62496ab8e1076473f 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 f87fc53e9b8cddab8d8f529c0ab730a8481ede8d..8e774d1a243c624dcca5b09c25065316629d886e 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 05c68aab5cf0a9a8e06a7fb93f27cd2b0d3cf3e0..734bfcd211481ccccf26c86a3db23399ecf9ffb3 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 4bcce8a3cdedd618e18844a55373c273cbd6427c..e0305a1485680b18cbc85ba33a506bda799f47c1 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 9e6e3ffd86bbbc4212e72eb3d0c7cd69e6d44c8e..23452ee617e11a5d304fffbd0da3e7bea805e0dc 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 6a0840b0dcff2be78366119126e5842aa4ab325f..780d5ed8e5d8a39ff9bec150d9840fcbbef713d8 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 26722423330dd283b62d3fd4c5b77409913372cb..f3dd7266c391c7f17dae6220ed094f548a1d4507 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 c321006e5430ac763e593ecee6314c6cee8fd2d6..84851b9f55592f2ddc4b35781e1efa20cac5cd02 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 3d2551cc10f2f6fc191acea154ff2a2bc303b09e..b5eb97fdc842f79893adc8d359c4e519df82d700 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 9b01133ee3fe9c22d3f51557430f011846e5bc8a..f5779d6182c638b02253af7bc9ab73dfed7e1916 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 7a444b5501d91d28a4e7e8fb5e044c2b4e7ea41b..659950e5b94f6b411577a84821f1a1c4d93b4593 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 d5438083fd6a8072c20275778f1f3b9fa0a42517..95558ef4a7a09c72ed52c4706348d765a40c4314 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 1bc45e71f1fe0217d25ad6b85edd396458cf123d..0df9ede99dfd798730376574511fa1041f2f528c 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;
        }