Merge tag 'asoc-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound...
authorTakashi Iwai <tiwai@suse.de>
Mon, 15 Apr 2013 17:45:16 +0000 (19:45 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 15 Apr 2013 17:45:16 +0000 (19:45 +0200)
ASoC: Updates for v3.10

A bunch of changes here, the most interesting one subsystem wise being
Morimoto-san's work to create snd_soc_component which doesn't do much
for now but will be pretty important going forwards:

 - Add a new component object type which will form the basis of moving
   to a more generic handling of SoC and off-SoC components, contributed
   by Kuninori Morimoto.
 - A fairly large set of cleanups for the dmaengine integration from
   Lars-Peter Clausen, starting to move towards being able to have a
   generic driver based on the library.
 - Performance optimisations to DAPM from Ryo Tsutsui.
 - Support for mixer control sharing in DAPM from Stephen Warren.
 - Multiplatform ARM cleanups from Arnd Bergmann.
 - New CODEC drivers for AK5385 and TAS5086 from Daniel Mack.

664 files changed:
Documentation/devicetree/bindings/sound/ak5386.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt
Documentation/devicetree/bindings/sound/ti,tas5086.txt [new file with mode: 0644]
Documentation/networking/ipvs-sysctl.txt
Documentation/sound/alsa/ALSA-Configuration.txt
MAINTAINERS
Makefile
arch/alpha/Makefile
arch/alpha/include/asm/floppy.h
arch/alpha/kernel/irq.c
arch/alpha/kernel/irq_alpha.c
arch/alpha/kernel/sys_nautilus.c
arch/alpha/kernel/sys_titan.c
arch/arc/include/asm/dma-mapping.h
arch/arc/include/asm/elf.h
arch/arc/include/asm/entry.h
arch/arc/include/asm/kgdb.h
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/syscalls.h
arch/arc/include/uapi/asm/ptrace.h
arch/arc/kernel/entry.S
arch/arc/kernel/kgdb.c
arch/arc/kernel/setup.c
arch/arc/kernel/sys.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/boot/dts/armada-370-mirabox.dts
arch/arm/boot/dts/armada-370.dtsi
arch/arm/boot/dts/dbx5x0.dtsi
arch/arm/boot/dts/kirkwood-goflexnet.dts
arch/arm/boot/dts/orion5x.dtsi
arch/arm/boot/dts/tegra20.dtsi
arch/arm/boot/dts/tegra30.dtsi
arch/arm/include/asm/delay.h
arch/arm/include/asm/highmem.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/entry-common.S
arch/arm/kernel/head.S
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kernel/smp_tlb.c
arch/arm/kvm/vgic.c
arch/arm/lib/delay.c
arch/arm/mach-cns3xxx/core.c
arch/arm/mach-cns3xxx/include/mach/cns3xxx.h
arch/arm/mach-ep93xx/include/mach/uncompress.h
arch/arm/mach-imx/common.h
arch/arm/mach-imx/hotplug.c
arch/arm/mach-imx/src.c
arch/arm/mach-kirkwood/guruplug-setup.c
arch/arm/mach-kirkwood/openrd-setup.c
arch/arm/mach-kirkwood/rd88f6281-setup.c
arch/arm/mach-msm/timer.c
arch/arm/mach-mvebu/irq-armada-370-xp.c
arch/arm/mach-mxs/mach-mxs.c
arch/arm/mach-omap1/clock_data.c
arch/arm/mach-omap2/cclock44xx_data.c
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-s3c24xx/dma-s3c2410.c
arch/arm/mach-s3c24xx/dma-s3c2412.c
arch/arm/mach-s3c24xx/dma-s3c2440.c
arch/arm/mach-s3c24xx/dma-s3c2443.c
arch/arm/mach-ux500/board-mop500-sdi.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mm/cache-l2x0.c
arch/arm/mm/context.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7.S
arch/arm/plat-samsung/devs.c
arch/arm64/mm/mmu.c
arch/ia64/kernel/process.c
arch/mips/Kconfig
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/bcm63xx/nvram.c
arch/mips/bcm63xx/setup.c
arch/mips/cavium-octeon/setup.c
arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
arch/mips/include/asm/mach-sead3/cpu-feature-overrides.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/signal.h
arch/mips/include/uapi/asm/signal.h
arch/mips/kernel/Makefile
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/linux32.c
arch/mips/kernel/mcount.S
arch/mips/kernel/proc.c
arch/mips/kernel/traps.c
arch/mips/lib/bitops.c
arch/mips/lib/csum_partial.S
arch/mips/mm/c-r4k.c
arch/mips/mm/sc-mips.c
arch/mips/pci/pci-alchemy.c
arch/powerpc/kernel/epapr_paravirt.c
arch/powerpc/kernel/exceptions-64s.S
arch/s390/include/asm/pgtable.h
arch/s390/lib/uaccess_pt.c
arch/tile/kernel/setup.c
arch/x86/boot/compressed/Makefile
arch/x86/include/asm/syscall.h
arch/x86/include/asm/xen/hypercall.h
arch/x86/include/uapi/asm/msr-index.h
arch/x86/kernel/microcode_intel_early.c
arch/x86/kvm/lapic.c
arch/x86/kvm/x86.c
arch/x86/lib/usercopy_64.c
arch/x86/xen/mmu.c
block/blk-flush.c
block/partition-generic.c
drivers/acpi/Kconfig
drivers/acpi/acpi_i2c.c
drivers/acpi/apei/cper.c
drivers/acpi/pci_root.c
drivers/acpi/processor_idle.c
drivers/acpi/sleep.c
drivers/base/power/qos.c
drivers/base/regmap/regcache-rbtree.c
drivers/base/regmap/regmap.c
drivers/block/Kconfig
drivers/block/aoe/aoecmd.c
drivers/block/cciss.c
drivers/block/loop.c
drivers/block/mg_disk.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/rbd.c
drivers/block/rsxx/Makefile
drivers/block/rsxx/config.c
drivers/block/rsxx/core.c
drivers/block/rsxx/cregs.c
drivers/block/rsxx/dma.c
drivers/block/rsxx/rsxx.h
drivers/block/rsxx/rsxx_cfg.h
drivers/block/rsxx/rsxx_priv.h
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/common.h
drivers/block/xen-blkback/xenbus.c
drivers/block/xen-blkfront.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/char/hw_random/core.c
drivers/char/virtio_console.c
drivers/clk/tegra/clk-tegra20.c
drivers/cpufreq/acpi-cpufreq.c
drivers/cpufreq/cpufreq-cpu0.c
drivers/cpufreq/cpufreq_governor.h
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/intel_pstate.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/compat.h
drivers/crypto/talitos.c
drivers/dma/Kconfig
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/eisa/pci_eisa.c
drivers/extcon/extcon-arizona.c
drivers/extcon/extcon-max77693.c
drivers/extcon/extcon-max8997.c
drivers/firmware/Kconfig
drivers/firmware/efivars.c
drivers/gpio/gpio-ich.c
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/nouveau/core/subdev/bios/base.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/radeon/radeon_bios.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-magicmouse.c
drivers/hid/hid-multitouch.c
drivers/hid/usbhid/hid-quirks.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/infiniband/hw/cxgb4/qp.c
drivers/infiniband/hw/ipath/ipath_verbs.c
drivers/infiniband/hw/qib/Kconfig
drivers/infiniband/hw/qib/qib_driver.c
drivers/infiniband/hw/qib/qib_iba6120.c
drivers/infiniband/hw/qib/qib_init.c
drivers/infiniband/hw/qib/qib_sd7220.c
drivers/infiniband/hw/qib/qib_verbs.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/iommu/Kconfig
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/irq_remapping.c
drivers/md/dm-cache-target.c
drivers/media/i2c/m5mols/m5mols_core.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/platform/Kconfig
drivers/media/platform/exynos-gsc/gsc-core.c
drivers/media/platform/s5p-fimc/fimc-core.c
drivers/media/platform/s5p-fimc/fimc-lite-reg.c
drivers/media/platform/s5p-fimc/fimc-lite.c
drivers/media/platform/s5p-fimc/fimc-mdevice.c
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/radio/radio-ma901.c
drivers/media/rc/Kconfig
drivers/media/v4l2-core/Makefile
drivers/mfd/wm5102-tables.c
drivers/misc/mei/hw-me.c
drivers/misc/mei/init.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/pci-me.c
drivers/misc/vmw_vmci/vmci_datagram.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/can/sja1000/Kconfig
drivers/net/can/sja1000/plx_pci.c
drivers/net/can/sja1000/sja1000.c
drivers/net/can/sja1000/sja1000.h
drivers/net/ethernet/atheros/atl1e/atl1e.h
drivers/net/ethernet/atheros/atl1e/atl1e_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/calxeda/xgmac.c
drivers/net/ethernet/davicom/dm9000.c
drivers/net/ethernet/davicom/dm9000.h
drivers/net/ethernet/freescale/fec.c
drivers/net/ethernet/freescale/fec_ptp.c
drivers/net/ethernet/intel/e1000/e1000_ethtool.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/igb_hwmon.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igb/igb_ptp.c
drivers/net/ethernet/intel/ixgb/ixgb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/marvell/sky2.h
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/eq.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/micrel/ks8851.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/usb/smsc75xx.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/rxon.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/rtlwifi/usb.c
drivers/nfc/microread/mei.c
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/rom.c
drivers/pinctrl/mvebu/pinctrl-mvebu.c
drivers/pinctrl/pinconf.c
drivers/pinctrl/pinconf.h
drivers/pinctrl/pinctrl-abx500.c
drivers/pinctrl/pinmux.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-at91rm9200.h
drivers/s390/block/scm_blk.c
drivers/s390/block/scm_drv.c
drivers/s390/char/tty3270.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/fcoe/fcoe_ctlr.c
drivers/scsi/libfc/fc_disc.c
drivers/spi/Kconfig
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-mpc512x-psc.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi-tegra20-slink.c
drivers/spi/spi.c
drivers/staging/comedi/drivers/s626.c
drivers/staging/zcache/Kconfig
drivers/target/target_core_transport.c
drivers/tty/serial/8250/8250_core.c [moved from drivers/tty/serial/8250/8250.c with 99% similarity]
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/Kconfig
drivers/tty/serial/8250/Makefile
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/xilinx_uartps.c
drivers/tty/vt/vc_screen.c
drivers/usb/core/hcd.c
drivers/usb/core/port.c
drivers/usb/core/usb-acpi.c
drivers/usb/gadget/Kconfig
drivers/usb/host/ehci-sched.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/phy/Kconfig
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/usb-serial.c
drivers/vhost/tcm_vhost.c
drivers/video/fbmon.c
drivers/video/mxsfb.c
drivers/video/omap/omapfb_main.c
drivers/video/omap2/displays/panel-tpo-td043mtea1.c
drivers/video/omap2/dss/dss_features.c
drivers/video/sh_mobile_lcdcfb.c
drivers/video/uvesafb.c
drivers/xen/Kconfig
drivers/xen/events.c
drivers/xen/fallback.c
drivers/xen/xen-acpi-processor.c
drivers/xen/xen-pciback/pci_stub.c
fs/block_dev.c
fs/btrfs/ctree.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ordered-data.c
fs/btrfs/qgroup.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/volumes.c
fs/dcache.c
fs/ext4/extents.c
fs/ext4/indirect.c
fs/gfs2/file.c
fs/gfs2/incore.h
fs/gfs2/lock_dlm.c
fs/gfs2/rgrp.c
fs/internal.h
fs/namespace.c
fs/nfs/blocklayout/blocklayoutdm.c
fs/nfs/idmap.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4proc.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
fs/nfsd/vfs.c
fs/pnode.c
fs/pnode.h
fs/proc/root.c
fs/read_write.c
fs/reiserfs/xattr.c
fs/splice.c
fs/sysfs/dir.c
fs/sysfs/mount.c
fs/ubifs/super.c
include/linux/compat.h
include/linux/debug_locks.h
include/linux/devfreq.h
include/linux/freezer.h
include/linux/fs_struct.h
include/linux/kvm_host.h
include/linux/kvm_types.h
include/linux/mfd/arizona/core.h
include/linux/mfd/arizona/registers.h
include/linux/mfd/max77693-private.h
include/linux/mfd/wm8994/pdata.h
include/linux/mm.h
include/linux/mman.h
include/linux/mount.h
include/linux/mxsfb.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/signal.h
include/linux/skbuff.h
include/linux/thermal.h
include/linux/udp.h
include/linux/usb/hcd.h
include/linux/user_namespace.h
include/net/flow_keys.h
include/net/ip_vs.h
include/net/ipip.h
include/scsi/libfc.h
include/sound/dmaengine_pcm.h
include/sound/soc-dai.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/tas5086.h [new file with mode: 0644]
include/sound/tegra_wm8903.h [deleted file]
include/uapi/linux/packet_diag.h
include/uapi/linux/unix_diag.h
include/xen/interface/io/blkif.h
include/xen/interface/physdev.h
ipc/mqueue.c
ipc/msg.c
kernel/exit.c
kernel/lockdep.c
kernel/pid_namespace.c
kernel/time/tick-broadcast.c
kernel/user.c
kernel/user_namespace.c
mm/fremap.c
mm/mlock.c
mm/mmap.c
mm/nommu.c
net/8021q/vlan.c
net/bluetooth/sco.c
net/bridge/br_fdb.c
net/core/dev.c
net/core/dev_addr_lists.c
net/core/flow.c
net/core/flow_dissector.c
net/core/rtnetlink.c
net/core/scm.c
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/ipconfig.c
net/ipv4/netfilter/Kconfig
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/ip6_input.c
net/ipv6/netfilter/ip6t_NPT.c
net/ipv6/udp.c
net/irda/af_irda.c
net/key/af_key.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_debugfs.c
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_ip6.c
net/l2tp/l2tp_netlink.c
net/l2tp/l2tp_ppp.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/ipvs/ip_vs_proto_sctp.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nfnetlink_acct.c
net/netfilter/nfnetlink_queue_core.c
net/netlink/genetlink.c
net/nfc/llcp/llcp.c
net/nfc/llcp/sock.c
net/sched/sch_cbq.c
net/sched/sch_fq_codel.c
net/sched/sch_generic.c
net/sunrpc/sched.c
net/unix/af_unix.c
net/vmw_vsock/af_vsock.c
net/vmw_vsock/vmci_transport.c
net/vmw_vsock/vsock_addr.c
net/vmw_vsock/vsock_addr.h
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/scan.c
net/wireless/sme.c
net/wireless/trace.h
net/wireless/wext-sme.c
net/xfrm/xfrm_replay.c
security/yama/yama_lsm.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_generic.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/au1x/ac97c.c
sound/soc/au1x/i2sc.c
sound/soc/au1x/psc-ac97.c
sound/soc/au1x/psc-i2s.c
sound/soc/blackfin/bf5xx-ac97.c
sound/soc/blackfin/bf5xx-i2s.c
sound/soc/blackfin/bf5xx-tdm.c
sound/soc/blackfin/bf6xx-i2s.c
sound/soc/cirrus/edb93xx.c
sound/soc/cirrus/ep93xx-ac97.c
sound/soc/cirrus/ep93xx-i2s.c
sound/soc/cirrus/ep93xx-pcm.c
sound/soc/cirrus/ep93xx-pcm.h [deleted file]
sound/soc/cirrus/simone.c
sound/soc/cirrus/snappercl15.c
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau1373.c
sound/soc/codecs/ak4104.c
sound/soc/codecs/ak5386.c [new file with mode: 0644]
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4271.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98090.c
sound/soc/codecs/si476x.c
sound/soc/codecs/tas5086.c [new file with mode: 0644]
sound/soc/codecs/wm0010.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2000.h
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5102.h
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm5110.h
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_adsp.h
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/davinci-i2s.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-pcm.c
sound/soc/davinci/davinci-pcm.h
sound/soc/davinci/davinci-vcif.c
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/imx-audmux.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/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/jz4740/jz4740-i2s.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/mid-x86/sst_platform.c
sound/soc/mid-x86/sst_platform.h
sound/soc/mxs/mxs-pcm.c
sound/soc/mxs/mxs-pcm.h
sound/soc/mxs/mxs-saif.c
sound/soc/nuc900/nuc900-ac97.c
sound/soc/omap/am3517evm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/mcbsp.c
sound/soc/omap/mcbsp.h
sound/soc/omap/n810.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-dmic.c
sound/soc/omap/omap-hdmi.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/omap/omap-pcm.h [deleted file]
sound/soc/omap/omap-twl4030.c
sound/soc/omap/omap3pandora.c
sound/soc/omap/osk5912.c
sound/soc/omap/rx51.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/s6000/s6000-i2s.c
sound/soc/samsung/Kconfig
sound/soc/samsung/ac97.c
sound/soc/samsung/goni_wm8994.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/idma.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/pcm.c
sound/soc/samsung/regs-ac97.h [moved from arch/arm/plat-samsung/include/plat/regs-ac97.h with 100% similarity]
sound/soc/samsung/regs-iis.h [moved from arch/arm/plat-samsung/include/plat/regs-iis.h with 100% similarity]
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c-i2s-v2.c
sound/soc/samsung/s3c-i2s-v2.h
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/samsung/spdif.c
sound/soc/sh/fsi.c
sound/soc/sh/hac.c
sound/soc/sh/migor.c
sound/soc/sh/siu_dai.c
sound/soc/sh/ssi.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-dmaengine-pcm.c
sound/soc/soc-io.c
sound/soc/spear/spdif_in.c
sound/soc/spear/spdif_out.c
sound/soc/spear/spear_pcm.c
sound/soc/tegra/tegra20_ac97.c
sound/soc/tegra/tegra20_ac97.h
sound/soc/tegra/tegra20_i2s.c
sound/soc/tegra/tegra20_i2s.h
sound/soc/tegra/tegra20_spdif.c
sound/soc/tegra/tegra20_spdif.h
sound/soc/tegra/tegra30_ahub.c
sound/soc/tegra/tegra30_ahub.h
sound/soc/tegra/tegra30_i2s.c
sound/soc/tegra/tegra30_i2s.h
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_asoc_utils.c
sound/soc/tegra/tegra_asoc_utils.h
sound/soc/tegra/tegra_pcm.c
sound/soc/tegra/tegra_pcm.h
sound/soc/tegra/tegra_wm8753.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/tegra/tegra_wm9712.c
sound/soc/tegra/trimslice.c
sound/soc/txx9/txx9aclc-ac97.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_dai.h
sound/soc/ux500/ux500_pcm.c
sound/soc/ux500/ux500_pcm.h
virt/kvm/kvm_main.c

diff --git a/Documentation/devicetree/bindings/sound/ak5386.txt b/Documentation/devicetree/bindings/sound/ak5386.txt
new file mode 100644 (file)
index 0000000..dc3914f
--- /dev/null
@@ -0,0 +1,19 @@
+AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+
+This device has no control interface.
+
+Required properties:
+
+  - compatible : "asahi-kasei,ak5386"
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset/power down pin.
+                If specified, it will be deasserted at probe time.
+
+Example:
+
+spdif: ak5386@0 {
+       compatible = "asahi-kasei,ak5386";
+       reset-gpio = <&gpio0 23>;
+};
index 1ac7b16..0e5c12c 100644 (file)
@@ -1,12 +1,22 @@
 NVIDIA Tegra30 AHUB (Audio Hub)
 
 Required properties:
-- compatible : "nvidia,tegra30-ahub"
+- compatible : "nvidia,tegra30-ahub", "nvidia,tegra114-ahub", etc.
 - reg : Should contain the register physical address and length for each of
-  the AHUB's APBIF registers and the AHUB's own registers.
+  the AHUB's register blocks.
+  - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks.
+  - Tegra114 requires an additional entry, for the APBIF2 register block.
 - interrupts : Should contain AHUB interrupt
-- nvidia,dma-request-selector : The Tegra DMA controller's phandle and
-  request selector for the first APBIF channel.
+- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each
+  entry contains the Tegra DMA controller's phandle and request selector.
+  If a single entry is present, the request selectors for the channels are
+  assumed to be contiguous, and increment from this value.
+  If multiple values are given, one value must be given per channel.
+- clocks : Must contain an entry for each required entry in clock-names.
+- clock-names : Must include the following entries:
+  - Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0,
+    dam1, dam2, spdif_in.
+  - Tegra114: Additionally requires amx, adx.
 - ranges : The bus address mapping for the configlink register bus.
   Can be empty since the mapping is 1:1.
 - #address-cells : For the configlink bus. Should be <1>;
@@ -25,7 +35,13 @@ ahub@70080000 {
        reg = <0x70080000 0x200 0x70080200 0x100>;
        interrupts = < 0 103 0x04 >;
        nvidia,dma-request-selector = <&apbdma 1>;
-
+       clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>,
+               <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>,
+               <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>,
+               <&tegra_car 110>, <&tegra_car 162>;
+       clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2",
+               "i2s3", "i2s4", "dam0", "dam1", "dam2",
+               "spdif_in";
        ranges;
        #address-cells = <1>;
        #size-cells = <1>;
diff --git a/Documentation/devicetree/bindings/sound/ti,tas5086.txt b/Documentation/devicetree/bindings/sound/ti,tas5086.txt
new file mode 100644 (file)
index 0000000..8ea4f5b
--- /dev/null
@@ -0,0 +1,32 @@
+Texas Instruments TAS5086 6-channel PWM Processor
+
+Required properties:
+
+ - compatible:         Should contain "ti,tas5086".
+ - reg:                        The i2c address. Should contain <0x1b>.
+
+Optional properties:
+
+ - reset-gpio:                 A GPIO spec to define which pin is connected to the
+                       chip's !RESET pin. If specified, the driver will
+                       assert a hardware reset at probe time.
+
+ - ti,charge-period:   This property should contain the time in microseconds
+                       that closely matches the external single-ended
+                       split-capacitor charge period. The hardware chip
+                       waits for this period of time before starting the
+                       PWM signals. This helps reduce pops and clicks.
+
+                       When not specified, the hardware default of 1300ms
+                       is retained.
+
+Examples:
+
+       i2c_bus {
+               tas5086@1b {
+                       compatible = "ti,tas5086";
+                       reg = <0x1b>;
+                       reset-gpio = <&gpio 23 0>;
+                       ti,charge-period = <156000>;
+               };
+       };
index f2a2488..9573d0c 100644 (file)
@@ -15,6 +15,13 @@ amemthresh - INTEGER
         enabled and the variable is automatically set to 2, otherwise
         the strategy is disabled and the variable is  set  to 1.
 
+backup_only - BOOLEAN
+       0 - disabled (default)
+       not 0 - enabled
+
+       If set, disable the director function while the server is
+       in backup mode to avoid packet loops for DR/TUN methods.
+
 conntrack - BOOLEAN
        0 - disabled (default)
        not 0 - enabled
index 4499bd9..95731a0 100644 (file)
@@ -890,9 +890,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
     enable_msi - Enable Message Signaled Interrupt (MSI) (default = off)
     power_save - Automatic power-saving timeout (in second, 0 =
                disable)
-    power_save_controller - Support runtime D3 of HD-audio controller
-               (-1 = on for supported chip (default), false = off,
-                true = force to on even for unsupported hardware)
+    power_save_controller - Reset HD-audio controller in power-saving mode
+               (default = on)
     align_buffer_size - Force rounding of buffer/period sizes to multiples
                      of 128 bytes. This is more efficient in terms of memory
                      access but isn't required by the HDA spec and prevents
index 4cf5fd3..c6108c3 100644 (file)
@@ -3242,6 +3242,12 @@ F:       Documentation/firmware_class/
 F:     drivers/base/firmware*.c
 F:     include/linux/firmware.h
 
+FLASHSYSTEM DRIVER (IBM FlashSystem 70/80 PCI SSD Flash Card)
+M:     Joshua Morris <josh.h.morris@us.ibm.com>
+M:     Philip Kelleher <pjk1939@linux.vnet.ibm.com>
+S:     Maintained
+F:     drivers/block/rsxx/
+
 FLOPPY DRIVER
 M:     Jiri Kosina <jkosina@suse.cz>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/floppy.git
@@ -5059,9 +5065,8 @@ S:        Maintained
 F:     drivers/net/ethernet/marvell/sk*
 
 MARVELL LIBERTAS WIRELESS DRIVER
-M:     Dan Williams <dcbw@redhat.com>
 L:     libertas-dev@lists.infradead.org
-S:     Maintained
+S:     Orphan
 F:     drivers/net/wireless/libertas/
 
 MARVELL MV643XX ETHERNET DRIVER
@@ -5563,6 +5568,7 @@ F:        include/uapi/linux/if_*
 F:     include/uapi/linux/netdevice.h
 
 NETXEN (1/10) GbE SUPPORT
+M:     Manish Chopra <manish.chopra@qlogic.com>
 M:     Sony Chacko <sony.chacko@qlogic.com>
 M:     Rajesh Borundia <rajesh.borundia@qlogic.com>
 L:     netdev@vger.kernel.org
@@ -5683,7 +5689,7 @@ S:        Maintained
 F:     arch/arm/*omap*/*clock*
 
 OMAP POWER MANAGEMENT SUPPORT
-M:     Kevin Hilman <khilman@ti.com>
+M:     Kevin Hilman <khilman@deeprootsystems.com>
 L:     linux-omap@vger.kernel.org
 S:     Maintained
 F:     arch/arm/*omap*/*pm*
@@ -5777,7 +5783,7 @@ F:        arch/arm/*omap*/usb*
 
 OMAP GPIO DRIVER
 M:     Santosh Shilimkar <santosh.shilimkar@ti.com>
-M:     Kevin Hilman <khilman@ti.com>
+M:     Kevin Hilman <khilman@deeprootsystems.com>
 L:     linux-omap@vger.kernel.org
 S:     Maintained
 F:     drivers/gpio/gpio-omap.c
@@ -6209,7 +6215,7 @@ F:        include/linux/power_supply.h
 F:     drivers/power/
 
 PNP SUPPORT
-M:     Adam Belay <abelay@mit.edu>
+M:     Rafael J. Wysocki <rafael.j.wysocki@intel.com>
 M:     Bjorn Helgaas <bhelgaas@google.com>
 S:     Maintained
 F:     drivers/pnp/
@@ -6551,12 +6557,6 @@ S:       Maintained
 F:     Documentation/blockdev/ramdisk.txt
 F:     drivers/block/brd.c
 
-RAMSAM DRIVER (IBM RamSan 70/80 PCI SSD Flash Card)
-M:     Joshua Morris <josh.h.morris@us.ibm.com>
-M:     Philip Kelleher <pjk1939@linux.vnet.ibm.com>
-S:     Maintained
-F:     drivers/block/rsxx/
-
 RANDOM NUMBER DRIVER
 M:     Theodore Ts'o" <tytso@mit.edu>
 S:     Maintained
@@ -6625,7 +6625,7 @@ S:        Supported
 F:     fs/reiserfs/
 
 REGISTER MAP ABSTRACTION
-M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
+M:     Mark Brown <broonie@kernel.org>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git
 S:     Supported
 F:     drivers/base/regmap/
@@ -7173,7 +7173,7 @@ F:        arch/arm/mach-s3c2410/bast-irq.c
 
 TI DAVINCI MACHINE SUPPORT
 M:     Sekhar Nori <nsekhar@ti.com>
-M:     Kevin Hilman <khilman@ti.com>
+M:     Kevin Hilman <khilman@deeprootsystems.com>
 L:     davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers)
 T:     git git://gitorious.org/linux-davinci/linux-davinci.git
 Q:     http://patchwork.kernel.org/project/linux-davinci/list/
@@ -7374,7 +7374,7 @@ F:        sound/
 
 SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
 M:     Liam Girdwood <lgirdwood@gmail.com>
-M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
+M:     Mark Brown <broonie@kernel.org>
 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
@@ -7463,7 +7463,7 @@ F:        drivers/clk/spear/
 
 SPI SUBSYSTEM
 M:     Grant Likely <grant.likely@secretlab.ca>
-M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
+M:     Mark Brown <broonie@kernel.org>
 L:     spi-devel-general@lists.sourceforge.net
 Q:     http://patchwork.kernel.org/project/spi-devel-general/list/
 T:     git git://git.secretlab.ca/git/linux-2.6.git
@@ -7706,9 +7706,10 @@ F:       include/linux/swiotlb.h
 
 SYNOPSYS ARC ARCHITECTURE
 M:     Vineet Gupta <vgupta@synopsys.com>
-L:     linux-snps-arc@vger.kernel.org
 S:     Supported
 F:     arch/arc/
+F:     Documentation/devicetree/bindings/arc/
+F:     drivers/tty/serial/arc-uart.c
 
 SYSV FILESYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
@@ -8707,7 +8708,7 @@ F:        drivers/scsi/vmw_pvscsi.h
 
 VOLTAGE AND CURRENT REGULATOR FRAMEWORK
 M:     Liam Girdwood <lrg@ti.com>
-M:     Mark Brown <broonie@opensource.wolfsonmicro.com>
+M:     Mark Brown <broonie@kernel.org>
 W:     http://opensource.wolfsonmicro.com/node/15
 W:     http://www.slimlogic.co.uk/?p=48
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/lrg/regulator.git
index 54d2b2a..6db672b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 9
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+EXTRAVERSION = -rc6
 NAME = Unicycling Gorilla
 
 # *DOCUMENTATION*
index 4759fe7..2cc3cc5 100644 (file)
@@ -12,7 +12,7 @@ NM := $(NM) -B
 
 LDFLAGS_vmlinux        := -static -N #-relax
 CHECKFLAGS     += -D__alpha__ -m64
-cflags-y       := -pipe -mno-fp-regs -ffixed-8 -msmall-data
+cflags-y       := -pipe -mno-fp-regs -ffixed-8
 cflags-y       += $(call cc-option, -fno-jump-tables)
 
 cpuflags-$(CONFIG_ALPHA_EV4)           := -mcpu=ev4
index 46cefbd..bae97eb 100644 (file)
@@ -26,7 +26,7 @@
 #define fd_disable_irq()        disable_irq(FLOPPY_IRQ)
 #define fd_cacheflush(addr,size) /* nothing */
 #define fd_request_irq()        request_irq(FLOPPY_IRQ, floppy_interrupt,\
-                                           IRQF_DISABLED, "floppy", NULL)
+                                           0, "floppy", NULL)
 #define fd_free_irq()           free_irq(FLOPPY_IRQ, NULL)
 
 #ifdef CONFIG_PCI
index 2872acc..7b2be25 100644 (file)
@@ -117,13 +117,6 @@ handle_irq(int irq)
                return;
        }
 
-       /*
-        * From here we must proceed with IPL_MAX. Note that we do not
-        * explicitly enable interrupts afterwards - some MILO PALcode
-        * (namely LX164 one) seems to have severe problems with RTI
-        * at IPL 0.
-        */
-       local_irq_disable();
        irq_enter();
        generic_handle_irq_desc(irq, desc);
        irq_exit();
index 772ddfd..f433fc1 100644 (file)
@@ -45,6 +45,14 @@ do_entInt(unsigned long type, unsigned long vector,
          unsigned long la_ptr, struct pt_regs *regs)
 {
        struct pt_regs *old_regs;
+
+       /*
+        * Disable interrupts during IRQ handling.
+        * Note that there is no matching local_irq_enable() due to
+        * severe problems with RTI at IPL0 and some MILO PALcode
+        * (namely LX164).
+        */
+       local_irq_disable();
        switch (type) {
        case 0:
 #ifdef CONFIG_SMP
@@ -62,7 +70,6 @@ do_entInt(unsigned long type, unsigned long vector,
          {
                long cpu;
 
-               local_irq_disable();
                smp_percpu_timer_interrupt(regs);
                cpu = smp_processor_id();
                if (cpu != boot_cpuid) {
@@ -222,7 +229,6 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
 
 struct irqaction timer_irqaction = {
        .handler        = timer_interrupt,
-       .flags          = IRQF_DISABLED,
        .name           = "timer",
 };
 
index 4d4c046..1383f86 100644 (file)
@@ -188,6 +188,10 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr)
 extern void free_reserved_mem(void *, void *);
 extern void pcibios_claim_one_bus(struct pci_bus *);
 
+static struct resource irongate_io = {
+       .name   = "Irongate PCI IO",
+       .flags  = IORESOURCE_IO,
+};
 static struct resource irongate_mem = {
        .name   = "Irongate PCI MEM",
        .flags  = IORESOURCE_MEM,
@@ -209,6 +213,7 @@ nautilus_init_pci(void)
 
        irongate = pci_get_bus_and_slot(0, 0);
        bus->self = irongate;
+       bus->resource[0] = &irongate_io;
        bus->resource[1] = &irongate_mem;
 
        pci_bus_size_bridges(bus);
index 5cf4a48..a53cf03 100644 (file)
@@ -280,15 +280,15 @@ titan_late_init(void)
         * all reported to the kernel as machine checks, so the handler
         * is a nop so it can be called to count the individual events.
         */
-       titan_request_irq(63+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(63+16, titan_intr_nop, 0,
                    "CChip Error", NULL);
-       titan_request_irq(62+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(62+16, titan_intr_nop, 0,
                    "PChip 0 H_Error", NULL);
-       titan_request_irq(61+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(61+16, titan_intr_nop, 0,
                    "PChip 1 H_Error", NULL);
-       titan_request_irq(60+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(60+16, titan_intr_nop, 0,
                    "PChip 0 C_Error", NULL);
-       titan_request_irq(59+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(59+16, titan_intr_nop, 0,
                    "PChip 1 C_Error", NULL);
 
        /* 
@@ -348,9 +348,9 @@ privateer_init_pci(void)
         * Hook a couple of extra err interrupts that the
         * common titan code won't.
         */
-       titan_request_irq(53+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(53+16, titan_intr_nop, 0,
                    "NMI", NULL);
-       titan_request_irq(50+16, titan_intr_nop, IRQF_DISABLED,
+       titan_request_irq(50+16, titan_intr_nop, 0,
                    "Temperature Warning", NULL);
 
        /*
index 31f77ae..45b8e0c 100644 (file)
@@ -126,7 +126,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg,
        int i;
 
        for_each_sg(sg, s, nents, i)
-               sg->dma_address = dma_map_page(dev, sg_page(s), s->offset,
+               s->dma_address = dma_map_page(dev, sg_page(s), s->offset,
                                               s->length, dir);
 
        return nents;
index f4c8d36..a262828 100644 (file)
@@ -72,7 +72,4 @@ extern int elf_check_arch(const struct elf32_hdr *);
  */
 #define ELF_PLATFORM   (NULL)
 
-#define SET_PERSONALITY(ex) \
-       set_personality(PER_LINUX | (current->personality & (~PER_MASK)))
-
 #endif
index 23daa32..eb2ae53 100644 (file)
  *-------------------------------------------------------------*/
 .macro SAVE_ALL_EXCEPTION   marker
 
-       st      \marker, [sp, 8]
+       st      \marker, [sp, 8]        /* orig_r8 */
        st      r0, [sp, 4]    /* orig_r0, needed only for sys calls */
 
        /* Restore r9 used to code the early prologue */
index f3c4934..4930957 100644 (file)
@@ -13,7 +13,7 @@
 
 #ifdef CONFIG_KGDB
 
-#include <asm/user.h>
+#include <asm/ptrace.h>
 
 /* to ensure compatibility with Linux 2.6.35, we don't implement the get/set
  * register API yet */
@@ -53,9 +53,7 @@ enum arc700_linux_regnums {
 };
 
 #else
-static inline void kgdb_trap(struct pt_regs *regs, int param)
-{
-}
+#define kgdb_trap(regs, param)
 #endif
 
 #endif /* __ARC_KGDB_H__ */
index 8ae783d..6179de7 100644 (file)
@@ -123,7 +123,7 @@ static inline long regs_return_value(struct pt_regs *regs)
 #define orig_r8_IS_SCALL               0x0001
 #define orig_r8_IS_SCALL_RESTARTED     0x0002
 #define orig_r8_IS_BRKPT               0x0004
-#define orig_r8_IS_EXCPN               0x0004
+#define orig_r8_IS_EXCPN               0x0008
 #define orig_r8_IS_IRQ1                        0x0010
 #define orig_r8_IS_IRQ2                        0x0020
 
index e53a534..dd785be 100644 (file)
@@ -16,8 +16,6 @@
 #include <linux/types.h>
 
 int sys_clone_wrapper(int, int, int, int, int);
-int sys_fork_wrapper(void);
-int sys_vfork_wrapper(void);
 int sys_cacheflush(uint32_t, uint32_t uint32_t);
 int sys_arc_settls(void *);
 int sys_arc_gettls(void);
index 6afa4f7..30333ce 100644 (file)
 */
 struct user_regs_struct {
 
-       struct scratch {
+       struct {
                long pad;
                long bta, lp_start, lp_end, lp_count;
                long status32, ret, blink, fp, gp;
                long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
                long sp;
        } scratch;
-       struct callee {
+       struct {
                long pad;
                long r25, r24, r23, r22, r21, r20;
                long r19, r18, r17, r16, r15, r14, r13;
index ef6800b..91eeab8 100644 (file)
@@ -452,7 +452,7 @@ tracesys:
        ; using ERET won't work since next-PC has already committed
        lr  r12, [efa]
        GET_CURR_TASK_FIELD_PTR   TASK_THREAD, r11
-       st  r12, [r11, THREAD_FAULT_ADDR]
+       st  r12, [r11, THREAD_FAULT_ADDR]       ; thread.fault_address
 
        ; PRE Sys Call Ptrace hook
        mov r0, sp                      ; pt_regs needed
@@ -792,31 +792,6 @@ ARC_EXIT ret_from_fork
 
 ;################### Special Sys Call Wrappers ##########################
 
-; TBD: call do_fork directly from here
-ARC_ENTRY sys_fork_wrapper
-       SAVE_CALLEE_SAVED_USER
-       bl  @sys_fork
-       DISCARD_CALLEE_SAVED_USER
-
-       GET_CURR_THR_INFO_FLAGS   r10
-       btst r10, TIF_SYSCALL_TRACE
-       bnz  tracesys_exit
-
-       b ret_from_system_call
-ARC_EXIT sys_fork_wrapper
-
-ARC_ENTRY sys_vfork_wrapper
-       SAVE_CALLEE_SAVED_USER
-       bl  @sys_vfork
-       DISCARD_CALLEE_SAVED_USER
-
-       GET_CURR_THR_INFO_FLAGS   r10
-       btst r10, TIF_SYSCALL_TRACE
-       bnz  tracesys_exit
-
-       b ret_from_system_call
-ARC_EXIT sys_vfork_wrapper
-
 ARC_ENTRY sys_clone_wrapper
        SAVE_CALLEE_SAVED_USER
        bl  @sys_clone
index 2888ba5..52bdc83 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/kgdb.h>
+#include <linux/sched.h>
 #include <asm/disasm.h>
 #include <asm/cacheflush.h>
 
index dc0f968..2d95ac0 100644 (file)
@@ -232,10 +232,8 @@ char *arc_extn_mumbojumbo(int cpu_id, char *buf, int len)
 
        n += scnprintf(buf + n, len - n, "\n");
 
-#ifdef _ASM_GENERIC_UNISTD_H
        n += scnprintf(buf + n, len - n,
-                      "OS ABI [v2]\t: asm-generic/{unistd,stat,fcntl}\n");
-#endif
+                      "OS ABI [v3]\t: no-legacy-syscalls\n");
 
        return buf;
 }
index f6bdd07..9d6c1ca 100644 (file)
@@ -6,8 +6,6 @@
 #include <asm/syscalls.h>
 
 #define sys_clone      sys_clone_wrapper
-#define sys_fork       sys_fork_wrapper
-#define sys_vfork      sys_vfork_wrapper
 
 #undef __SYSCALL
 #define __SYSCALL(nr, call) [nr] = (call),
index 13b7394..1cacda4 100644 (file)
@@ -1183,9 +1183,9 @@ config ARM_NR_BANKS
        default 8
 
 config IWMMXT
-       bool "Enable iWMMXt support"
+       bool "Enable iWMMXt support" if !CPU_PJ4
        depends on CPU_XSCALE || CPU_XSC3 || CPU_MOHAWK || CPU_PJ4
-       default y if PXA27x || PXA3xx || ARCH_MMP
+       default y if PXA27x || PXA3xx || ARCH_MMP || CPU_PJ4
        help
          Enable support for iWMMXt context switching at run time if
          running on a CPU that supports it.
@@ -1439,6 +1439,16 @@ config ARM_ERRATA_775420
         to deadlock. This workaround puts DSB before executing ISB if
         an abort may occur on cache maintenance.
 
+config ARM_ERRATA_798181
+       bool "ARM errata: TLBI/DSB failure on Cortex-A15"
+       depends on CPU_V7 && SMP
+       help
+         On Cortex-A15 (r0p0..r3p2) the TLBI*IS/DSB operations are not
+         adequately shooting down all use of the old entries. This
+         option enables the Linux kernel workaround for this erratum
+         which sends an IPI to the CPUs that are running the same ASID
+         as the one being invalidated.
+
 endmenu
 
 source "arch/arm/common/Kconfig"
index ecfcdba..9b31f43 100644 (file)
@@ -495,6 +495,7 @@ config DEBUG_IMX_UART_PORT
                                                DEBUG_IMX53_UART || \
                                                DEBUG_IMX6Q_UART
        default 1
+       depends on ARCH_MXC
        help
          Choose UART port on which kernel low-level debug messages
          should be output.
index dd0c57d..3234875 100644 (file)
@@ -54,7 +54,7 @@
                };
 
                mvsdio@d00d4000 {
-                       pinctrl-0 = <&sdio_pins2>;
+                       pinctrl-0 = <&sdio_pins3>;
                        pinctrl-names = "default";
                        status = "okay";
                        /*
index 8188d13..a195deb 100644 (file)
                                             "mpp50", "mpp51", "mpp52";
                              marvell,function = "sd0";
                        };
+
+                       sdio_pins3: sdio-pins3 {
+                             marvell,pins = "mpp48", "mpp49", "mpp50",
+                                            "mpp51", "mpp52", "mpp53";
+                             marvell,function = "sd0";
+                       };
                };
 
                gpio0: gpio@d0018100 {
index 9de9309..aaa63d0 100644 (file)
 
                prcmu: prcmu@80157000 {
                        compatible = "stericsson,db8500-prcmu";
-                       reg = <0x80157000 0x1000>;
-                       reg-names = "prcmu";
+                       reg = <0x80157000 0x1000>, <0x801b0000 0x8000>, <0x801b8000 0x1000>;
+                       reg-names = "prcmu", "prcmu-tcpm", "prcmu-tcdm";
                        interrupts = <0 47 0x4>;
                        #address-cells = <1>;
                        #size-cells = <1>;
index bd83b8f..c3573be 100644 (file)
@@ -77,6 +77,7 @@
                };
 
                nand@3000000 {
+                       chip-delay = <40>;
                        status = "okay";
 
                        partition@0 {
index 8aad00f..f7bec3b 100644 (file)
@@ -13,6 +13,9 @@
        compatible = "marvell,orion5x";
        interrupt-parent = <&intc>;
 
+       aliases {
+               gpio0 = &gpio0;
+       };
        intc: interrupt-controller {
                compatible = "marvell,orion-intc", "marvell,intc";
                interrupt-controller;
@@ -32,7 +35,9 @@
                        #gpio-cells = <2>;
                        gpio-controller;
                        reg = <0x10100 0x40>;
-                       ngpio = <32>;
+                       ngpios = <32>;
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
                        interrupts = <6>, <7>, <8>, <9>;
                };
 
@@ -91,7 +96,7 @@
                        reg = <0x90000 0x10000>,
                              <0xf2200000 0x800>;
                        reg-names = "regs", "sram";
-                       interrupts = <22>;
+                       interrupts = <28>;
                        status = "okay";
                };
        };
index 48d00a0..3d3f64d 100644 (file)
 
        spi@7000d800 {
                compatible = "nvidia,tegra20-slink";
-               reg = <0x7000d480 0x200>;
+               reg = <0x7000d800 0x200>;
                interrupts = <0 83 0x04>;
                nvidia,dma-request-selector = <&apbdma 17>;
                #address-cells = <1>;
index 9d87a3f..dbf46c2 100644 (file)
 
        spi@7000d800 {
                compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink";
-               reg = <0x7000d480 0x200>;
+               reg = <0x7000d800 0x200>;
                interrupts = <0 83 0x04>;
                nvidia,dma-request-selector = <&apbdma 17>;
                #address-cells = <1>;
index 720799f..dff714d 100644 (file)
@@ -24,7 +24,7 @@ extern struct arm_delay_ops {
        void (*delay)(unsigned long);
        void (*const_udelay)(unsigned long);
        void (*udelay)(unsigned long);
-       bool const_clock;
+       unsigned long ticks_per_jiffy;
 } arm_delay_ops;
 
 #define __delay(n)             arm_delay_ops.delay(n)
index 8c5e828..91b99ab 100644 (file)
@@ -41,6 +41,13 @@ extern void kunmap_high(struct page *page);
 #endif
 #endif
 
+/*
+ * Needed to be able to broadcast the TLB invalidation for kmap.
+ */
+#ifdef CONFIG_ARM_ERRATA_798181
+#undef ARCH_NEEDS_KMAP_HIGH_GET
+#endif
+
 #ifdef ARCH_NEEDS_KMAP_HIGH_GET
 extern void *kmap_high_get(struct page *page);
 #else
index 863a661..a7b85e0 100644 (file)
@@ -27,6 +27,8 @@ void __check_vmalloc_seq(struct mm_struct *mm);
 void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
 #define init_new_context(tsk,mm)       ({ atomic64_set(&mm->context.id, 0); 0; })
 
+DECLARE_PER_CPU(atomic64_t, active_asids);
+
 #else  /* !CONFIG_CPU_HAS_ASID */
 
 #ifdef CONFIG_MMU
index 4db8c88..9e9c041 100644 (file)
@@ -450,6 +450,21 @@ static inline void local_flush_bp_all(void)
                isb();
 }
 
+#ifdef CONFIG_ARM_ERRATA_798181
+static inline void dummy_flush_tlb_a15_erratum(void)
+{
+       /*
+        * Dummy TLBIMVAIS. Using the unmapped address 0 and ASID 0.
+        */
+       asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (0));
+       dsb();
+}
+#else
+static inline void dummy_flush_tlb_a15_erratum(void)
+{
+}
+#endif
+
 /*
  *     flush_pmd_entry
  *
index 3248cde..fefd7f9 100644 (file)
@@ -276,7 +276,13 @@ ENDPROC(ftrace_graph_caller_old)
  */
 
 .macro mcount_enter
+/*
+ * This pad compensates for the push {lr} at the call site.  Note that we are
+ * unable to unwind through a function which does not otherwise save its lr.
+ */
+ UNWIND(.pad   #4)
        stmdb   sp!, {r0-r3, lr}
+ UNWIND(.save  {r0-r3, lr})
 .endm
 
 .macro mcount_get_lr reg
@@ -289,6 +295,7 @@ ENDPROC(ftrace_graph_caller_old)
 .endm
 
 ENTRY(__gnu_mcount_nc)
+UNWIND(.fnstart)
 #ifdef CONFIG_DYNAMIC_FTRACE
        mov     ip, lr
        ldmia   sp!, {lr}
@@ -296,17 +303,22 @@ ENTRY(__gnu_mcount_nc)
 #else
        __mcount
 #endif
+UNWIND(.fnend)
 ENDPROC(__gnu_mcount_nc)
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 ENTRY(ftrace_caller)
+UNWIND(.fnstart)
        __ftrace_caller
+UNWIND(.fnend)
 ENDPROC(ftrace_caller)
 #endif
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 ENTRY(ftrace_graph_caller)
+UNWIND(.fnstart)
        __ftrace_graph_caller
+UNWIND(.fnend)
 ENDPROC(ftrace_graph_caller)
 #endif
 
index e0eb9a1..8bac553 100644 (file)
@@ -267,7 +267,7 @@ __create_page_tables:
        addne   r6, r6, #1 << SECTION_SHIFT
        strne   r6, [r3]
 
-#if defined(CONFIG_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8)
+#if defined(CONFIG_ARM_LPAE) && defined(CONFIG_CPU_ENDIAN_BE8)
        sub     r4, r4, #4                      @ Fixup page table pointer
                                                @ for 64-bit descriptors
 #endif
index 96093b7..5dc1aa6 100644 (file)
@@ -966,7 +966,7 @@ static void reset_ctrl_regs(void *unused)
        }
 
        if (err) {
-               pr_warning("CPU %d debug is powered down!\n", cpu);
+               pr_warn_once("CPU %d debug is powered down!\n", cpu);
                cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu));
                return;
        }
@@ -987,7 +987,7 @@ clear_vcr:
        isb();
 
        if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) {
-               pr_warning("CPU %d failed to disable vector catch\n", cpu);
+               pr_warn_once("CPU %d failed to disable vector catch\n", cpu);
                return;
        }
 
@@ -1007,7 +1007,7 @@ clear_vcr:
        }
 
        if (cpumask_intersects(&debug_err_mask, cpumask_of(cpu))) {
-               pr_warning("CPU %d failed to clear debug register pairs\n", cpu);
+               pr_warn_once("CPU %d failed to clear debug register pairs\n", cpu);
                return;
        }
 
index 3f6cbb2..d343a6c 100644 (file)
@@ -353,6 +353,23 @@ void __init early_print(const char *str, ...)
        printk("%s", buf);
 }
 
+static void __init cpuid_init_hwcaps(void)
+{
+       unsigned int divide_instrs;
+
+       if (cpu_architecture() < CPU_ARCH_ARMv7)
+               return;
+
+       divide_instrs = (read_cpuid_ext(CPUID_EXT_ISAR0) & 0x0f000000) >> 24;
+
+       switch (divide_instrs) {
+       case 2:
+               elf_hwcap |= HWCAP_IDIVA;
+       case 1:
+               elf_hwcap |= HWCAP_IDIVT;
+       }
+}
+
 static void __init feat_v6_fixup(void)
 {
        int id = read_cpuid_id();
@@ -483,8 +500,11 @@ static void __init setup_processor(void)
        snprintf(elf_platform, ELF_PLATFORM_SIZE, "%s%c",
                 list->elf_name, ENDIANNESS);
        elf_hwcap = list->elf_hwcap;
+
+       cpuid_init_hwcaps();
+
 #ifndef CONFIG_ARM_THUMB
-       elf_hwcap &= ~HWCAP_THUMB;
+       elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
 #endif
 
        feat_v6_fixup();
@@ -524,7 +544,7 @@ int __init arm_add_memory(phys_addr_t start, phys_addr_t size)
        size -= start & ~PAGE_MASK;
        bank->start = PAGE_ALIGN(start);
 
-#ifndef CONFIG_LPAE
+#ifndef CONFIG_ARM_LPAE
        if (bank->start + size < bank->start) {
                printk(KERN_CRIT "Truncating memory at 0x%08llx to fit in "
                        "32-bit physical address space\n", (long long)start);
index 79078ed..1f2cccc 100644 (file)
@@ -673,9 +673,6 @@ static int cpufreq_callback(struct notifier_block *nb,
        if (freq->flags & CPUFREQ_CONST_LOOPS)
                return NOTIFY_OK;
 
-       if (arm_delay_ops.const_clock)
-               return NOTIFY_OK;
-
        if (!per_cpu(l_p_j_ref, cpu)) {
                per_cpu(l_p_j_ref, cpu) =
                        per_cpu(cpu_data, cpu).loops_per_jiffy;
index bd03005..e82e1d2 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <asm/smp_plat.h>
 #include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
 
 /**********************************************************************/
 
@@ -69,12 +70,72 @@ 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();
+}
+
+static void broadcast_tlb_a15_erratum(void)
+{
+       if (!erratum_a15_798181())
+               return;
+
+       dummy_flush_tlb_a15_erratum();
+       smp_call_function_many(cpu_online_mask, ipi_flush_tlb_a15_erratum,
+                              NULL, 1);
+}
+
+static void broadcast_tlb_mm_a15_erratum(struct mm_struct *mm)
+{
+       int cpu;
+       cpumask_t mask = { CPU_BITS_NONE };
+
+       if (!erratum_a15_798181())
+               return;
+
+       dummy_flush_tlb_a15_erratum();
+       for_each_online_cpu(cpu) {
+               if (cpu == smp_processor_id())
+                       continue;
+               /*
+                * We only need to send an IPI if the other CPUs are running
+                * the same ASID as the one being invalidated. There is no
+                * need for locking around the active_asids check since the
+                * switch_mm() function has at least one dmb() (as required by
+                * this workaround) in case a context switch happens on
+                * another CPU after the condition below.
+                */
+               if (atomic64_read(&mm->context.id) ==
+                   atomic64_read(&per_cpu(active_asids, cpu)))
+                       cpumask_set_cpu(cpu, &mask);
+       }
+       smp_call_function_many(&mask, ipi_flush_tlb_a15_erratum, NULL, 1);
+}
+
 void flush_tlb_all(void)
 {
        if (tlb_ops_need_broadcast())
                on_each_cpu(ipi_flush_tlb_all, NULL, 1);
        else
                local_flush_tlb_all();
+       broadcast_tlb_a15_erratum();
 }
 
 void flush_tlb_mm(struct mm_struct *mm)
@@ -83,6 +144,7 @@ void flush_tlb_mm(struct mm_struct *mm)
                on_each_cpu_mask(mm_cpumask(mm), ipi_flush_tlb_mm, mm, 1);
        else
                local_flush_tlb_mm(mm);
+       broadcast_tlb_mm_a15_erratum(mm);
 }
 
 void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
@@ -95,6 +157,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
                                        &ta, 1);
        } else
                local_flush_tlb_page(vma, uaddr);
+       broadcast_tlb_mm_a15_erratum(vma->vm_mm);
 }
 
 void flush_tlb_kernel_page(unsigned long kaddr)
@@ -105,6 +168,7 @@ void flush_tlb_kernel_page(unsigned long kaddr)
                on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1);
        } else
                local_flush_tlb_kernel_page(kaddr);
+       broadcast_tlb_a15_erratum();
 }
 
 void flush_tlb_range(struct vm_area_struct *vma,
@@ -119,6 +183,7 @@ void flush_tlb_range(struct vm_area_struct *vma,
                                        &ta, 1);
        } else
                local_flush_tlb_range(vma, start, end);
+       broadcast_tlb_mm_a15_erratum(vma->vm_mm);
 }
 
 void flush_tlb_kernel_range(unsigned long start, unsigned long end)
@@ -130,6 +195,7 @@ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
                on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1);
        } else
                local_flush_tlb_kernel_range(start, end);
+       broadcast_tlb_a15_erratum();
 }
 
 void flush_bp_all(void)
index c9a1731..0e4cfe1 100644 (file)
@@ -883,8 +883,7 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
                          lr, irq, vgic_cpu->vgic_lr[lr]);
                BUG_ON(!test_bit(lr, vgic_cpu->lr_used));
                vgic_cpu->vgic_lr[lr] |= GICH_LR_PENDING_BIT;
-
-               goto out;
+               return true;
        }
 
        /* Try to use another LR for this interrupt */
@@ -898,7 +897,6 @@ static bool vgic_queue_irq(struct kvm_vcpu *vcpu, u8 sgi_source_id, int irq)
        vgic_cpu->vgic_irq_lr_map[irq] = lr;
        set_bit(lr, vgic_cpu->lr_used);
 
-out:
        if (!vgic_irq_is_edge(vcpu, irq))
                vgic_cpu->vgic_lr[lr] |= GICH_LR_EOI;
 
@@ -1018,21 +1016,6 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 
        kvm_debug("MISR = %08x\n", vgic_cpu->vgic_misr);
 
-       /*
-        * We do not need to take the distributor lock here, since the only
-        * action we perform is clearing the irq_active_bit for an EOIed
-        * level interrupt.  There is a potential race with
-        * the queuing of an interrupt in __kvm_vgic_flush_hwstate(), where we
-        * check if the interrupt is already active. Two possibilities:
-        *
-        * - The queuing is occurring on the same vcpu: cannot happen,
-        *   as we're already in the context of this vcpu, and
-        *   executing the handler
-        * - The interrupt has been migrated to another vcpu, and we
-        *   ignore this interrupt for this run. Big deal. It is still
-        *   pending though, and will get considered when this vcpu
-        *   exits.
-        */
        if (vgic_cpu->vgic_misr & GICH_MISR_EOI) {
                /*
                 * Some level interrupts have been EOIed. Clear their
@@ -1054,6 +1037,13 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
                        } else {
                                vgic_cpu_irq_clear(vcpu, irq);
                        }
+
+                       /*
+                        * Despite being EOIed, the LR may not have
+                        * been marked as empty.
+                        */
+                       set_bit(lr, (unsigned long *)vgic_cpu->vgic_elrsr);
+                       vgic_cpu->vgic_lr[lr] &= ~GICH_LR_ACTIVE_BIT;
                }
        }
 
@@ -1064,9 +1054,8 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 }
 
 /*
- * Sync back the VGIC state after a guest run. We do not really touch
- * the distributor here (the irq_pending_on_cpu bit is safe to set),
- * so there is no need for taking its lock.
+ * Sync back the VGIC state after a guest run. The distributor lock is
+ * needed so we don't get preempted in the middle of the state processing.
  */
 static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
@@ -1112,10 +1101,14 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
        if (!irqchip_in_kernel(vcpu->kvm))
                return;
 
+       spin_lock(&dist->lock);
        __kvm_vgic_sync_hwstate(vcpu);
+       spin_unlock(&dist->lock);
 }
 
 int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
index 6b93f6a..64dbfa5 100644 (file)
@@ -58,7 +58,7 @@ static void __timer_delay(unsigned long cycles)
 static void __timer_const_udelay(unsigned long xloops)
 {
        unsigned long long loops = xloops;
-       loops *= loops_per_jiffy;
+       loops *= arm_delay_ops.ticks_per_jiffy;
        __timer_delay(loops >> UDELAY_SHIFT);
 }
 
@@ -73,11 +73,13 @@ void __init register_current_timer_delay(const struct delay_timer *timer)
                pr_info("Switching to timer-based delay loop\n");
                delay_timer                     = timer;
                lpj_fine                        = timer->freq / HZ;
-               loops_per_jiffy                 = lpj_fine;
+
+               /* cpufreq may scale loops_per_jiffy, so keep a private copy */
+               arm_delay_ops.ticks_per_jiffy   = lpj_fine;
                arm_delay_ops.delay             = __timer_delay;
                arm_delay_ops.const_udelay      = __timer_const_udelay;
                arm_delay_ops.udelay            = __timer_udelay;
-               arm_delay_ops.const_clock       = true;
+
                delay_calibrated                = true;
        } else {
                pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
index e698f26..52e4bb5 100644 (file)
 
 static struct map_desc cns3xxx_io_desc[] __initdata = {
        {
-               .virtual        = CNS3XXX_TC11MP_TWD_BASE_VIRT,
-               .pfn            = __phys_to_pfn(CNS3XXX_TC11MP_TWD_BASE),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT,
-               .pfn            = __phys_to_pfn(CNS3XXX_TC11MP_GIC_CPU_BASE),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT,
-               .pfn            = __phys_to_pfn(CNS3XXX_TC11MP_GIC_DIST_BASE),
-               .length         = SZ_4K,
+               .virtual        = CNS3XXX_TC11MP_SCU_BASE_VIRT,
+               .pfn            = __phys_to_pfn(CNS3XXX_TC11MP_SCU_BASE),
+               .length         = SZ_8K,
                .type           = MT_DEVICE,
        }, {
                .virtual        = CNS3XXX_TIMER1_2_3_BASE_VIRT,
index 191c8e5..b1021aa 100644 (file)
 #define RTC_INTR_STS_OFFSET                    0x34
 
 #define CNS3XXX_MISC_BASE                      0x76000000      /* Misc Control */
-#define CNS3XXX_MISC_BASE_VIRT                 0xFFF07000      /* Misc Control */
+#define CNS3XXX_MISC_BASE_VIRT                 0xFB000000      /* Misc Control */
 
 #define CNS3XXX_PM_BASE                                0x77000000      /* Power Management Control */
-#define CNS3XXX_PM_BASE_VIRT                   0xFFF08000
+#define CNS3XXX_PM_BASE_VIRT                   0xFB001000
 
 #define PM_CLK_GATE_OFFSET                     0x00
 #define PM_SOFT_RST_OFFSET                     0x04
 #define PM_PLL_HM_PD_OFFSET                    0x1C
 
 #define CNS3XXX_UART0_BASE                     0x78000000      /* UART 0 */
-#define CNS3XXX_UART0_BASE_VIRT                        0xFFF09000
+#define CNS3XXX_UART0_BASE_VIRT                        0xFB002000
 
 #define CNS3XXX_UART1_BASE                     0x78400000      /* UART 1 */
 #define CNS3XXX_UART1_BASE_VIRT                        0xFFF0A000
 #define CNS3XXX_I2S_BASE_VIRT                  0xFFF10000
 
 #define CNS3XXX_TIMER1_2_3_BASE                        0x7C800000      /* Timer */
-#define CNS3XXX_TIMER1_2_3_BASE_VIRT           0xFFF10800
+#define CNS3XXX_TIMER1_2_3_BASE_VIRT           0xFB003000
 
 #define TIMER1_COUNTER_OFFSET                  0x00
 #define TIMER1_AUTO_RELOAD_OFFSET              0x04
  * Testchip peripheral and fpga gic regions
  */
 #define CNS3XXX_TC11MP_SCU_BASE                        0x90000000      /* IRQ, Test chip */
-#define CNS3XXX_TC11MP_SCU_BASE_VIRT           0xFF000000
+#define CNS3XXX_TC11MP_SCU_BASE_VIRT           0xFB004000
 
 #define CNS3XXX_TC11MP_GIC_CPU_BASE            0x90000100      /* Test chip interrupt controller CPU interface */
-#define CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT       0xFF000100
+#define CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT       (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x100)
 
 #define CNS3XXX_TC11MP_TWD_BASE                        0x90000600
-#define CNS3XXX_TC11MP_TWD_BASE_VIRT           0xFF000600
+#define CNS3XXX_TC11MP_TWD_BASE_VIRT           (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x600)
 
 #define CNS3XXX_TC11MP_GIC_DIST_BASE           0x90001000      /* Test chip interrupt controller distributor */
-#define CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT      0xFF001000
+#define CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT      (CNS3XXX_TC11MP_SCU_BASE_VIRT + 0x1000)
 
 #define CNS3XXX_TC11MP_L220_BASE               0x92002000      /* L220 registers */
 #define CNS3XXX_TC11MP_L220_BASE_VIRT          0xFF002000
index d2afb4d..b5cc77d 100644 (file)
@@ -47,9 +47,13 @@ static void __raw_writel(unsigned int value, unsigned int ptr)
 
 static inline void putc(int c)
 {
-       /* Transmit fifo not full?  */
-       while (__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF)
-               ;
+       int i;
+
+       for (i = 0; i < 10000; i++) {
+               /* Transmit fifo not full? */
+               if (!(__raw_readb(PHYS_UART_FLAG) & UART_FLAG_TXFF))
+                       break;
+       }
 
        __raw_writeb(c, PHYS_UART_DATA);
 }
index 5a800bf..5bf4a97 100644 (file)
@@ -110,6 +110,8 @@ void tzic_handle_irq(struct pt_regs *);
 
 extern void imx_enable_cpu(int cpu, bool enable);
 extern void imx_set_cpu_jump(int cpu, void *jump_addr);
+extern u32 imx_get_cpu_arg(int cpu);
+extern void imx_set_cpu_arg(int cpu, u32 arg);
 extern void v7_cpu_resume(void);
 extern u32 *pl310_get_save_ptr(void);
 #ifdef CONFIG_SMP
index 7bc5fe1..361a253 100644 (file)
@@ -46,11 +46,23 @@ static inline void cpu_enter_lowpower(void)
 void imx_cpu_die(unsigned int cpu)
 {
        cpu_enter_lowpower();
+       /*
+        * We use the cpu jumping argument register to sync with
+        * imx_cpu_kill() which is running on cpu0 and waiting for
+        * the register being cleared to kill the cpu.
+        */
+       imx_set_cpu_arg(cpu, ~0);
        cpu_do_idle();
 }
 
 int imx_cpu_kill(unsigned int cpu)
 {
+       unsigned long timeout = jiffies + msecs_to_jiffies(50);
+
+       while (imx_get_cpu_arg(cpu) == 0)
+               if (time_after(jiffies, timeout))
+                       return 0;
        imx_enable_cpu(cpu, false);
+       imx_set_cpu_arg(cpu, 0);
        return 1;
 }
index e15f155..09a742f 100644 (file)
@@ -43,6 +43,18 @@ void imx_set_cpu_jump(int cpu, void *jump_addr)
                       src_base + SRC_GPR1 + cpu * 8);
 }
 
+u32 imx_get_cpu_arg(int cpu)
+{
+       cpu = cpu_logical_map(cpu);
+       return readl_relaxed(src_base + SRC_GPR1 + cpu * 8 + 4);
+}
+
+void imx_set_cpu_arg(int cpu, u32 arg)
+{
+       cpu = cpu_logical_map(cpu);
+       writel_relaxed(arg, src_base + SRC_GPR1 + cpu * 8 + 4);
+}
+
 void imx_src_prepare_restart(void)
 {
        u32 val;
index 1c6e736..08dd739 100644 (file)
@@ -53,6 +53,8 @@ static struct mv_sata_platform_data guruplug_sata_data = {
 
 static struct mvsdio_platform_data guruplug_mvsdio_data = {
        /* unfortunately the CD signal has not been connected */
+       .gpio_card_detect = -1,
+       .gpio_write_protect = -1,
 };
 
 static struct gpio_led guruplug_led_pins[] = {
index 8ddd69f..6a6eb54 100644 (file)
@@ -55,6 +55,7 @@ static struct mv_sata_platform_data openrd_sata_data = {
 
 static struct mvsdio_platform_data openrd_mvsdio_data = {
        .gpio_card_detect = 29, /* MPP29 used as SD card detect */
+       .gpio_write_protect = -1,
 };
 
 static unsigned int openrd_mpp_config[] __initdata = {
index c7d93b4..d242231 100644 (file)
@@ -69,6 +69,7 @@ static struct mv_sata_platform_data rd88f6281_sata_data = {
 
 static struct mvsdio_platform_data rd88f6281_mvsdio_data = {
        .gpio_card_detect = 28,
+       .gpio_write_protect = -1,
 };
 
 static unsigned int rd88f6281_mpp_config[] __initdata = {
index 2969027..f9fd77e 100644 (file)
@@ -62,7 +62,10 @@ static int msm_timer_set_next_event(unsigned long cycles,
 {
        u32 ctrl = readl_relaxed(event_base + TIMER_ENABLE);
 
-       writel_relaxed(0, event_base + TIMER_CLEAR);
+       ctrl &= ~TIMER_ENABLE_EN;
+       writel_relaxed(ctrl, event_base + TIMER_ENABLE);
+
+       writel_relaxed(ctrl, event_base + TIMER_CLEAR);
        writel_relaxed(cycles, event_base + TIMER_MATCH_VAL);
        writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE);
        return 0;
index 274ff58..6a9195e 100644 (file)
@@ -44,6 +44,8 @@
 
 #define ARMADA_370_XP_MAX_PER_CPU_IRQS         (28)
 
+#define ARMADA_370_XP_TIMER0_PER_CPU_IRQ       (5)
+
 #define ACTIVE_DOORBELLS                       (8)
 
 static DEFINE_RAW_SPINLOCK(irq_controller_lock);
@@ -62,7 +64,7 @@ static void armada_370_xp_irq_mask(struct irq_data *d)
 #ifdef CONFIG_SMP
        irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
-       if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
+       if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
                writel(hwirq, main_int_base +
                                ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS);
        else
@@ -79,7 +81,7 @@ static void armada_370_xp_irq_unmask(struct irq_data *d)
 #ifdef CONFIG_SMP
        irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
-       if (hwirq > ARMADA_370_XP_MAX_PER_CPU_IRQS)
+       if (hwirq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
                writel(hwirq, main_int_base +
                                ARMADA_370_XP_INT_SET_ENABLE_OFFS);
        else
@@ -147,7 +149,7 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h,
        writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS);
        irq_set_status_flags(virq, IRQ_LEVEL);
 
-       if (hw < ARMADA_370_XP_MAX_PER_CPU_IRQS) {
+       if (hw == ARMADA_370_XP_TIMER0_PER_CPU_IRQ) {
                irq_set_percpu_devid(virq);
                irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip,
                                        handle_percpu_devid_irq);
index 3218f1f..e7b781d 100644 (file)
@@ -41,8 +41,6 @@ static struct fb_videomode mx23evk_video_modes[] = {
                .lower_margin   = 4,
                .hsync_len      = 1,
                .vsync_len      = 1,
-               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT |
-                                 FB_SYNC_DOTCLK_FAILING_ACT,
        },
 };
 
@@ -59,8 +57,6 @@ static struct fb_videomode mx28evk_video_modes[] = {
                .lower_margin   = 10,
                .hsync_len      = 10,
                .vsync_len      = 10,
-               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT |
-                                 FB_SYNC_DOTCLK_FAILING_ACT,
        },
 };
 
@@ -77,7 +73,6 @@ static struct fb_videomode m28evk_video_modes[] = {
                .lower_margin   = 45,
                .hsync_len      = 1,
                .vsync_len      = 1,
-               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT,
        },
 };
 
@@ -94,9 +89,7 @@ static struct fb_videomode apx4devkit_video_modes[] = {
                .lower_margin   = 13,
                .hsync_len      = 48,
                .vsync_len      = 3,
-               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT |
-                                 FB_SYNC_DATA_ENABLE_HIGH_ACT |
-                                 FB_SYNC_DOTCLK_FAILING_ACT,
+               .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
        },
 };
 
@@ -113,9 +106,7 @@ static struct fb_videomode apf28dev_video_modes[] = {
                .lower_margin = 0x15,
                .hsync_len = 64,
                .vsync_len = 4,
-               .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT |
-                               FB_SYNC_DATA_ENABLE_HIGH_ACT |
-                               FB_SYNC_DOTCLK_FAILING_ACT,
+               .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
        },
 };
 
@@ -132,7 +123,6 @@ static struct fb_videomode cfa10049_video_modes[] = {
                .lower_margin   = 2,
                .hsync_len      = 15,
                .vsync_len      = 15,
-               .sync           = FB_SYNC_DATA_ENABLE_HIGH_ACT
        },
 };
 
@@ -259,6 +249,8 @@ static void __init imx23_evk_init(void)
        mxsfb_pdata.mode_count = ARRAY_SIZE(mx23evk_video_modes);
        mxsfb_pdata.default_bpp = 32;
        mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
+       mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
+                               MXSFB_SYNC_DOTCLK_FAILING_ACT;
 }
 
 static inline void enable_clk_enet_out(void)
@@ -278,6 +270,8 @@ static void __init imx28_evk_init(void)
        mxsfb_pdata.mode_count = ARRAY_SIZE(mx28evk_video_modes);
        mxsfb_pdata.default_bpp = 32;
        mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
+       mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
+                               MXSFB_SYNC_DOTCLK_FAILING_ACT;
 
        mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0);
 }
@@ -297,6 +291,7 @@ static void __init m28evk_init(void)
        mxsfb_pdata.mode_count = ARRAY_SIZE(m28evk_video_modes);
        mxsfb_pdata.default_bpp = 16;
        mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT;
+       mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
 }
 
 static void __init sc_sps1_init(void)
@@ -322,6 +317,8 @@ static void __init apx4devkit_init(void)
        mxsfb_pdata.mode_count = ARRAY_SIZE(apx4devkit_video_modes);
        mxsfb_pdata.default_bpp = 32;
        mxsfb_pdata.ld_intf_width = STMLCDIF_24BIT;
+       mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
+                               MXSFB_SYNC_DOTCLK_FAILING_ACT;
 }
 
 #define ENET0_MDC__GPIO_4_0    MXS_GPIO_NR(4, 0)
@@ -407,6 +404,7 @@ static void __init cfa10049_init(void)
        mxsfb_pdata.mode_count = ARRAY_SIZE(cfa10049_video_modes);
        mxsfb_pdata.default_bpp = 32;
        mxsfb_pdata.ld_intf_width = STMLCDIF_18BIT;
+       mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT;
 }
 
 static void __init cfa10037_init(void)
@@ -423,6 +421,8 @@ static void __init apf28_init(void)
        mxsfb_pdata.mode_count = ARRAY_SIZE(apf28dev_video_modes);
        mxsfb_pdata.default_bpp = 16;
        mxsfb_pdata.ld_intf_width = STMLCDIF_16BIT;
+       mxsfb_pdata.sync = MXSFB_SYNC_DATA_ENABLE_HIGH_ACT |
+                               MXSFB_SYNC_DOTCLK_FAILING_ACT;
 }
 
 static void __init mxs_machine_init(void)
index cb7c6ae..6c4f766 100644 (file)
@@ -538,15 +538,6 @@ static struct clk usb_hhc_ck16xx = {
 };
 
 static struct clk usb_dc_ck = {
-       .name           = "usb_dc_ck",
-       .ops            = &clkops_generic,
-       /* Direct from ULPD, no parent */
-       .rate           = 48000000,
-       .enable_reg     = OMAP1_IO_ADDRESS(SOFT_REQ_REG),
-       .enable_bit     = USB_REQ_EN_SHIFT,
-};
-
-static struct clk usb_dc_ck7xx = {
        .name           = "usb_dc_ck",
        .ops            = &clkops_generic,
        /* Direct from ULPD, no parent */
@@ -727,8 +718,7 @@ static struct omap_clk omap_clks[] = {
        CLK(NULL,       "usb_clko",     &usb_clko,      CK_16XX | CK_1510 | CK_310),
        CLK(NULL,       "usb_hhc_ck",   &usb_hhc_ck1510, CK_1510 | CK_310),
        CLK(NULL,       "usb_hhc_ck",   &usb_hhc_ck16xx, CK_16XX),
-       CLK(NULL,       "usb_dc_ck",    &usb_dc_ck,     CK_16XX),
-       CLK(NULL,       "usb_dc_ck",    &usb_dc_ck7xx,  CK_7XX),
+       CLK(NULL,       "usb_dc_ck",    &usb_dc_ck,     CK_16XX | CK_7XX),
        CLK(NULL,       "mclk",         &mclk_1510,     CK_1510 | CK_310),
        CLK(NULL,       "mclk",         &mclk_16xx,     CK_16XX),
        CLK(NULL,       "bclk",         &bclk_1510,     CK_1510 | CK_310),
index 3d58f33..0c6834a 100644 (file)
  */
 #define OMAP4_DPLL_ABE_DEFFREQ                         98304000
 
+/*
+ * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section
+ * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred
+ * locked frequency for the USB DPLL is 960MHz.
+ */
+#define OMAP4_DPLL_USB_DEFFREQ                         960000000
+
 /* Root clocks */
 
 DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0);
@@ -1011,6 +1018,10 @@ DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel,
                    OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK,
                    hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops);
 
+DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0,
+               OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
+               OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL);
+
 DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0,
                OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
                OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
@@ -1538,6 +1549,7 @@ static struct omap_clk omap44xx_clks[] = {
        CLK(NULL,       "per_mcbsp4_gfclk",                     &per_mcbsp4_gfclk,      CK_443X),
        CLK(NULL,       "hsmmc1_fclk",                  &hsmmc1_fclk,   CK_443X),
        CLK(NULL,       "hsmmc2_fclk",                  &hsmmc2_fclk,   CK_443X),
+       CLK(NULL,       "ocp2scp_usb_phy_phy_48m",      &ocp2scp_usb_phy_phy_48m,       CK_443X),
        CLK(NULL,       "sha2md5_fck",                  &sha2md5_fck,   CK_443X),
        CLK(NULL,       "slimbus1_fclk_1",              &slimbus1_fclk_1,       CK_443X),
        CLK(NULL,       "slimbus1_fclk_0",              &slimbus1_fclk_0,       CK_443X),
@@ -1705,5 +1717,13 @@ int __init omap4xxx_clk_init(void)
        if (rc)
                pr_err("%s: failed to configure ABE DPLL!\n", __func__);
 
+       /*
+        * Lock USB DPLL on OMAP4 devices so that the L3INIT power
+        * domain can transition to retention state when not in use.
+        */
+       rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure USB DPLL!\n", __func__);
+
        return 0;
 }
index 40f4a03..d6ba13e 100644 (file)
@@ -293,5 +293,8 @@ extern void omap_reserve(void);
 struct omap_hwmod;
 extern int omap_dss_reset(struct omap_hwmod *);
 
+/* SoC specific clock initializer */
+extern int (*omap_clk_init)(void);
+
 #endif /* __ASSEMBLER__ */
 #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
index 2c3fdd6..5c445ca 100644 (file)
 #include "prm3xxx.h"
 #include "prm44xx.h"
 
+/*
+ * omap_clk_init: points to a function that does the SoC-specific
+ * clock initializations
+ */
+int (*omap_clk_init)(void);
+
 /*
  * The machine specific code may provide the extra mapping besides the
  * default mapping provided here.
@@ -397,7 +403,7 @@ void __init omap2420_init_early(void)
        omap242x_clockdomains_init();
        omap2420_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap2420_clk_init();
+       omap_clk_init = omap2420_clk_init;
 }
 
 void __init omap2420_init_late(void)
@@ -427,7 +433,7 @@ void __init omap2430_init_early(void)
        omap243x_clockdomains_init();
        omap2430_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap2430_clk_init();
+       omap_clk_init = omap2430_clk_init;
 }
 
 void __init omap2430_init_late(void)
@@ -462,7 +468,7 @@ void __init omap3_init_early(void)
        omap3xxx_clockdomains_init();
        omap3xxx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap3xxx_clk_init();
+       omap_clk_init = omap3xxx_clk_init;
 }
 
 void __init omap3430_init_early(void)
@@ -500,7 +506,7 @@ void __init ti81xx_init_early(void)
        omap3xxx_clockdomains_init();
        omap3xxx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap3xxx_clk_init();
+       omap_clk_init = omap3xxx_clk_init;
 }
 
 void __init omap3_init_late(void)
@@ -568,7 +574,7 @@ void __init am33xx_init_early(void)
        am33xx_clockdomains_init();
        am33xx_hwmod_init();
        omap_hwmod_init_postsetup();
-       am33xx_clk_init();
+       omap_clk_init = am33xx_clk_init;
 }
 #endif
 
@@ -593,7 +599,7 @@ void __init omap4430_init_early(void)
        omap44xx_clockdomains_init();
        omap44xx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap4xxx_clk_init();
+       omap_clk_init = omap4xxx_clk_init;
 }
 
 void __init omap4430_init_late(void)
index c2c798c..a202a47 100644 (file)
@@ -1368,7 +1368,9 @@ static void _enable_sysc(struct omap_hwmod *oh)
        }
 
        if (sf & SYSC_HAS_MIDLEMODE) {
-               if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
+               if (oh->flags & HWMOD_FORCE_MSTANDBY) {
+                       idlemode = HWMOD_IDLEMODE_FORCE;
+               } else if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
                        idlemode = HWMOD_IDLEMODE_NO;
                } else {
                        if (sf & SYSC_HAS_ENAWAKEUP)
@@ -1440,7 +1442,8 @@ static void _idle_sysc(struct omap_hwmod *oh)
        }
 
        if (sf & SYSC_HAS_MIDLEMODE) {
-               if (oh->flags & HWMOD_SWSUP_MSTANDBY) {
+               if ((oh->flags & HWMOD_SWSUP_MSTANDBY) ||
+                   (oh->flags & HWMOD_FORCE_MSTANDBY)) {
                        idlemode = HWMOD_IDLEMODE_FORCE;
                } else {
                        if (sf & SYSC_HAS_ENAWAKEUP)
index d43d9b6..d5dc935 100644 (file)
@@ -427,8 +427,8 @@ struct omap_hwmod_omap4_prcm {
  *
  * HWMOD_SWSUP_SIDLE: omap_hwmod code should manually bring module in and out
  *     of idle, rather than relying on module smart-idle
- * HWMOD_SWSUP_MSTDBY: omap_hwmod code should manually bring module in and out
- *     of standby, rather than relying on module smart-standby
+ * HWMOD_SWSUP_MSTANDBY: omap_hwmod code should manually bring module in and
+ *     out of standby, rather than relying on module smart-standby
  * HWMOD_INIT_NO_RESET: don't reset this module at boot - important for
  *     SDRAM controller, etc. XXX probably belongs outside the main hwmod file
  *     XXX Should be HWMOD_SETUP_NO_RESET
@@ -459,6 +459,10 @@ struct omap_hwmod_omap4_prcm {
  *     correctly, or this is being abused to deal with some PM latency
  *     issues -- but we're currently suffering from a shortage of
  *     folks who are able to track these issues down properly.
+ * HWMOD_FORCE_MSTANDBY: Always keep MIDLEMODE bits cleared so that device
+ *     is kept in force-standby mode. Failing to do so causes PM problems
+ *     with musb on OMAP3630 at least. Note that musb has a dedicated register
+ *     to control MSTANDBY signal when MIDLEMODE is set to force-standby.
  */
 #define HWMOD_SWSUP_SIDLE                      (1 << 0)
 #define HWMOD_SWSUP_MSTANDBY                   (1 << 1)
@@ -471,6 +475,7 @@ struct omap_hwmod_omap4_prcm {
 #define HWMOD_16BIT_REG                                (1 << 8)
 #define HWMOD_EXT_OPT_MAIN_CLK                 (1 << 9)
 #define HWMOD_BLOCK_WFI                                (1 << 10)
+#define HWMOD_FORCE_MSTANDBY                   (1 << 11)
 
 /*
  * omap_hwmod._int_flags definitions
index ac7e03e..5112d04 100644 (file)
@@ -1707,9 +1707,14 @@ static struct omap_hwmod omap3xxx_usbhsotg_hwmod = {
         * Erratum ID: i479  idle_req / idle_ack mechanism potentially
         * broken when autoidle is enabled
         * workaround is to disable the autoidle bit at module level.
+        *
+        * Enabling the device in any other MIDLEMODE setting but force-idle
+        * causes core_pwrdm not enter idle states at least on OMAP3630.
+        * Note that musb has OTG_FORCESTDBY register that controls MSTANDBY
+        * signal when MIDLEMODE is set to force-idle.
         */
        .flags          = HWMOD_NO_OCP_AUTOIDLE | HWMOD_SWSUP_SIDLE
-                               | HWMOD_SWSUP_MSTANDBY,
+                               | HWMOD_FORCE_MSTANDBY,
 };
 
 /* usb_otg_hs */
index 0e47d2e..9e05765 100644 (file)
@@ -2714,6 +2714,10 @@ static struct omap_ocp2scp_dev ocp2scp_dev_attr[] = {
        { }
 };
 
+static struct omap_hwmod_opt_clk ocp2scp_usb_phy_opt_clks[] = {
+       { .role = "48mhz", .clk = "ocp2scp_usb_phy_phy_48m" },
+};
+
 /* ocp2scp_usb_phy */
 static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
        .name           = "ocp2scp_usb_phy",
@@ -2728,6 +2732,8 @@ static struct omap_hwmod omap44xx_ocp2scp_usb_phy_hwmod = {
                },
        },
        .dev_attr       = ocp2scp_dev_attr,
+       .opt_clks       = ocp2scp_usb_phy_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(ocp2scp_usb_phy_opt_clks),
 };
 
 /*
index 2bdd4cf..f62b509 100644 (file)
@@ -547,6 +547,8 @@ static inline void __init realtime_counter_init(void)
                               clksrc_nr, clksrc_src)                   \
 void __init omap##name##_gptimer_timer_init(void)                      \
 {                                                                      \
+       if (omap_clk_init)                                              \
+               omap_clk_init();                                        \
        omap_dmtimer_init();                                            \
        omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);    \
        omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src);        \
@@ -556,6 +558,8 @@ void __init omap##name##_gptimer_timer_init(void)                   \
                                clksrc_nr, clksrc_src)                  \
 void __init omap##name##_sync32k_timer_init(void)              \
 {                                                                      \
+       if (omap_clk_init)                                              \
+               omap_clk_init();                                        \
        omap_dmtimer_init();                                            \
        omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);    \
        /* Enable the use of clocksource="gp_timer" kernel parameter */ \
index 25d085a..a4a13c9 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
index d2408ba..6eaa7a4 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
index 0b86e74..477d450 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
index 0553625..80a8d56 100644 (file)
 
 #include <plat/regs-serial.h>
 #include <mach/regs-gpio.h>
-#include <plat/regs-ac97.h>
 #include <plat/regs-dma.h>
 #include <mach/regs-lcd.h>
 #include <mach/regs-sdi.h>
-#include <plat/regs-iis.h>
 #include <plat/regs-spi.h>
 
 #define MAP(x) { \
index 051b62c..7f2cb6c 100644 (file)
@@ -81,7 +81,6 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = {
 #endif
 
 struct mmci_platform_data mop500_sdi0_data = {
-       .ios_handler    = mop500_sdi0_ios_handler,
        .ocr_mask       = MMC_VDD_29_30,
        .f_max          = 50000000,
        .capabilities   = MMC_CAP_4_BIT_DATA |
index b034578..87d2d7b 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-nomadik.h>
@@ -439,6 +440,15 @@ static void mop500_prox_deactivate(struct device *dev)
        regulator_put(prox_regulator);
 }
 
+void mop500_snowball_ethernet_clock_enable(void)
+{
+       struct clk *clk;
+
+       clk = clk_get_sys("fsmc", NULL);
+       if (!IS_ERR(clk))
+               clk_prepare_enable(clk);
+}
+
 static struct cryp_platform_data u8500_cryp1_platform_data = {
                .mem_to_engine = {
                                .dir = STEDMA40_MEM_TO_PERIPH,
@@ -683,6 +693,8 @@ static void __init snowball_init_machine(void)
        mop500_audio_init(parent);
        mop500_uart_init(parent);
 
+       mop500_snowball_ethernet_clock_enable();
+
        /* This board has full regulator constraints */
        regulator_has_full_constraints();
 }
index eaa605f..d38951b 100644 (file)
@@ -104,6 +104,7 @@ void __init mop500_pinmaps_init(void);
 void __init snowball_pinmaps_init(void);
 void __init hrefv60_pinmaps_init(void);
 void mop500_audio_init(struct device *parent);
+void mop500_snowball_ethernet_clock_enable(void);
 
 int __init mop500_uib_init(void);
 void mop500_uib_i2c_add(int busnum, struct i2c_board_info *info,
index 19235cf..f1a5818 100644 (file)
@@ -312,9 +312,10 @@ static void __init u8500_init_machine(void)
        /* Pinmaps must be in place before devices register */
        if (of_machine_is_compatible("st-ericsson,mop500"))
                mop500_pinmaps_init();
-       else if (of_machine_is_compatible("calaosystems,snowball-a9500"))
+       else if (of_machine_is_compatible("calaosystems,snowball-a9500")) {
                snowball_pinmaps_init();
-       else if (of_machine_is_compatible("st-ericsson,hrefv60+"))
+               mop500_snowball_ethernet_clock_enable();
+       } else if (of_machine_is_compatible("st-ericsson,hrefv60+"))
                hrefv60_pinmaps_init();
        else if (of_machine_is_compatible("st-ericsson,ccu9540")) {}
                /* TODO: Add pinmaps for ccu9540 board. */
index c2f3739..c465fac 100644 (file)
@@ -299,7 +299,7 @@ static void l2x0_unlock(u32 cache_id)
        int lockregs;
        int i;
 
-       switch (cache_id) {
+       switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
        case L2X0_CACHE_ID_PART_L310:
                lockregs = 8;
                break;
@@ -333,15 +333,14 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
        if (cache_id_part_number_from_dt)
                cache_id = cache_id_part_number_from_dt;
        else
-               cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID)
-                       & L2X0_CACHE_ID_PART_MASK;
+               cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
        aux = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
 
        aux &= aux_mask;
        aux |= aux_val;
 
        /* Determine the number of ways */
-       switch (cache_id) {
+       switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
        case L2X0_CACHE_ID_PART_L310:
                if (aux & (1 << 16))
                        ways = 16;
@@ -725,7 +724,6 @@ static const struct l2x0_of_data pl310_data = {
                .flush_all   = l2x0_flush_all,
                .inv_all     = l2x0_inv_all,
                .disable     = l2x0_disable,
-               .set_debug   = pl310_set_debug,
        },
 };
 
@@ -814,9 +812,8 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
                data->save();
 
        of_init = true;
-       l2x0_init(l2x0_base, aux_val, aux_mask);
-
        memcpy(&outer_cache, &data->outer_cache, sizeof(outer_cache));
+       l2x0_init(l2x0_base, aux_val, aux_mask);
 
        return 0;
 }
index a5a4b2b..2ac3737 100644 (file)
@@ -48,7 +48,7 @@ static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
 static atomic64_t asid_generation = ATOMIC64_INIT(ASID_FIRST_VERSION);
 static DECLARE_BITMAP(asid_map, NUM_USER_ASIDS);
 
-static DEFINE_PER_CPU(atomic64_t, active_asids);
+DEFINE_PER_CPU(atomic64_t, active_asids);
 static DEFINE_PER_CPU(u64, reserved_asids);
 static cpumask_t tlb_flush_pending;
 
@@ -215,6 +215,7 @@ 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();
        }
 
        atomic64_set(&per_cpu(active_asids, cpu), asid);
index e95a996..7897894 100644 (file)
@@ -598,39 +598,60 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
        } while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
-static void __init alloc_init_section(pud_t *pud, unsigned long addr,
-                                     unsigned long end, phys_addr_t phys,
-                                     const struct mem_type *type)
+static void __init map_init_section(pmd_t *pmd, unsigned long addr,
+                       unsigned long end, phys_addr_t phys,
+                       const struct mem_type *type)
 {
-       pmd_t *pmd = pmd_offset(pud, addr);
-
+#ifndef CONFIG_ARM_LPAE
        /*
-        * Try a section mapping - end, addr and phys must all be aligned
-        * to a section boundary.  Note that PMDs refer to the individual
-        * L1 entries, whereas PGDs refer to a group of L1 entries making
-        * up one logical pointer to an L2 table.
+        * In classic MMU format, puds and pmds are folded in to
+        * the pgds. pmd_offset gives the PGD entry. PGDs refer to a
+        * group of L1 entries making up one logical pointer to
+        * an L2 table (2MB), where as PMDs refer to the individual
+        * L1 entries (1MB). Hence increment to get the correct
+        * offset for odd 1MB sections.
+        * (See arch/arm/include/asm/pgtable-2level.h)
         */
-       if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
-               pmd_t *p = pmd;
-
-#ifndef CONFIG_ARM_LPAE
-               if (addr & SECTION_SIZE)
-                       pmd++;
+       if (addr & SECTION_SIZE)
+               pmd++;
 #endif
+       do {
+               *pmd = __pmd(phys | type->prot_sect);
+               phys += SECTION_SIZE;
+       } while (pmd++, addr += SECTION_SIZE, addr != end);
 
-               do {
-                       *pmd = __pmd(phys | type->prot_sect);
-                       phys += SECTION_SIZE;
-               } while (pmd++, addr += SECTION_SIZE, addr != end);
+       flush_pmd_entry(pmd);
+}
 
-               flush_pmd_entry(p);
-       } else {
+static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
+                                     unsigned long end, phys_addr_t phys,
+                                     const struct mem_type *type)
+{
+       pmd_t *pmd = pmd_offset(pud, addr);
+       unsigned long next;
+
+       do {
                /*
-                * No need to loop; pte's aren't interested in the
-                * individual L1 entries.
+                * With LPAE, we must loop over to map
+                * all the pmds for the given range.
                 */
-               alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
-       }
+               next = pmd_addr_end(addr, end);
+
+               /*
+                * Try a section mapping - addr, next and phys must all be
+                * aligned to a section boundary.
+                */
+               if (type->prot_sect &&
+                               ((addr | next | phys) & ~SECTION_MASK) == 0) {
+                       map_init_section(pmd, addr, next, phys, type);
+               } else {
+                       alloc_init_pte(pmd, addr, next,
+                                               __phys_to_pfn(phys), type);
+               }
+
+               phys += next - addr;
+
+       } while (pmd++, addr = next, addr != end);
 }
 
 static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
@@ -641,7 +662,7 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
 
        do {
                next = pud_addr_end(addr, end);
-               alloc_init_section(pud, addr, next, phys, type);
+               alloc_init_pmd(pud, addr, next, phys, type);
                phys += next - addr;
        } while (pud++, addr = next, addr != end);
 }
index 3a3c015..f584d3f 100644 (file)
@@ -420,7 +420,7 @@ __v7_pj4b_proc_info:
 __v7_ca7mp_proc_info:
        .long   0x410fc070
        .long   0xff0ffff0
-       __v7_proc __v7_ca7mp_setup, hwcaps = HWCAP_IDIV
+       __v7_proc __v7_ca7mp_setup
        .size   __v7_ca7mp_proc_info, . - __v7_ca7mp_proc_info
 
        /*
@@ -430,9 +430,24 @@ __v7_ca7mp_proc_info:
 __v7_ca15mp_proc_info:
        .long   0x410fc0f0
        .long   0xff0ffff0
-       __v7_proc __v7_ca15mp_setup, hwcaps = HWCAP_IDIV
+       __v7_proc __v7_ca15mp_setup
        .size   __v7_ca15mp_proc_info, . - __v7_ca15mp_proc_info
 
+       /*
+        * Qualcomm Inc. Krait processors.
+        */
+       .type   __krait_proc_info, #object
+__krait_proc_info:
+       .long   0x510f0400              @ Required ID value
+       .long   0xff0ffc00              @ Mask for ID
+       /*
+        * Some Krait processors don't indicate support for SDIV and UDIV
+        * instructions in the ARM instruction set, even though they actually
+        * do support them.
+        */
+       __v7_proc __v7_setup, hwcaps = HWCAP_IDIV
+       .size   __krait_proc_info, . - __krait_proc_info
+
        /*
         * Match any ARMv7 processor core.
         */
index 51afedd..d81d9fb 100644 (file)
@@ -146,14 +146,20 @@ struct platform_device s3c_device_camif = {
 
 /* ASOC DMA */
 
+#ifdef CONFIG_PLAT_S5P 
+static struct resource samsung_asoc_idma_resource = DEFINE_RES_IRQ(IRQ_I2S0);
+
 struct platform_device samsung_asoc_idma = {
        .name           = "samsung-idma",
        .id             = -1,
+       .num_resources  = 1,
+       .resource       = &samsung_asoc_idma_resource,
        .dev            = {
                .dma_mask               = &samsung_device_dma_mask,
                .coherent_dma_mask      = DMA_BIT_MASK(32),
        }
 };
+#endif
 
 /* FB */
 
index 224b44a..70b8cd4 100644 (file)
@@ -261,7 +261,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
 void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
 {
        unsigned long size, mask;
-       bool page64k = IS_ENABLED(ARM64_64K_PAGES);
+       bool page64k = IS_ENABLED(CONFIG_ARM64_64K_PAGES);
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
index e34f565..6f7dc8b 100644 (file)
@@ -291,7 +291,6 @@ cpu_idle (void)
                }
 
                if (!need_resched()) {
-                       void (*idle)(void);
 #ifdef CONFIG_SMP
                        min_xtp();
 #endif
@@ -299,9 +298,7 @@ cpu_idle (void)
                        if (mark_idle)
                                (*mark_idle)(1);
 
-                       if (!idle)
-                               idle = default_idle;
-                       (*idle)();
+                       default_idle();
                        if (mark_idle)
                                (*mark_idle)(0);
 #ifdef CONFIG_SMP
index cd2e21f..51244bf 100644 (file)
@@ -18,7 +18,7 @@ config MIPS
        select HAVE_KRETPROBES
        select HAVE_DEBUG_KMEMLEAK
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
-       select HAVE_ARCH_TRANSPARENT_HUGEPAGE
+       select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
        select RTC_LIB if !MACH_LOONGSON
        select GENERIC_ATOMIC64 if !64BIT
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
@@ -657,7 +657,7 @@ config SNI_RM
        bool "SNI RM200/300/400"
        select FW_ARC if CPU_LITTLE_ENDIAN
        select FW_ARC32 if CPU_LITTLE_ENDIAN
-       select SNIPROM if CPU_BIG_ENDIAN
+       select FW_SNIPROM if CPU_BIG_ENDIAN
        select ARCH_MAY_HAVE_PC_FDC
        select BOOT_ELF32
        select CEVT_R4K
@@ -1144,7 +1144,7 @@ config DEFAULT_SGI_PARTITION
 config FW_ARC32
        bool
 
-config SNIPROM
+config FW_SNIPROM
        bool
 
 config BOOT_ELF32
@@ -1493,7 +1493,6 @@ config CPU_XLP
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_64BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
-       select CPU_HAS_LLSC
        select WEAK_ORDERING
        select WEAK_REORDERING_BEYOND_LLSC
        select CPU_HAS_PREFETCH
index ed1949c..9aa7d44 100644 (file)
@@ -745,10 +745,7 @@ void __init board_prom_init(void)
                strcpy(cfe_version, "unknown");
        printk(KERN_INFO PFX "CFE version: %s\n", cfe_version);
 
-       if (bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET)) {
-               printk(KERN_ERR PFX "invalid nvram checksum\n");
-               return;
-       }
+       bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET);
 
        board_name = bcm63xx_nvram_get_name();
        /* find board by name */
index 6206116..a4b8864 100644 (file)
@@ -38,7 +38,7 @@ struct bcm963xx_nvram {
 static struct bcm963xx_nvram nvram;
 static int mac_addr_used;
 
-int __init bcm63xx_nvram_init(void *addr)
+void __init bcm63xx_nvram_init(void *addr)
 {
        unsigned int check_len;
        u32 crc, expected_crc;
@@ -60,9 +60,8 @@ int __init bcm63xx_nvram_init(void *addr)
        crc = crc32_le(~0, (u8 *)&nvram, check_len);
 
        if (crc != expected_crc)
-               return -EINVAL;
-
-       return 0;
+               pr_warn("nvram checksum failed, contents may be invalid (expected %08x, got %08x)\n",
+                       expected_crc, crc);
 }
 
 u8 *bcm63xx_nvram_get_name(void)
index 314231b..35e18e9 100644 (file)
@@ -157,4 +157,4 @@ int __init bcm63xx_register_devices(void)
        return board_register_devices();
 }
 
-device_initcall(bcm63xx_register_devices);
+arch_initcall(bcm63xx_register_devices);
index c594a3d..b0baa29 100644 (file)
@@ -174,7 +174,10 @@ static int octeon_kexec_prepare(struct kimage *image)
 
 static void octeon_generic_shutdown(void)
 {
-       int cpu, i;
+       int i;
+#ifdef CONFIG_SMP
+       int cpu;
+#endif
        struct cvmx_bootmem_desc *bootmem_desc;
        void *named_block_array_ptr;
 
index 62d6a3b..4e0b6bc 100644 (file)
@@ -9,10 +9,8 @@
  *
  * Initialized the local nvram copy from the target address and checks
  * its checksum.
- *
- * Returns 0 on success.
  */
-int __init bcm63xx_nvram_init(void *nvram);
+void bcm63xx_nvram_init(void *nvram);
 
 /**
  * bcm63xx_nvram_get_name() - returns the board name according to nvram
index d9c8284..193c091 100644 (file)
 /* #define cpu_has_prefetch    ? */
 #define cpu_has_mcheck         1
 /* #define cpu_has_ejtag       ? */
-#ifdef CONFIG_CPU_HAS_LLSC
 #define cpu_has_llsc           1
-#else
-#define cpu_has_llsc           0
-#endif
 /* #define cpu_has_vtag_icache ? */
 /* #define cpu_has_dc_aliases  ? */
 /* #define cpu_has_ic_fills_f_dc ? */
index 12b70c2..0da44d4 100644 (file)
@@ -1166,7 +1166,10 @@ do {                                                                     \
        unsigned int __dspctl;                                          \
                                                                        \
        __asm__ __volatile__(                                           \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
        "       rddsp   %0, %x1                                 \n"     \
+       "       .set pop                                        \n"     \
        : "=r" (__dspctl)                                               \
        : "i" (mask));                                                  \
        __dspctl;                                                       \
@@ -1175,30 +1178,198 @@ do {                                                                   \
 #define wrdsp(val, mask)                                               \
 do {                                                                   \
        __asm__ __volatile__(                                           \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
        "       wrdsp   %0, %x1                                 \n"     \
+       "       .set pop                                        \n"     \
        :                                                               \
        : "r" (val), "i" (mask));                                       \
 } while (0)
 
-#define mflo0() ({ long mflo0; __asm__("mflo %0, $ac0" : "=r" (mflo0)); mflo0;})
-#define mflo1() ({ long mflo1; __asm__("mflo %0, $ac1" : "=r" (mflo1)); mflo1;})
-#define mflo2() ({ long mflo2; __asm__("mflo %0, $ac2" : "=r" (mflo2)); mflo2;})
-#define mflo3() ({ long mflo3; __asm__("mflo %0, $ac3" : "=r" (mflo3)); mflo3;})
-
-#define mfhi0() ({ long mfhi0; __asm__("mfhi %0, $ac0" : "=r" (mfhi0)); mfhi0;})
-#define mfhi1() ({ long mfhi1; __asm__("mfhi %0, $ac1" : "=r" (mfhi1)); mfhi1;})
-#define mfhi2() ({ long mfhi2; __asm__("mfhi %0, $ac2" : "=r" (mfhi2)); mfhi2;})
-#define mfhi3() ({ long mfhi3; __asm__("mfhi %0, $ac3" : "=r" (mfhi3)); mfhi3;})
-
-#define mtlo0(x) __asm__("mtlo %0, $ac0" ::"r" (x))
-#define mtlo1(x) __asm__("mtlo %0, $ac1" ::"r" (x))
-#define mtlo2(x) __asm__("mtlo %0, $ac2" ::"r" (x))
-#define mtlo3(x) __asm__("mtlo %0, $ac3" ::"r" (x))
-
-#define mthi0(x) __asm__("mthi %0, $ac0" ::"r" (x))
-#define mthi1(x) __asm__("mthi %0, $ac1" ::"r" (x))
-#define mthi2(x) __asm__("mthi %0, $ac2" ::"r" (x))
-#define mthi3(x) __asm__("mthi %0, $ac3" ::"r" (x))
+#define mflo0()                                                                \
+({                                                                     \
+       long mflo0;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mflo %0, $ac0                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mflo0));                                                \
+       mflo0;                                                          \
+})
+
+#define mflo1()                                                                \
+({                                                                     \
+       long mflo1;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mflo %0, $ac1                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mflo1));                                                \
+       mflo1;                                                          \
+})
+
+#define mflo2()                                                                \
+({                                                                     \
+       long mflo2;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mflo %0, $ac2                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mflo2));                                                \
+       mflo2;                                                          \
+})
+
+#define mflo3()                                                                \
+({                                                                     \
+       long mflo3;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mflo %0, $ac3                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mflo3));                                                \
+       mflo3;                                                          \
+})
+
+#define mfhi0()                                                                \
+({                                                                     \
+       long mfhi0;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mfhi %0, $ac0                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mfhi0));                                                \
+       mfhi0;                                                          \
+})
+
+#define mfhi1()                                                                \
+({                                                                     \
+       long mfhi1;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mfhi %0, $ac1                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mfhi1));                                                \
+       mfhi1;                                                          \
+})
+
+#define mfhi2()                                                                \
+({                                                                     \
+       long mfhi2;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mfhi %0, $ac2                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mfhi2));                                                \
+       mfhi2;                                                          \
+})
+
+#define mfhi3()                                                                \
+({                                                                     \
+       long mfhi3;                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mfhi %0, $ac3                                   \n"     \
+       "       .set pop                                        \n"     \
+       : "=r" (mfhi3));                                                \
+       mfhi3;                                                          \
+})
+
+
+#define mtlo0(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mtlo %0, $ac0                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mtlo1(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mtlo %0, $ac1                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mtlo2(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mtlo %0, $ac2                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mtlo3(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mtlo %0, $ac3                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mthi0(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mthi %0, $ac0                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mthi1(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mthi %0, $ac1                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mthi2(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mthi %0, $ac2                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
+
+#define mthi3(x)                                                       \
+({                                                                     \
+       __asm__(                                                        \
+       "       .set push                                       \n"     \
+       "       .set dsp                                        \n"     \
+       "       mthi %0, $ac3                                   \n"     \
+       "       .set pop                                        \n"     \
+       :                                                               \
+       : "r" (x));                                                     \
+})
 
 #else
 
index 197f636..8efe5a9 100644 (file)
@@ -21,6 +21,6 @@
 #include <asm/sigcontext.h>
 #include <asm/siginfo.h>
 
-#define __ARCH_HAS_ODD_SIGACTION
+#define __ARCH_HAS_IRIX_SIGACTION
 
 #endif /* _ASM_SIGNAL_H */
index d6b18b4..addb9f5 100644 (file)
@@ -72,6 +72,12 @@ typedef unsigned long old_sigset_t;          /* at least 32 bits */
  *
  * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
  * Unix names RESETHAND and NODEFER respectively.
+ *
+ * SA_RESTORER used to be defined as 0x04000000 but only the O32 ABI ever
+ * supported its use and no libc was using it, so the entire sa-restorer
+ * functionality was removed with lmo commit 39bffc12c3580ab for 2.5.48
+ * retaining only the SA_RESTORER definition as a reminder to avoid
+ * accidental reuse of the mask bit.
  */
 #define SA_ONSTACK     0x08000000
 #define SA_RESETHAND   0x80000000
@@ -84,8 +90,6 @@ typedef unsigned long old_sigset_t;           /* at least 32 bits */
 #define SA_NOMASK      SA_NODEFER
 #define SA_ONESHOT     SA_RESETHAND
 
-#define SA_RESTORER    0x04000000      /* Only for o32 */
-
 #define MINSIGSTKSZ    2048
 #define SIGSTKSZ       8192
 
index f81d98f..de75fb5 100644 (file)
@@ -100,29 +100,16 @@ obj-$(CONFIG_HW_PERF_EVENTS)      += perf_event_mipsxx.o
 obj-$(CONFIG_JUMP_LABEL)       += jump_label.o
 
 #
-# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is safe
-# to enable DSP assembler support here even if the MIPS Release 2 CPU we
-# are targetting does not support DSP because all code-paths making use of
-# it properly check that the running CPU *actually does* support these
-# instructions.
+# DSP ASE supported for MIPS32 or MIPS64 Release 2 cores only. It is not
+# safe to unconditionnaly use the assembler -mdsp / -mdspr2 switches
+# here because the compiler may use DSP ASE instructions (such as lwx) in
+# code paths where we cannot check that the CPU we are running on supports it.
+# Proper abstraction using HAVE_AS_DSP and macros is done in
+# arch/mips/include/asm/mipsregs.h.
 #
 ifeq ($(CONFIG_CPU_MIPSR2), y)
 CFLAGS_DSP                     = -DHAVE_AS_DSP
 
-#
-# Check if assembler supports DSP ASE
-#
-ifeq ($(call cc-option-yn,-mdsp), y)
-CFLAGS_DSP                     += -mdsp
-endif
-
-#
-# Check if assembler supports DSP ASE Rev2
-#
-ifeq ($(call cc-option-yn,-mdspr2), y)
-CFLAGS_DSP                     += -mdspr2
-endif
-
 CFLAGS_signal.o                        = $(CFLAGS_DSP)
 CFLAGS_signal32.o              = $(CFLAGS_DSP)
 CFLAGS_process.o               = $(CFLAGS_DSP)
index 6bfccc2..5fe66a0 100644 (file)
@@ -580,6 +580,9 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->tlbsize = 48;
                break;
        case PRID_IMP_VR41XX:
+               set_isa(c, MIPS_CPU_ISA_III);
+               c->options = R4K_OPTS;
+               c->tlbsize = 32;
                switch (c->processor_id & 0xf0) {
                case PRID_REV_VR4111:
                        c->cputype = CPU_VR4111;
@@ -604,6 +607,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                                __cpu_name[cpu] = "NEC VR4131";
                        } else {
                                c->cputype = CPU_VR4133;
+                               c->options |= MIPS_CPU_LLSC;
                                __cpu_name[cpu] = "NEC VR4133";
                        }
                        break;
@@ -613,9 +617,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                        __cpu_name[cpu] = "NEC Vr41xx";
                        break;
                }
-               set_isa(c, MIPS_CPU_ISA_III);
-               c->options = R4K_OPTS;
-               c->tlbsize = 32;
                break;
        case PRID_IMP_R4300:
                c->cputype = CPU_R4300;
@@ -1226,10 +1227,8 @@ __cpuinit void cpu_probe(void)
        if (c->options & MIPS_CPU_FPU) {
                c->fpu_id = cpu_get_fpu_id();
 
-               if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
-                   c->isa_level == MIPS_CPU_ISA_M32R2 ||
-                   c->isa_level == MIPS_CPU_ISA_M64R1 ||
-                   c->isa_level == MIPS_CPU_ISA_M64R2) {
+               if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+                                   MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
                        if (c->fpu_id & MIPS_FPIR_3D)
                                c->ases |= MIPS_ASE_MIPS3D;
                }
index 8eeee1c..db9655f 100644 (file)
@@ -171,7 +171,7 @@ SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
                err = compat_sys_shmctl(first, second, compat_ptr(ptr));
                break;
        default:
-               err = -EINVAL;
+               err = -ENOSYS;
                break;
        }
 
index 1658676..33d0671 100644 (file)
        PTR_L   a5, PT_R9(sp)
        PTR_L   a6, PT_R10(sp)
        PTR_L   a7, PT_R11(sp)
-#else
-       PTR_ADDIU       sp, PT_SIZE
 #endif
-.endm
+       PTR_ADDIU       sp, PT_SIZE
+       .endm
 
        .macro RETURN_BACK
        jr ra
@@ -68,7 +67,11 @@ NESTED(ftrace_caller, PT_SIZE, ra)
        .globl _mcount
 _mcount:
        b       ftrace_stub
-       addiu sp,sp,8
+#ifdef CONFIG_32BIT
+        addiu sp,sp,8
+#else
+        nop
+#endif
 
        /* When tracing is activated, it calls ftrace_caller+8 (aka here) */
        lw      t1, function_trace_stop
index 135c4aa..7a54f74 100644 (file)
@@ -67,7 +67,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        if (cpu_has_mips_r) {
                seq_printf(m, "isa\t\t\t:");
                if (cpu_has_mips_1)
-                       seq_printf(m, "%s", "mips1");
+                       seq_printf(m, "%s", " mips1");
                if (cpu_has_mips_2)
                        seq_printf(m, "%s", " mips2");
                if (cpu_has_mips_3)
index a200b5b..c3abb88 100644 (file)
@@ -1571,7 +1571,7 @@ void __cpuinit per_cpu_trap_init(bool is_boot_cpu)
 #ifdef CONFIG_64BIT
        status_set |= ST0_FR|ST0_KX|ST0_SX|ST0_UX;
 #endif
-       if (current_cpu_data.isa_level == MIPS_CPU_ISA_IV)
+       if (current_cpu_data.isa_level & MIPS_CPU_ISA_IV)
                status_set |= ST0_XX;
        if (cpu_has_dsp)
                status_set |= ST0_MX;
index 81f1dcf..a64daee 100644 (file)
@@ -90,12 +90,12 @@ int __mips_test_and_set_bit(unsigned long nr,
        unsigned bit = nr & SZLONG_MASK;
        unsigned long mask;
        unsigned long flags;
-       unsigned long res;
+       int res;
 
        a += nr >> SZLONG_LOG;
        mask = 1UL << bit;
        raw_local_irq_save(flags);
-       res = (mask & *a);
+       res = (mask & *a) != 0;
        *a |= mask;
        raw_local_irq_restore(flags);
        return res;
@@ -116,12 +116,12 @@ int __mips_test_and_set_bit_lock(unsigned long nr,
        unsigned bit = nr & SZLONG_MASK;
        unsigned long mask;
        unsigned long flags;
-       unsigned long res;
+       int res;
 
        a += nr >> SZLONG_LOG;
        mask = 1UL << bit;
        raw_local_irq_save(flags);
-       res = (mask & *a);
+       res = (mask & *a) != 0;
        *a |= mask;
        raw_local_irq_restore(flags);
        return res;
@@ -141,12 +141,12 @@ int __mips_test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
        unsigned bit = nr & SZLONG_MASK;
        unsigned long mask;
        unsigned long flags;
-       unsigned long res;
+       int res;
 
        a += nr >> SZLONG_LOG;
        mask = 1UL << bit;
        raw_local_irq_save(flags);
-       res = (mask & *a);
+       res = (mask & *a) != 0;
        *a &= ~mask;
        raw_local_irq_restore(flags);
        return res;
@@ -166,12 +166,12 @@ int __mips_test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
        unsigned bit = nr & SZLONG_MASK;
        unsigned long mask;
        unsigned long flags;
-       unsigned long res;
+       int res;
 
        a += nr >> SZLONG_LOG;
        mask = 1UL << bit;
        raw_local_irq_save(flags);
-       res = (mask & *a);
+       res = (mask & *a) != 0;
        *a ^= mask;
        raw_local_irq_restore(flags);
        return res;
index 507147a..a6adffb 100644 (file)
@@ -270,7 +270,7 @@ LEAF(csum_partial)
 #endif
 
        /* odd buffer alignment? */
-#ifdef CPU_MIPSR2
+#ifdef CONFIG_CPU_MIPSR2
        wsbh    v1, sum
        movn    sum, v1, t7
 #else
@@ -670,7 +670,7 @@ EXC(        sb      t0, NBYTES-2(dst), .Ls_exc)
        addu    sum, v1
 #endif
 
-#ifdef CPU_MIPSR2
+#ifdef CONFIG_CPU_MIPSR2
        wsbh    v1, sum
        movn    sum, v1, odd
 #else
index ecca559..2078915 100644 (file)
@@ -1247,10 +1247,8 @@ static void __cpuinit setup_scache(void)
                return;
 
        default:
-               if (c->isa_level == MIPS_CPU_ISA_M32R1 ||
-                   c->isa_level == MIPS_CPU_ISA_M32R2 ||
-                   c->isa_level == MIPS_CPU_ISA_M64R1 ||
-                   c->isa_level == MIPS_CPU_ISA_M64R2) {
+               if (c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+                                   MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)) {
 #ifdef CONFIG_MIPS_CPU_SCACHE
                        if (mips_sc_init ()) {
                                scache_size = c->scache.ways * c->scache.sets * c->scache.linesz;
index 93d937b..df96da7 100644 (file)
@@ -98,10 +98,8 @@ static inline int __init mips_sc_probe(void)
        c->scache.flags |= MIPS_CACHE_NOT_PRESENT;
 
        /* Ignore anything but MIPSxx processors */
-       if (c->isa_level != MIPS_CPU_ISA_M32R1 &&
-           c->isa_level != MIPS_CPU_ISA_M32R2 &&
-           c->isa_level != MIPS_CPU_ISA_M64R1 &&
-           c->isa_level != MIPS_CPU_ISA_M64R2)
+       if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 |
+                             MIPS_CPU_ISA_M64R1 | MIPS_CPU_ISA_M64R2)))
                return 0;
 
        /* Does this MIPS32/MIPS64 CPU have a config2 register? */
index 38a80c8..d1faece 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/tlbmisc.h>
 
-#ifdef CONFIG_DEBUG_PCI
+#ifdef CONFIG_PCI_DEBUG
 #define DBG(x...) printk(KERN_DEBUG x)
 #else
 #define DBG(x...) do {} while (0)
@@ -162,7 +162,7 @@ static int config_access(unsigned char access_type, struct pci_bus *bus,
        if (status & (1 << 29)) {
                *data = 0xffffffff;
                error = -1;
-               DBG("alchemy-pci: master abort on cfg access %d bus %d dev %d",
+               DBG("alchemy-pci: master abort on cfg access %d bus %d dev %d\n",
                    access_type, bus->number, device);
        } else if ((status >> 28) & 0xf) {
                DBG("alchemy-pci: PCI ERR detected: dev %d, status %lx\n",
index f3eab85..d44a571 100644 (file)
 #include <asm/code-patching.h>
 #include <asm/machdep.h>
 
+#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
 extern void epapr_ev_idle(void);
 extern u32 epapr_ev_idle_start[];
+#endif
 
 bool epapr_paravirt_enabled;
 
@@ -47,11 +49,15 @@ static int __init epapr_paravirt_init(void)
 
        for (i = 0; i < (len / 4); i++) {
                patch_instruction(epapr_hypercall_start + i, insts[i]);
+#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
                patch_instruction(epapr_ev_idle_start + i, insts[i]);
+#endif
        }
 
+#if !defined(CONFIG_64BIT) || defined(CONFIG_PPC_BOOK3E_64)
        if (of_get_property(hyper_node, "has-idle", NULL))
                ppc_md.power_save = epapr_ev_idle;
+#endif
 
        epapr_paravirt_enabled = true;
 
index 200afa5..56bd923 100644 (file)
@@ -1066,78 +1066,6 @@ unrecov_user_slb:
 #endif /* __DISABLED__ */
 
 
-/*
- * r13 points to the PACA, r9 contains the saved CR,
- * r12 contain the saved SRR1, SRR0 is still ready for return
- * r3 has the faulting address
- * r9 - r13 are saved in paca->exslb.
- * r3 is saved in paca->slb_r3
- * We assume we aren't going to take any exceptions during this procedure.
- */
-_GLOBAL(slb_miss_realmode)
-       mflr    r10
-#ifdef CONFIG_RELOCATABLE
-       mtctr   r11
-#endif
-
-       stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
-       std     r10,PACA_EXSLB+EX_LR(r13)       /* save LR */
-
-       bl      .slb_allocate_realmode
-
-       /* All done -- return from exception. */
-
-       ld      r10,PACA_EXSLB+EX_LR(r13)
-       ld      r3,PACA_EXSLB+EX_R3(r13)
-       lwz     r9,PACA_EXSLB+EX_CCR(r13)       /* get saved CR */
-
-       mtlr    r10
-
-       andi.   r10,r12,MSR_RI  /* check for unrecoverable exception */
-       beq-    2f
-
-.machine       push
-.machine       "power4"
-       mtcrf   0x80,r9
-       mtcrf   0x01,r9         /* slb_allocate uses cr0 and cr7 */
-.machine       pop
-
-       RESTORE_PPR_PACA(PACA_EXSLB, r9)
-       ld      r9,PACA_EXSLB+EX_R9(r13)
-       ld      r10,PACA_EXSLB+EX_R10(r13)
-       ld      r11,PACA_EXSLB+EX_R11(r13)
-       ld      r12,PACA_EXSLB+EX_R12(r13)
-       ld      r13,PACA_EXSLB+EX_R13(r13)
-       rfid
-       b       .       /* prevent speculative execution */
-
-2:     mfspr   r11,SPRN_SRR0
-       ld      r10,PACAKBASE(r13)
-       LOAD_HANDLER(r10,unrecov_slb)
-       mtspr   SPRN_SRR0,r10
-       ld      r10,PACAKMSR(r13)
-       mtspr   SPRN_SRR1,r10
-       rfid
-       b       .
-
-unrecov_slb:
-       EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
-       DISABLE_INTS
-       bl      .save_nvgprs
-1:     addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .unrecoverable_exception
-       b       1b
-
-
-#ifdef CONFIG_PPC_970_NAP
-power4_fixup_nap:
-       andc    r9,r9,r10
-       std     r9,TI_LOCAL_FLAGS(r11)
-       ld      r10,_LINK(r1)           /* make idle task do the */
-       std     r10,_NIP(r1)            /* equivalent of a blr */
-       blr
-#endif
-
        .align  7
        .globl alignment_common
 alignment_common:
@@ -1335,6 +1263,78 @@ _GLOBAL(opal_mc_secondary_handler)
 #endif /* CONFIG_PPC_POWERNV */
 
 
+/*
+ * r13 points to the PACA, r9 contains the saved CR,
+ * r12 contain the saved SRR1, SRR0 is still ready for return
+ * r3 has the faulting address
+ * r9 - r13 are saved in paca->exslb.
+ * r3 is saved in paca->slb_r3
+ * We assume we aren't going to take any exceptions during this procedure.
+ */
+_GLOBAL(slb_miss_realmode)
+       mflr    r10
+#ifdef CONFIG_RELOCATABLE
+       mtctr   r11
+#endif
+
+       stw     r9,PACA_EXSLB+EX_CCR(r13)       /* save CR in exc. frame */
+       std     r10,PACA_EXSLB+EX_LR(r13)       /* save LR */
+
+       bl      .slb_allocate_realmode
+
+       /* All done -- return from exception. */
+
+       ld      r10,PACA_EXSLB+EX_LR(r13)
+       ld      r3,PACA_EXSLB+EX_R3(r13)
+       lwz     r9,PACA_EXSLB+EX_CCR(r13)       /* get saved CR */
+
+       mtlr    r10
+
+       andi.   r10,r12,MSR_RI  /* check for unrecoverable exception */
+       beq-    2f
+
+.machine       push
+.machine       "power4"
+       mtcrf   0x80,r9
+       mtcrf   0x01,r9         /* slb_allocate uses cr0 and cr7 */
+.machine       pop
+
+       RESTORE_PPR_PACA(PACA_EXSLB, r9)
+       ld      r9,PACA_EXSLB+EX_R9(r13)
+       ld      r10,PACA_EXSLB+EX_R10(r13)
+       ld      r11,PACA_EXSLB+EX_R11(r13)
+       ld      r12,PACA_EXSLB+EX_R12(r13)
+       ld      r13,PACA_EXSLB+EX_R13(r13)
+       rfid
+       b       .       /* prevent speculative execution */
+
+2:     mfspr   r11,SPRN_SRR0
+       ld      r10,PACAKBASE(r13)
+       LOAD_HANDLER(r10,unrecov_slb)
+       mtspr   SPRN_SRR0,r10
+       ld      r10,PACAKMSR(r13)
+       mtspr   SPRN_SRR1,r10
+       rfid
+       b       .
+
+unrecov_slb:
+       EXCEPTION_PROLOG_COMMON(0x4100, PACA_EXSLB)
+       DISABLE_INTS
+       bl      .save_nvgprs
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .unrecoverable_exception
+       b       1b
+
+
+#ifdef CONFIG_PPC_970_NAP
+power4_fixup_nap:
+       andc    r9,r9,r10
+       std     r9,TI_LOCAL_FLAGS(r11)
+       ld      r10,_LINK(r1)           /* make idle task do the */
+       std     r10,_NIP(r1)            /* equivalent of a blr */
+       blr
+#endif
+
 /*
  * Hash table stuff
  */
index 4a29308..4a54431 100644 (file)
@@ -344,6 +344,7 @@ extern unsigned long MODULES_END;
 #define _REGION3_ENTRY_CO      0x100   /* change-recording override        */
 
 /* Bits in the segment table entry */
+#define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address       */
 #define _SEGMENT_ENTRY_ORIGIN  ~0x7ffUL/* segment table origin             */
 #define _SEGMENT_ENTRY_RO      0x200   /* page protection bit              */
 #define _SEGMENT_ENTRY_INV     0x20    /* invalid segment table entry      */
@@ -1531,7 +1532,8 @@ extern int s390_enable_sie(void);
 /*
  * No page table caches to initialise
  */
-#define pgtable_cache_init()   do { } while (0)
+static inline void pgtable_cache_init(void) { }
+static inline void check_pgt_cache(void) { }
 
 #include <asm-generic/pgtable.h>
 
index dff631d..466fb33 100644 (file)
@@ -77,42 +77,69 @@ static size_t copy_in_kernel(size_t count, void __user *to,
  * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occured and the address
  * contains the (negative) exception code.
  */
-static __always_inline unsigned long follow_table(struct mm_struct *mm,
-                                                 unsigned long addr, int write)
+#ifdef CONFIG_64BIT
+static unsigned long follow_table(struct mm_struct *mm,
+                                 unsigned long address, int write)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *ptep;
+       unsigned long *table = (unsigned long *)__pa(mm->pgd);
+
+       switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
+       case _ASCE_TYPE_REGION1:
+               table = table + ((address >> 53) & 0x7ff);
+               if (unlikely(*table & _REGION_ENTRY_INV))
+                       return -0x39UL;
+               table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+       case _ASCE_TYPE_REGION2:
+               table = table + ((address >> 42) & 0x7ff);
+               if (unlikely(*table & _REGION_ENTRY_INV))
+                       return -0x3aUL;
+               table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+       case _ASCE_TYPE_REGION3:
+               table = table + ((address >> 31) & 0x7ff);
+               if (unlikely(*table & _REGION_ENTRY_INV))
+                       return -0x3bUL;
+               table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
+       case _ASCE_TYPE_SEGMENT:
+               table = table + ((address >> 20) & 0x7ff);
+               if (unlikely(*table & _SEGMENT_ENTRY_INV))
+                       return -0x10UL;
+               if (unlikely(*table & _SEGMENT_ENTRY_LARGE)) {
+                       if (write && (*table & _SEGMENT_ENTRY_RO))
+                               return -0x04UL;
+                       return (*table & _SEGMENT_ENTRY_ORIGIN_LARGE) +
+                               (address & ~_SEGMENT_ENTRY_ORIGIN_LARGE);
+               }
+               table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
+       }
+       table = table + ((address >> 12) & 0xff);
+       if (unlikely(*table & _PAGE_INVALID))
+               return -0x11UL;
+       if (write && (*table & _PAGE_RO))
+               return -0x04UL;
+       return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
+}
 
-       pgd = pgd_offset(mm, addr);
-       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
-               return -0x3aUL;
+#else /* CONFIG_64BIT */
 
-       pud = pud_offset(pgd, addr);
-       if (pud_none(*pud) || unlikely(pud_bad(*pud)))
-               return -0x3bUL;
+static unsigned long follow_table(struct mm_struct *mm,
+                                 unsigned long address, int write)
+{
+       unsigned long *table = (unsigned long *)__pa(mm->pgd);
 
-       pmd = pmd_offset(pud, addr);
-       if (pmd_none(*pmd))
+       table = table + ((address >> 20) & 0x7ff);
+       if (unlikely(*table & _SEGMENT_ENTRY_INV))
                return -0x10UL;
-       if (pmd_large(*pmd)) {
-               if (write && (pmd_val(*pmd) & _SEGMENT_ENTRY_RO))
-                       return -0x04UL;
-               return (pmd_val(*pmd) & HPAGE_MASK) + (addr & ~HPAGE_MASK);
-       }
-       if (unlikely(pmd_bad(*pmd)))
-               return -0x10UL;
-
-       ptep = pte_offset_map(pmd, addr);
-       if (!pte_present(*ptep))
+       table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
+       table = table + ((address >> 12) & 0xff);
+       if (unlikely(*table & _PAGE_INVALID))
                return -0x11UL;
-       if (write && (!pte_write(*ptep) || !pte_dirty(*ptep)))
+       if (write && (*table & _PAGE_RO))
                return -0x04UL;
-
-       return (pte_val(*ptep) & PAGE_MASK) + (addr & ~PAGE_MASK);
+       return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
 }
 
+#endif /* CONFIG_64BIT */
+
 static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
                                             size_t n, int write_user)
 {
@@ -197,7 +224,7 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
 
 static size_t clear_user_pt(size_t n, void __user *to)
 {
-       void *zpage = &empty_zero_page;
+       void *zpage = (void *) empty_zero_page;
        long done, size, ret;
 
        done = 0;
index d1e15f7..7a5aa1a 100644 (file)
@@ -1004,15 +1004,8 @@ void __cpuinit setup_cpu(int boot)
 
 #ifdef CONFIG_BLK_DEV_INITRD
 
-/*
- * Note that the kernel can potentially support other compression
- * techniques than gz, though we don't do so by default.  If we ever
- * decide to do so we can either look for other filename extensions,
- * or just allow a file with this name to be compressed with an
- * arbitrary compressor (somewhat counterintuitively).
- */
 static int __initdata set_initramfs_file;
-static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
+static char __initdata initramfs_file[128] = "initramfs";
 
 static int __init setup_initramfs_file(char *str)
 {
@@ -1026,9 +1019,9 @@ static int __init setup_initramfs_file(char *str)
 early_param("initramfs_file", setup_initramfs_file);
 
 /*
- * We look for an "initramfs.cpio.gz" file in the hvfs.
- * If there is one, we allocate some memory for it and it will be
- * unpacked to the initramfs.
+ * We look for a file called "initramfs" in the hvfs.  If there is one, we
+ * allocate some memory for it and it will be unpacked to the initramfs.
+ * If it's compressed, the initd code will uncompress it first.
  */
 static void __init load_hv_initrd(void)
 {
@@ -1038,10 +1031,16 @@ static void __init load_hv_initrd(void)
 
        fd = hv_fs_findfile((HV_VirtAddr) initramfs_file);
        if (fd == HV_ENOENT) {
-               if (set_initramfs_file)
+               if (set_initramfs_file) {
                        pr_warning("No such hvfs initramfs file '%s'\n",
                                   initramfs_file);
-               return;
+                       return;
+               } else {
+                       /* Try old backwards-compatible name. */
+                       fd = hv_fs_findfile((HV_VirtAddr)"initramfs.cpio.gz");
+                       if (fd == HV_ENOENT)
+                               return;
+               }
        }
        BUG_ON(fd < 0);
        stat = hv_fs_fstat(fd);
index 8a84501..5ef205c 100644 (file)
@@ -4,7 +4,7 @@
 # create a compressed vmlinux image from the original vmlinux
 #
 
-targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo head_$(BITS).o misc.o string.o cmdline.o early_serial_console.o piggy.o
+targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xz vmlinux.bin.lzo
 
 KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2
 KBUILD_CFLAGS += -fno-strict-aliasing -fPIC
@@ -29,7 +29,6 @@ VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
        $(obj)/piggy.o
 
 $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
-$(obj)/efi_stub_$(BITS).o: KBUILD_CLFAGS += -fshort-wchar -mno-red-zone
 
 ifeq ($(CONFIG_EFI_STUB), y)
        VMLINUX_OBJS += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
@@ -43,7 +42,7 @@ OBJCOPYFLAGS_vmlinux.bin :=  -R .comment -S
 $(obj)/vmlinux.bin: vmlinux FORCE
        $(call if_changed,objcopy)
 
-targets += vmlinux.bin.all vmlinux.relocs
+targets += $(patsubst $(obj)/%,%,$(VMLINUX_OBJS)) vmlinux.bin.all vmlinux.relocs
 
 CMD_RELOCS = arch/x86/tools/relocs
 quiet_cmd_relocs = RELOCS  $@
index 1ace47b..2e188d6 100644 (file)
@@ -29,13 +29,13 @@ extern const unsigned long sys_call_table[];
  */
 static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
 {
-       return regs->orig_ax & __SYSCALL_MASK;
+       return regs->orig_ax;
 }
 
 static inline void syscall_rollback(struct task_struct *task,
                                    struct pt_regs *regs)
 {
-       regs->ax = regs->orig_ax & __SYSCALL_MASK;
+       regs->ax = regs->orig_ax;
 }
 
 static inline long syscall_get_error(struct task_struct *task,
index c20d1ce..e709884 100644 (file)
@@ -382,14 +382,14 @@ HYPERVISOR_console_io(int cmd, int count, char *str)
        return _hypercall3(int, console_io, cmd, count, str);
 }
 
-extern int __must_check HYPERVISOR_physdev_op_compat(int, void *);
+extern int __must_check xen_physdev_op_compat(int, void *);
 
 static inline int
 HYPERVISOR_physdev_op(int cmd, void *arg)
 {
        int rc = _hypercall2(int, physdev_op, cmd, arg);
        if (unlikely(rc == -ENOSYS))
-               rc = HYPERVISOR_physdev_op_compat(cmd, arg);
+               rc = xen_physdev_op_compat(cmd, arg);
        return rc;
 }
 
index 892ce40..7a060f4 100644 (file)
@@ -44,6 +44,7 @@
 #define SNB_C1_AUTO_UNDEMOTE           (1UL << 27)
 #define SNB_C3_AUTO_UNDEMOTE           (1UL << 28)
 
+#define MSR_PLATFORM_INFO              0x000000ce
 #define MSR_MTRRcap                    0x000000fe
 #define MSR_IA32_BBL_CR_CTL            0x00000119
 #define MSR_IA32_BBL_CR_CTL3           0x0000011e
index 7890bc8..d893e8e 100644 (file)
@@ -90,13 +90,13 @@ microcode_phys(struct microcode_intel **mc_saved_tmp,
        struct microcode_intel ***mc_saved;
 
        mc_saved = (struct microcode_intel ***)
-                  __pa_symbol(&mc_saved_data->mc_saved);
+                  __pa_nodebug(&mc_saved_data->mc_saved);
        for (i = 0; i < mc_saved_data->mc_saved_count; i++) {
                struct microcode_intel *p;
 
                p = *(struct microcode_intel **)
-                       __pa(mc_saved_data->mc_saved + i);
-               mc_saved_tmp[i] = (struct microcode_intel *)__pa(p);
+                       __pa_nodebug(mc_saved_data->mc_saved + i);
+               mc_saved_tmp[i] = (struct microcode_intel *)__pa_nodebug(p);
        }
 }
 #endif
@@ -562,7 +562,7 @@ scan_microcode(unsigned long start, unsigned long end,
        struct cpio_data cd;
        long offset = 0;
 #ifdef CONFIG_X86_32
-       char *p = (char *)__pa_symbol(ucode_name);
+       char *p = (char *)__pa_nodebug(ucode_name);
 #else
        char *p = ucode_name;
 #endif
@@ -630,8 +630,8 @@ static void __cpuinit print_ucode(struct ucode_cpu_info *uci)
        if (mc_intel == NULL)
                return;
 
-       delay_ucode_info_p = (int *)__pa_symbol(&delay_ucode_info);
-       current_mc_date_p = (int *)__pa_symbol(&current_mc_date);
+       delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info);
+       current_mc_date_p = (int *)__pa_nodebug(&current_mc_date);
 
        *delay_ucode_info_p = 1;
        *current_mc_date_p = mc_intel->hdr.date;
@@ -659,8 +659,8 @@ static inline void __cpuinit print_ucode(struct ucode_cpu_info *uci)
 }
 #endif
 
-static int apply_microcode_early(struct mc_saved_data *mc_saved_data,
-                                struct ucode_cpu_info *uci)
+static int __cpuinit apply_microcode_early(struct mc_saved_data *mc_saved_data,
+                                          struct ucode_cpu_info *uci)
 {
        struct microcode_intel *mc_intel;
        unsigned int val[2];
@@ -741,15 +741,15 @@ load_ucode_intel_bsp(void)
 #ifdef CONFIG_X86_32
        struct boot_params *boot_params_p;
 
-       boot_params_p = (struct boot_params *)__pa_symbol(&boot_params);
+       boot_params_p = (struct boot_params *)__pa_nodebug(&boot_params);
        ramdisk_image = boot_params_p->hdr.ramdisk_image;
        ramdisk_size  = boot_params_p->hdr.ramdisk_size;
        initrd_start_early = ramdisk_image;
        initrd_end_early = initrd_start_early + ramdisk_size;
 
        _load_ucode_intel_bsp(
-               (struct mc_saved_data *)__pa_symbol(&mc_saved_data),
-               (unsigned long *)__pa_symbol(&mc_saved_in_initrd),
+               (struct mc_saved_data *)__pa_nodebug(&mc_saved_data),
+               (unsigned long *)__pa_nodebug(&mc_saved_in_initrd),
                initrd_start_early, initrd_end_early, &uci);
 #else
        ramdisk_image = boot_params.hdr.ramdisk_image;
@@ -772,10 +772,10 @@ void __cpuinit load_ucode_intel_ap(void)
        unsigned long *initrd_start_p;
 
        mc_saved_in_initrd_p =
-               (unsigned long *)__pa_symbol(mc_saved_in_initrd);
-       mc_saved_data_p = (struct mc_saved_data *)__pa_symbol(&mc_saved_data);
-       initrd_start_p = (unsigned long *)__pa_symbol(&initrd_start);
-       initrd_start_addr = (unsigned long)__pa_symbol(*initrd_start_p);
+               (unsigned long *)__pa_nodebug(mc_saved_in_initrd);
+       mc_saved_data_p = (struct mc_saved_data *)__pa_nodebug(&mc_saved_data);
+       initrd_start_p = (unsigned long *)__pa_nodebug(&initrd_start);
+       initrd_start_addr = (unsigned long)__pa_nodebug(*initrd_start_p);
 #else
        mc_saved_data_p = &mc_saved_data;
        mc_saved_in_initrd_p = mc_saved_in_initrd;
index 02b51dd..f77df1c 100644 (file)
@@ -1857,7 +1857,7 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data)
        if (!pv_eoi_enabled(vcpu))
                return 0;
        return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data,
-                                        addr);
+                                        addr, sizeof(u8));
 }
 
 void kvm_lapic_init(void)
index f19ac0a..e172132 100644 (file)
@@ -1823,7 +1823,8 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
                return 0;
        }
 
-       if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa))
+       if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.apf.data, gpa,
+                                       sizeof(u32)))
                return 1;
 
        vcpu->arch.apf.send_user_only = !(data & KVM_ASYNC_PF_SEND_ALWAYS);
@@ -1952,12 +1953,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
                gpa_offset = data & ~(PAGE_MASK | 1);
 
-               /* Check that the address is 32-byte aligned. */
-               if (gpa_offset & (sizeof(struct pvclock_vcpu_time_info) - 1))
-                       break;
-
                if (kvm_gfn_to_hva_cache_init(vcpu->kvm,
-                    &vcpu->arch.pv_time, data & ~1ULL))
+                    &vcpu->arch.pv_time, data & ~1ULL,
+                    sizeof(struct pvclock_vcpu_time_info)))
                        vcpu->arch.pv_time_enabled = false;
                else
                        vcpu->arch.pv_time_enabled = true;
@@ -1977,7 +1975,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        return 1;
 
                if (kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.st.stime,
-                                                       data & KVM_STEAL_VALID_BITS))
+                                               data & KVM_STEAL_VALID_BITS,
+                                               sizeof(struct kvm_steal_time)))
                        return 1;
 
                vcpu->arch.st.msr_val = data;
index 05928aa..906fea3 100644 (file)
@@ -74,10 +74,10 @@ copy_user_handle_tail(char *to, char *from, unsigned len, unsigned zerorest)
        char c;
        unsigned zero_len;
 
-       for (; len; --len) {
+       for (; len; --len, to++) {
                if (__get_user_nocheck(c, from++, sizeof(char)))
                        break;
-               if (__put_user_nocheck(c, to++, sizeof(char)))
+               if (__put_user_nocheck(c, to, sizeof(char)))
                        break;
        }
 
index e8e3493..6afbb2c 100644 (file)
@@ -1467,8 +1467,6 @@ static void __init xen_write_cr3_init(unsigned long cr3)
        __xen_write_cr3(true, cr3);
 
        xen_mc_issue(PARAVIRT_LAZY_CPU);  /* interrupts restored */
-
-       pv_mmu_ops.write_cr3 = &xen_write_cr3;
 }
 #endif
 
@@ -2122,6 +2120,7 @@ static void __init xen_post_allocator_init(void)
 #endif
 
 #ifdef CONFIG_X86_64
+       pv_mmu_ops.write_cr3 = &xen_write_cr3;
        SetPagePinned(virt_to_page(level3_user_vsyscall));
 #endif
        xen_mark_init_mm_pinned();
index db8f1b5..cc2b827 100644 (file)
@@ -444,7 +444,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
         * copied from blk_rq_pos(rq).
         */
        if (error_sector)
-               *error_sector = bio->bi_sector;
+               *error_sector = bio->bi_sector;
 
        if (!bio_flagged(bio, BIO_UPTODATE))
                ret = -EIO;
index 789cdea..ae95ee6 100644 (file)
@@ -257,6 +257,7 @@ void delete_partition(struct gendisk *disk, int partno)
 
        hd_struct_put(part);
 }
+EXPORT_SYMBOL(delete_partition);
 
 static ssize_t whole_disk_show(struct device *dev,
                               struct device_attribute *attr, char *buf)
index 92ed969..4bf68c8 100644 (file)
@@ -396,7 +396,7 @@ config ACPI_CUSTOM_METHOD
 
 config ACPI_BGRT
        bool "Boottime Graphics Resource Table support"
-       depends on EFI
+       depends on EFI && X86
         help
          This driver adds support for exposing the ACPI Boottime Graphics
          Resource Table, which allows the operating system to obtain
index 82045e3..a82c762 100644 (file)
@@ -90,7 +90,7 @@ void acpi_i2c_register_devices(struct i2c_adapter *adapter)
        acpi_handle handle;
        acpi_status status;
 
-       handle = ACPI_HANDLE(&adapter->dev);
+       handle = ACPI_HANDLE(adapter->dev.parent);
        if (!handle)
                return;
 
index 1e5d8a4..fefc2ca 100644 (file)
@@ -405,7 +405,7 @@ int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
                return rc;
        data_len = estatus->data_length;
        gdata = (struct acpi_hest_generic_data *)(estatus + 1);
-       while (data_len > sizeof(*gdata)) {
+       while (data_len >= sizeof(*gdata)) {
                gedata_len = gdata->error_data_length;
                if (gedata_len > data_len - sizeof(*gdata))
                        return -EINVAL;
index 0ac546d..6ae5e44 100644 (file)
@@ -415,7 +415,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
        struct acpi_pci_root *root;
        struct acpi_pci_driver *driver;
        u32 flags, base_flags;
-       bool is_osc_granted = false;
 
        root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
        if (!root)
@@ -476,6 +475,30 @@ static int acpi_pci_root_add(struct acpi_device *device,
        flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
        acpi_pci_osc_support(root, flags);
 
+       /*
+        * TBD: Need PCI interface for enumeration/configuration of roots.
+        */
+
+       mutex_lock(&acpi_pci_root_lock);
+       list_add_tail(&root->node, &acpi_pci_roots);
+       mutex_unlock(&acpi_pci_root_lock);
+
+       /*
+        * Scan the Root Bridge
+        * --------------------
+        * Must do this prior to any attempt to bind the root device, as the
+        * PCI namespace does not get created until this call is made (and
+        * thus the root bridge's pci_dev does not exist).
+        */
+       root->bus = pci_acpi_scan_root(root);
+       if (!root->bus) {
+               printk(KERN_ERR PREFIX
+                           "Bus %04x:%02x not present in PCI namespace\n",
+                           root->segment, (unsigned int)root->secondary.start);
+               result = -ENODEV;
+               goto out_del_root;
+       }
+
        /* Indicate support for various _OSC capabilities. */
        if (pci_ext_cfg_avail())
                flags |= OSC_EXT_PCI_CONFIG_SUPPORT;
@@ -494,6 +517,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
                        flags = base_flags;
                }
        }
+
        if (!pcie_ports_disabled
            && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
                flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL
@@ -514,54 +538,28 @@ static int acpi_pci_root_add(struct acpi_device *device,
                status = acpi_pci_osc_control_set(device->handle, &flags,
                                       OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
                if (ACPI_SUCCESS(status)) {
-                       is_osc_granted = true;
                        dev_info(&device->dev,
                                "ACPI _OSC control (0x%02x) granted\n", flags);
+                       if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {
+                               /*
+                                * We have ASPM control, but the FADT indicates
+                                * that it's unsupported. Clear it.
+                                */
+                               pcie_clear_aspm(root->bus);
+                       }
                } else {
-                       is_osc_granted = false;
                        dev_info(&device->dev,
                                "ACPI _OSC request failed (%s), "
                                "returned control mask: 0x%02x\n",
                                acpi_format_exception(status), flags);
+                       pr_info("ACPI _OSC control for PCIe not granted, "
+                               "disabling ASPM\n");
+                       pcie_no_aspm();
                }
        } else {
                dev_info(&device->dev,
-                       "Unable to request _OSC control "
-                       "(_OSC support mask: 0x%02x)\n", flags);
-       }
-
-       /*
-        * TBD: Need PCI interface for enumeration/configuration of roots.
-        */
-
-       mutex_lock(&acpi_pci_root_lock);
-       list_add_tail(&root->node, &acpi_pci_roots);
-       mutex_unlock(&acpi_pci_root_lock);
-
-       /*
-        * Scan the Root Bridge
-        * --------------------
-        * Must do this prior to any attempt to bind the root device, as the
-        * PCI namespace does not get created until this call is made (and 
-        * thus the root bridge's pci_dev does not exist).
-        */
-       root->bus = pci_acpi_scan_root(root);
-       if (!root->bus) {
-               printk(KERN_ERR PREFIX
-                           "Bus %04x:%02x not present in PCI namespace\n",
-                           root->segment, (unsigned int)root->secondary.start);
-               result = -ENODEV;
-               goto out_del_root;
-       }
-
-       /* ASPM setting */
-       if (is_osc_granted) {
-               if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM)
-                       pcie_clear_aspm(root->bus);
-       } else {
-               pr_info("ACPI _OSC control for PCIe not granted, "
-                       "disabling ASPM\n");
-               pcie_no_aspm();
+                        "Unable to request _OSC control "
+                        "(_OSC support mask: 0x%02x)\n", flags);
        }
 
        pci_acpi_add_bus_pm_notifier(device, root->bus);
@@ -646,6 +644,7 @@ static void handle_root_bridge_insertion(acpi_handle handle)
 
 static void handle_root_bridge_removal(struct acpi_device *device)
 {
+       acpi_status status;
        struct acpi_eject_event *ej_event;
 
        ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
@@ -661,7 +660,9 @@ static void handle_root_bridge_removal(struct acpi_device *device)
        ej_event->device = device;
        ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
 
-       acpi_bus_hot_remove_device(ej_event);
+       status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
+       if (ACPI_FAILURE(status))
+               kfree(ej_event);
 }
 
 static void _handle_hotplug_event_root(struct work_struct *work)
@@ -676,8 +677,9 @@ static void _handle_hotplug_event_root(struct work_struct *work)
        handle = hp_work->handle;
        type = hp_work->type;
 
-       root = acpi_pci_find_root(handle);
+       acpi_scan_lock_acquire();
 
+       root = acpi_pci_find_root(handle);
        acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
 
        switch (type) {
@@ -711,6 +713,7 @@ static void _handle_hotplug_event_root(struct work_struct *work)
                break;
        }
 
+       acpi_scan_lock_release();
        kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
        kfree(buffer.pointer);
 }
index fc95308..ee255c6 100644 (file)
@@ -66,7 +66,8 @@ module_param(latency_factor, uint, 0644);
 
 static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device);
 
-static struct acpi_processor_cx *acpi_cstate[CPUIDLE_STATE_MAX];
+static DEFINE_PER_CPU(struct acpi_processor_cx * [CPUIDLE_STATE_MAX],
+                                                               acpi_cstate);
 
 static int disabled_by_idle_boot_param(void)
 {
@@ -722,7 +723,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
                struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor *pr;
-       struct acpi_processor_cx *cx = acpi_cstate[index];
+       struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
 
        pr = __this_cpu_read(processors);
 
@@ -745,7 +746,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
  */
 static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
 {
-       struct acpi_processor_cx *cx = acpi_cstate[index];
+       struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
 
        ACPI_FLUSH_CPU_CACHE();
 
@@ -775,7 +776,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor *pr;
-       struct acpi_processor_cx *cx = acpi_cstate[index];
+       struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
 
        pr = __this_cpu_read(processors);
 
@@ -833,7 +834,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                struct cpuidle_driver *drv, int index)
 {
        struct acpi_processor *pr;
-       struct acpi_processor_cx *cx = acpi_cstate[index];
+       struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
 
        pr = __this_cpu_read(processors);
 
@@ -960,7 +961,7 @@ static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr,
                    !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
                        continue;
 #endif
-               acpi_cstate[count] = cx;
+               per_cpu(acpi_cstate[count], dev->cpu) = cx;
 
                count++;
                if (count == CPUIDLE_STATE_MAX)
index 2421303..9c1a435 100644 (file)
@@ -193,6 +193,14 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
        },
        {
        .callback = init_nvs_nosave,
+       .ident = "Sony Vaio VGN-FW21M",
+       .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FW21M"),
+               },
+       },
+       {
+       .callback = init_nvs_nosave,
        .ident = "Sony Vaio VPCEB17FX",
        .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
index 5f74587..71671c4 100644 (file)
@@ -46,6 +46,7 @@
 #include "power.h"
 
 static DEFINE_MUTEX(dev_pm_qos_mtx);
+static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
 
 static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
 
@@ -216,12 +217,17 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
        struct pm_qos_constraints *c;
        struct pm_qos_flags *f;
 
-       mutex_lock(&dev_pm_qos_mtx);
+       mutex_lock(&dev_pm_qos_sysfs_mtx);
 
        /*
         * If the device's PM QoS resume latency limit or PM QoS flags have been
         * exposed to user space, they have to be hidden at this point.
         */
+       pm_qos_sysfs_remove_latency(dev);
+       pm_qos_sysfs_remove_flags(dev);
+
+       mutex_lock(&dev_pm_qos_mtx);
+
        __dev_pm_qos_hide_latency_limit(dev);
        __dev_pm_qos_hide_flags(dev);
 
@@ -254,6 +260,8 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
 
  out:
        mutex_unlock(&dev_pm_qos_mtx);
+
+       mutex_unlock(&dev_pm_qos_sysfs_mtx);
 }
 
 /**
@@ -558,6 +566,14 @@ static void __dev_pm_qos_drop_user_request(struct device *dev,
        kfree(req);
 }
 
+static void dev_pm_qos_drop_user_request(struct device *dev,
+                                        enum dev_pm_qos_req_type type)
+{
+       mutex_lock(&dev_pm_qos_mtx);
+       __dev_pm_qos_drop_user_request(dev, type);
+       mutex_unlock(&dev_pm_qos_mtx);
+}
+
 /**
  * dev_pm_qos_expose_latency_limit - Expose PM QoS latency limit to user space.
  * @dev: Device whose PM QoS latency limit is to be exposed to user space.
@@ -581,6 +597,8 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
                return ret;
        }
 
+       mutex_lock(&dev_pm_qos_sysfs_mtx);
+
        mutex_lock(&dev_pm_qos_mtx);
 
        if (IS_ERR_OR_NULL(dev->power.qos))
@@ -591,26 +609,27 @@ int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
        if (ret < 0) {
                __dev_pm_qos_remove_request(req);
                kfree(req);
+               mutex_unlock(&dev_pm_qos_mtx);
                goto out;
        }
-
        dev->power.qos->latency_req = req;
+
+       mutex_unlock(&dev_pm_qos_mtx);
+
        ret = pm_qos_sysfs_add_latency(dev);
        if (ret)
-               __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
+               dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
 
  out:
-       mutex_unlock(&dev_pm_qos_mtx);
+       mutex_unlock(&dev_pm_qos_sysfs_mtx);
        return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_limit);
 
 static void __dev_pm_qos_hide_latency_limit(struct device *dev)
 {
-       if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req) {
-               pm_qos_sysfs_remove_latency(dev);
+       if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->latency_req)
                __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_LATENCY);
-       }
 }
 
 /**
@@ -619,9 +638,15 @@ static void __dev_pm_qos_hide_latency_limit(struct device *dev)
  */
 void dev_pm_qos_hide_latency_limit(struct device *dev)
 {
+       mutex_lock(&dev_pm_qos_sysfs_mtx);
+
+       pm_qos_sysfs_remove_latency(dev);
+
        mutex_lock(&dev_pm_qos_mtx);
        __dev_pm_qos_hide_latency_limit(dev);
        mutex_unlock(&dev_pm_qos_mtx);
+
+       mutex_unlock(&dev_pm_qos_sysfs_mtx);
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_limit);
 
@@ -649,6 +674,8 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)
        }
 
        pm_runtime_get_sync(dev);
+       mutex_lock(&dev_pm_qos_sysfs_mtx);
+
        mutex_lock(&dev_pm_qos_mtx);
 
        if (IS_ERR_OR_NULL(dev->power.qos))
@@ -659,16 +686,19 @@ int dev_pm_qos_expose_flags(struct device *dev, s32 val)
        if (ret < 0) {
                __dev_pm_qos_remove_request(req);
                kfree(req);
+               mutex_unlock(&dev_pm_qos_mtx);
                goto out;
        }
-
        dev->power.qos->flags_req = req;
+
+       mutex_unlock(&dev_pm_qos_mtx);
+
        ret = pm_qos_sysfs_add_flags(dev);
        if (ret)
-               __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
+               dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
 
  out:
-       mutex_unlock(&dev_pm_qos_mtx);
+       mutex_unlock(&dev_pm_qos_sysfs_mtx);
        pm_runtime_put(dev);
        return ret;
 }
@@ -676,10 +706,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_expose_flags);
 
 static void __dev_pm_qos_hide_flags(struct device *dev)
 {
-       if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req) {
-               pm_qos_sysfs_remove_flags(dev);
+       if (!IS_ERR_OR_NULL(dev->power.qos) && dev->power.qos->flags_req)
                __dev_pm_qos_drop_user_request(dev, DEV_PM_QOS_FLAGS);
-       }
 }
 
 /**
@@ -689,9 +717,15 @@ static void __dev_pm_qos_hide_flags(struct device *dev)
 void dev_pm_qos_hide_flags(struct device *dev)
 {
        pm_runtime_get_sync(dev);
+       mutex_lock(&dev_pm_qos_sysfs_mtx);
+
+       pm_qos_sysfs_remove_flags(dev);
+
        mutex_lock(&dev_pm_qos_mtx);
        __dev_pm_qos_hide_flags(dev);
        mutex_unlock(&dev_pm_qos_mtx);
+
+       mutex_unlock(&dev_pm_qos_sysfs_mtx);
        pm_runtime_put(dev);
 }
 EXPORT_SYMBOL_GPL(dev_pm_qos_hide_flags);
index e6732cf..79f4fca 100644 (file)
@@ -398,7 +398,7 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min,
                        base = 0;
 
                if (max < rbnode->base_reg + rbnode->blklen)
-                       end = rbnode->base_reg + rbnode->blklen - max;
+                       end = max - rbnode->base_reg + 1;
                else
                        end = rbnode->blklen;
 
index 3d23675..d34adef 100644 (file)
@@ -710,12 +710,12 @@ skip_format_initialization:
                }
        }
 
+       regmap_debugfs_init(map, config->name);
+
        ret = regcache_init(map, config);
        if (ret != 0)
                goto err_range;
 
-       regmap_debugfs_init(map, config->name);
-
        /* Add a devres resource for dev_get_regmap() */
        m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
        if (!m) {
@@ -943,8 +943,7 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                unsigned int ival;
                int val_bytes = map->format.val_bytes;
                for (i = 0; i < val_len / val_bytes; i++) {
-                       memcpy(map->work_buf, val + (i * val_bytes), val_bytes);
-                       ival = map->format.parse_val(map->work_buf);
+                       ival = map->format.parse_val(val + (i * val_bytes));
                        ret = regcache_write(map, reg + (i * map->reg_stride),
                                             ival);
                        if (ret) {
@@ -1036,6 +1035,8 @@ static int _regmap_raw_write(struct regmap *map, unsigned int reg,
                        kfree(async->work_buf);
                        kfree(async);
                }
+
+               return ret;
        }
 
        trace_regmap_hw_write_start(map->dev, reg,
index 5dc0dae..b81ddfe 100644 (file)
@@ -532,11 +532,11 @@ config BLK_DEV_RBD
          If unsure, say N.
 
 config BLK_DEV_RSXX
-       tristate "RamSam PCIe Flash SSD Device Driver"
+       tristate "IBM FlashSystem 70/80 PCIe SSD Device Driver"
        depends on PCI
        help
          Device driver for IBM's high speed PCIe SSD
-         storage devices: RamSan-70 and RamSan-80.
+         storage devices: FlashSystem-70 and FlashSystem-80.
 
          To compile this driver as a module, choose M here: the
          module will be called rsxx.
index 25ef5c0..92b6d7c 100644 (file)
@@ -51,8 +51,9 @@ new_skb(ulong len)
 {
        struct sk_buff *skb;
 
-       skb = alloc_skb(len, GFP_ATOMIC);
+       skb = alloc_skb(len + MAX_HEADER, GFP_ATOMIC);
        if (skb) {
+               skb_reserve(skb, MAX_HEADER);
                skb_reset_mac_header(skb);
                skb_reset_network_header(skb);
                skb->protocol = __constant_htons(ETH_P_AOE);
index ade58bc..1c1b8e5 100644 (file)
@@ -4206,7 +4206,7 @@ static int cciss_find_cfgtables(ctlr_info_t *h)
        if (rc)
                return rc;
        h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
-               cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable));
+               cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
        if (!h->cfgtable)
                return -ENOMEM;
        rc = write_driver_ver_to_cfgtable(h->cfgtable);
index 747bb2a..2c127f9 100644 (file)
@@ -922,6 +922,11 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
                lo->lo_flags |= LO_FLAGS_PARTSCAN;
        if (lo->lo_flags & LO_FLAGS_PARTSCAN)
                ioctl_by_bdev(bdev, BLKRRPART, 0);
+
+       /* Grab the block_device to prevent its destruction after we
+        * put /dev/loopXX inode. Later in loop_clr_fd() we bdput(bdev).
+        */
+       bdgrab(bdev);
        return 0;
 
 out_clr:
@@ -1031,8 +1036,10 @@ static int loop_clr_fd(struct loop_device *lo)
        memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
        memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
        memset(lo->lo_file_name, 0, LO_NAME_SIZE);
-       if (bdev)
+       if (bdev) {
+               bdput(bdev);
                invalidate_bdev(bdev);
+       }
        set_capacity(lo->lo_disk, 0);
        loop_sysfs_exit(lo);
        if (bdev) {
@@ -1044,12 +1051,29 @@ static int loop_clr_fd(struct loop_device *lo)
        lo->lo_state = Lo_unbound;
        /* This is safe: open() is still holding a reference. */
        module_put(THIS_MODULE);
-       if (lo->lo_flags & LO_FLAGS_PARTSCAN && bdev)
-               ioctl_by_bdev(bdev, BLKRRPART, 0);
        lo->lo_flags = 0;
        if (!part_shift)
                lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN;
        mutex_unlock(&lo->lo_ctl_mutex);
+
+       /*
+        * Remove all partitions, since BLKRRPART won't remove user
+        * added partitions when max_part=0
+        */
+       if (bdev) {
+               struct disk_part_iter piter;
+               struct hd_struct *part;
+
+               mutex_lock_nested(&bdev->bd_mutex, 1);
+               invalidate_partition(bdev->bd_disk, 0);
+               disk_part_iter_init(&piter, bdev->bd_disk,
+                                       DISK_PITER_INCL_EMPTY);
+               while ((part = disk_part_iter_next(&piter)))
+                       delete_partition(bdev->bd_disk, part->partno);
+               disk_part_iter_exit(&piter);
+               mutex_unlock(&bdev->bd_mutex);
+       }
+
        /*
         * Need not hold lo_ctl_mutex to fput backing file.
         * Calling fput holding lo_ctl_mutex triggers a circular
@@ -1623,6 +1647,7 @@ static int loop_add(struct loop_device **l, int i)
                goto out_free_dev;
        i = err;
 
+       err = -ENOMEM;
        lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
        if (!lo->lo_queue)
                goto out_free_dev;
index 1788f49..076ae7f 100644 (file)
@@ -890,8 +890,10 @@ static int mg_probe(struct platform_device *plat_dev)
        gpio_direction_output(host->rst, 1);
 
        /* reset out pin */
-       if (!(prv_data->dev_attr & MG_DEV_MASK))
+       if (!(prv_data->dev_attr & MG_DEV_MASK)) {
+               err = -EINVAL;
                goto probe_err_3a;
+       }
 
        if (prv_data->dev_attr != MG_BOOT_DEV) {
                rsc = platform_get_resource_byname(plat_dev, IORESOURCE_IO,
index 11cc952..92250af 100644 (file)
@@ -4224,6 +4224,7 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        dd->isr_workq = create_workqueue(dd->workq_name);
        if (!dd->isr_workq) {
                dev_warn(&pdev->dev, "Can't create wq %d\n", dd->instance);
+               rv = -ENOMEM;
                goto block_initialize_err;
        }
 
@@ -4282,7 +4283,8 @@ static int mtip_pci_probe(struct pci_dev *pdev,
        INIT_WORK(&dd->work[7].work, mtip_workq_sdbf7);
 
        pci_set_master(pdev);
-       if (pci_enable_msi(pdev)) {
+       rv = pci_enable_msi(pdev);
+       if (rv) {
                dev_warn(&pdev->dev,
                        "Unable to enable MSI interrupt.\n");
                goto block_initialize_err;
index 6c81a4c..f556f8a 100644 (file)
@@ -1264,6 +1264,32 @@ static bool obj_request_done_test(struct rbd_obj_request *obj_request)
        return atomic_read(&obj_request->done) != 0;
 }
 
+static void
+rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
+{
+       dout("%s: obj %p img %p result %d %llu/%llu\n", __func__,
+               obj_request, obj_request->img_request, obj_request->result,
+               obj_request->xferred, obj_request->length);
+       /*
+        * ENOENT means a hole in the image.  We zero-fill the
+        * entire length of the request.  A short read also implies
+        * zero-fill to the end of the request.  Either way we
+        * update the xferred count to indicate the whole request
+        * was satisfied.
+        */
+       BUG_ON(obj_request->type != OBJ_REQUEST_BIO);
+       if (obj_request->result == -ENOENT) {
+               zero_bio_chain(obj_request->bio_list, 0);
+               obj_request->result = 0;
+               obj_request->xferred = obj_request->length;
+       } else if (obj_request->xferred < obj_request->length &&
+                       !obj_request->result) {
+               zero_bio_chain(obj_request->bio_list, obj_request->xferred);
+               obj_request->xferred = obj_request->length;
+       }
+       obj_request_done_set(obj_request);
+}
+
 static void rbd_obj_request_complete(struct rbd_obj_request *obj_request)
 {
        dout("%s: obj %p cb %p\n", __func__, obj_request,
@@ -1284,23 +1310,10 @@ static void rbd_osd_read_callback(struct rbd_obj_request *obj_request)
 {
        dout("%s: obj %p result %d %llu/%llu\n", __func__, obj_request,
                obj_request->result, obj_request->xferred, obj_request->length);
-       /*
-        * ENOENT means a hole in the object.  We zero-fill the
-        * entire length of the request.  A short read also implies
-        * zero-fill to the end of the request.  Either way we
-        * update the xferred count to indicate the whole request
-        * was satisfied.
-        */
-       if (obj_request->result == -ENOENT) {
-               zero_bio_chain(obj_request->bio_list, 0);
-               obj_request->result = 0;
-               obj_request->xferred = obj_request->length;
-       } else if (obj_request->xferred < obj_request->length &&
-                       !obj_request->result) {
-               zero_bio_chain(obj_request->bio_list, obj_request->xferred);
-               obj_request->xferred = obj_request->length;
-       }
-       obj_request_done_set(obj_request);
+       if (obj_request->img_request)
+               rbd_img_obj_request_read_callback(obj_request);
+       else
+               obj_request_done_set(obj_request);
 }
 
 static void rbd_osd_write_callback(struct rbd_obj_request *obj_request)
index f35cd0b..b1c53c0 100644 (file)
@@ -1,2 +1,2 @@
 obj-$(CONFIG_BLK_DEV_RSXX) += rsxx.o
-rsxx-y := config.o core.o cregs.o dev.o dma.o
+rsxx-objs := config.o core.o cregs.o dev.o dma.o
index a295e7e..10cd530 100644 (file)
 #include "rsxx_priv.h"
 #include "rsxx_cfg.h"
 
-static void initialize_config(void *config)
+static void initialize_config(struct rsxx_card_cfg *cfg)
 {
-       struct rsxx_card_cfg *cfg = config;
-
        cfg->hdr.version = RSXX_CFG_VERSION;
 
        cfg->data.block_size        = RSXX_HW_BLK_SIZE;
        cfg->data.stripe_size       = RSXX_HW_BLK_SIZE;
-       cfg->data.vendor_id         = RSXX_VENDOR_ID_TMS_IBM;
+       cfg->data.vendor_id         = RSXX_VENDOR_ID_IBM;
        cfg->data.cache_order       = (-1);
        cfg->data.intr_coal.mode    = RSXX_INTR_COAL_DISABLED;
        cfg->data.intr_coal.count   = 0;
@@ -181,7 +179,7 @@ int rsxx_load_config(struct rsxx_cardinfo *card)
        } else {
                dev_info(CARD_TO_DEV(card),
                        "Initializing card configuration.\n");
-               initialize_config(card);
+               initialize_config(&card->config);
                st = rsxx_save_config(card);
                if (st)
                        return st;
index e516248..5af21f2 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/bitops.h>
+#include <linux/delay.h>
 
 #include <linux/genhd.h>
 #include <linux/idr.h>
@@ -39,8 +40,8 @@
 
 #define NO_LEGACY 0
 
-MODULE_DESCRIPTION("IBM RamSan PCIe Flash SSD Device Driver");
-MODULE_AUTHOR("IBM <support@ramsan.com>");
+MODULE_DESCRIPTION("IBM FlashSystem 70/80 PCIe SSD Device Driver");
+MODULE_AUTHOR("Joshua Morris/Philip Kelleher, IBM");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRIVER_VERSION);
 
@@ -52,6 +53,13 @@ static DEFINE_IDA(rsxx_disk_ida);
 static DEFINE_SPINLOCK(rsxx_ida_lock);
 
 /*----------------- Interrupt Control & Handling -------------------*/
+
+static void rsxx_mask_interrupts(struct rsxx_cardinfo *card)
+{
+       card->isr_mask = 0;
+       card->ier_mask = 0;
+}
+
 static void __enable_intr(unsigned int *mask, unsigned int intr)
 {
        *mask |= intr;
@@ -71,7 +79,8 @@ static void __disable_intr(unsigned int *mask, unsigned int intr)
  */
 void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr)
 {
-       if (unlikely(card->halt))
+       if (unlikely(card->halt) ||
+           unlikely(card->eeh_state))
                return;
 
        __enable_intr(&card->ier_mask, intr);
@@ -80,6 +89,9 @@ void rsxx_enable_ier(struct rsxx_cardinfo *card, unsigned int intr)
 
 void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr)
 {
+       if (unlikely(card->eeh_state))
+               return;
+
        __disable_intr(&card->ier_mask, intr);
        iowrite32(card->ier_mask, card->regmap + IER);
 }
@@ -87,7 +99,8 @@ void rsxx_disable_ier(struct rsxx_cardinfo *card, unsigned int intr)
 void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card,
                                 unsigned int intr)
 {
-       if (unlikely(card->halt))
+       if (unlikely(card->halt) ||
+           unlikely(card->eeh_state))
                return;
 
        __enable_intr(&card->isr_mask, intr);
@@ -97,6 +110,9 @@ void rsxx_enable_ier_and_isr(struct rsxx_cardinfo *card,
 void rsxx_disable_ier_and_isr(struct rsxx_cardinfo *card,
                                  unsigned int intr)
 {
+       if (unlikely(card->eeh_state))
+               return;
+
        __disable_intr(&card->isr_mask, intr);
        __disable_intr(&card->ier_mask, intr);
        iowrite32(card->ier_mask, card->regmap + IER);
@@ -115,6 +131,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata)
        do {
                reread_isr = 0;
 
+               if (unlikely(card->eeh_state))
+                       break;
+
                isr = ioread32(card->regmap + ISR);
                if (isr == 0xffffffff) {
                        /*
@@ -161,9 +180,9 @@ static irqreturn_t rsxx_isr(int irq, void *pdata)
 }
 
 /*----------------- Card Event Handler -------------------*/
-static char *rsxx_card_state_to_str(unsigned int state)
+static const char * const rsxx_card_state_to_str(unsigned int state)
 {
-       static char *state_strings[] = {
+       static const char * const state_strings[] = {
                "Unknown", "Shutdown", "Starting", "Formatting",
                "Uninitialized", "Good", "Shutting Down",
                "Fault", "Read Only Fault", "dStroying"
@@ -304,6 +323,192 @@ static int card_shutdown(struct rsxx_cardinfo *card)
        return 0;
 }
 
+static int rsxx_eeh_frozen(struct pci_dev *dev)
+{
+       struct rsxx_cardinfo *card = pci_get_drvdata(dev);
+       int i;
+       int st;
+
+       dev_warn(&dev->dev, "IBM FlashSystem PCI: preparing for slot reset.\n");
+
+       card->eeh_state = 1;
+       rsxx_mask_interrupts(card);
+
+       /*
+        * We need to guarantee that the write for eeh_state and masking
+        * interrupts does not become reordered. This will prevent a possible
+        * race condition with the EEH code.
+        */
+       wmb();
+
+       pci_disable_device(dev);
+
+       st = rsxx_eeh_save_issued_dmas(card);
+       if (st)
+               return st;
+
+       rsxx_eeh_save_issued_creg(card);
+
+       for (i = 0; i < card->n_targets; i++) {
+               if (card->ctrl[i].status.buf)
+                       pci_free_consistent(card->dev, STATUS_BUFFER_SIZE8,
+                                           card->ctrl[i].status.buf,
+                                           card->ctrl[i].status.dma_addr);
+               if (card->ctrl[i].cmd.buf)
+                       pci_free_consistent(card->dev, COMMAND_BUFFER_SIZE8,
+                                           card->ctrl[i].cmd.buf,
+                                           card->ctrl[i].cmd.dma_addr);
+       }
+
+       return 0;
+}
+
+static void rsxx_eeh_failure(struct pci_dev *dev)
+{
+       struct rsxx_cardinfo *card = pci_get_drvdata(dev);
+       int i;
+
+       dev_err(&dev->dev, "IBM FlashSystem PCI: disabling failed card.\n");
+
+       card->eeh_state = 1;
+
+       for (i = 0; i < card->n_targets; i++)
+               del_timer_sync(&card->ctrl[i].activity_timer);
+
+       rsxx_eeh_cancel_dmas(card);
+}
+
+static int rsxx_eeh_fifo_flush_poll(struct rsxx_cardinfo *card)
+{
+       unsigned int status;
+       int iter = 0;
+
+       /* We need to wait for the hardware to reset */
+       while (iter++ < 10) {
+               status = ioread32(card->regmap + PCI_RECONFIG);
+
+               if (status & RSXX_FLUSH_BUSY) {
+                       ssleep(1);
+                       continue;
+               }
+
+               if (status & RSXX_FLUSH_TIMEOUT)
+                       dev_warn(CARD_TO_DEV(card), "HW: flash controller timeout\n");
+               return 0;
+       }
+
+       /* Hardware failed resetting itself. */
+       return -1;
+}
+
+static pci_ers_result_t rsxx_error_detected(struct pci_dev *dev,
+                                           enum pci_channel_state error)
+{
+       int st;
+
+       if (dev->revision < RSXX_EEH_SUPPORT)
+               return PCI_ERS_RESULT_NONE;
+
+       if (error == pci_channel_io_perm_failure) {
+               rsxx_eeh_failure(dev);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       st = rsxx_eeh_frozen(dev);
+       if (st) {
+               dev_err(&dev->dev, "Slot reset setup failed\n");
+               rsxx_eeh_failure(dev);
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+static pci_ers_result_t rsxx_slot_reset(struct pci_dev *dev)
+{
+       struct rsxx_cardinfo *card = pci_get_drvdata(dev);
+       unsigned long flags;
+       int i;
+       int st;
+
+       dev_warn(&dev->dev,
+               "IBM FlashSystem PCI: recovering from slot reset.\n");
+
+       st = pci_enable_device(dev);
+       if (st)
+               goto failed_hw_setup;
+
+       pci_set_master(dev);
+
+       st = rsxx_eeh_fifo_flush_poll(card);
+       if (st)
+               goto failed_hw_setup;
+
+       rsxx_dma_queue_reset(card);
+
+       for (i = 0; i < card->n_targets; i++) {
+               st = rsxx_hw_buffers_init(dev, &card->ctrl[i]);
+               if (st)
+                       goto failed_hw_buffers_init;
+       }
+
+       if (card->config_valid)
+               rsxx_dma_configure(card);
+
+       /* Clears the ISR register from spurious interrupts */
+       st = ioread32(card->regmap + ISR);
+
+       card->eeh_state = 0;
+
+       st = rsxx_eeh_remap_dmas(card);
+       if (st)
+               goto failed_remap_dmas;
+
+       spin_lock_irqsave(&card->irq_lock, flags);
+       if (card->n_targets & RSXX_MAX_TARGETS)
+               rsxx_enable_ier_and_isr(card, CR_INTR_ALL_G);
+       else
+               rsxx_enable_ier_and_isr(card, CR_INTR_ALL_C);
+       spin_unlock_irqrestore(&card->irq_lock, flags);
+
+       rsxx_kick_creg_queue(card);
+
+       for (i = 0; i < card->n_targets; i++) {
+               spin_lock(&card->ctrl[i].queue_lock);
+               if (list_empty(&card->ctrl[i].queue)) {
+                       spin_unlock(&card->ctrl[i].queue_lock);
+                       continue;
+               }
+               spin_unlock(&card->ctrl[i].queue_lock);
+
+               queue_work(card->ctrl[i].issue_wq,
+                               &card->ctrl[i].issue_dma_work);
+       }
+
+       dev_info(&dev->dev, "IBM FlashSystem PCI: recovery complete.\n");
+
+       return PCI_ERS_RESULT_RECOVERED;
+
+failed_hw_buffers_init:
+failed_remap_dmas:
+       for (i = 0; i < card->n_targets; i++) {
+               if (card->ctrl[i].status.buf)
+                       pci_free_consistent(card->dev,
+                                       STATUS_BUFFER_SIZE8,
+                                       card->ctrl[i].status.buf,
+                                       card->ctrl[i].status.dma_addr);
+               if (card->ctrl[i].cmd.buf)
+                       pci_free_consistent(card->dev,
+                                       COMMAND_BUFFER_SIZE8,
+                                       card->ctrl[i].cmd.buf,
+                                       card->ctrl[i].cmd.dma_addr);
+       }
+failed_hw_setup:
+       rsxx_eeh_failure(dev);
+       return PCI_ERS_RESULT_DISCONNECT;
+
+}
+
 /*----------------- Driver Initialization & Setup -------------------*/
 /* Returns:   0 if the driver is compatible with the device
             -1 if the driver is NOT compatible with the device */
@@ -383,6 +588,7 @@ static int rsxx_pci_probe(struct pci_dev *dev,
 
        spin_lock_init(&card->irq_lock);
        card->halt = 0;
+       card->eeh_state = 0;
 
        spin_lock_irq(&card->irq_lock);
        rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
@@ -538,9 +744,6 @@ static void rsxx_pci_remove(struct pci_dev *dev)
        rsxx_disable_ier_and_isr(card, CR_INTR_EVENT);
        spin_unlock_irqrestore(&card->irq_lock, flags);
 
-       /* Prevent work_structs from re-queuing themselves. */
-       card->halt = 1;
-
        cancel_work_sync(&card->event_work);
 
        rsxx_destroy_dev(card);
@@ -549,6 +752,10 @@ static void rsxx_pci_remove(struct pci_dev *dev)
        spin_lock_irqsave(&card->irq_lock, flags);
        rsxx_disable_ier_and_isr(card, CR_INTR_ALL);
        spin_unlock_irqrestore(&card->irq_lock, flags);
+
+       /* Prevent work_structs from re-queuing themselves. */
+       card->halt = 1;
+
        free_irq(dev->irq, card);
 
        if (!force_legacy)
@@ -592,11 +799,14 @@ static void rsxx_pci_shutdown(struct pci_dev *dev)
        card_shutdown(card);
 }
 
+static const struct pci_error_handlers rsxx_err_handler = {
+       .error_detected = rsxx_error_detected,
+       .slot_reset     = rsxx_slot_reset,
+};
+
 static DEFINE_PCI_DEVICE_TABLE(rsxx_pci_ids) = {
-       {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70_FLASH)},
-       {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS70D_FLASH)},
-       {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS80_FLASH)},
-       {PCI_DEVICE(PCI_VENDOR_ID_TMS_IBM, PCI_DEVICE_ID_RS81_FLASH)},
+       {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS70_FLASH)},
+       {PCI_DEVICE(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_FS80_FLASH)},
        {0,},
 };
 
@@ -609,6 +819,7 @@ static struct pci_driver rsxx_pci_driver = {
        .remove         = rsxx_pci_remove,
        .suspend        = rsxx_pci_suspend,
        .shutdown       = rsxx_pci_shutdown,
+       .err_handler    = &rsxx_err_handler,
 };
 
 static int __init rsxx_core_init(void)
index 80bbe63..4b5c020 100644 (file)
@@ -58,7 +58,7 @@ static struct kmem_cache *creg_cmd_pool;
 #error Unknown endianess!!! Aborting...
 #endif
 
-static void copy_to_creg_data(struct rsxx_cardinfo *card,
+static int copy_to_creg_data(struct rsxx_cardinfo *card,
                              int cnt8,
                              void *buf,
                              unsigned int stream)
@@ -66,6 +66,9 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card,
        int i = 0;
        u32 *data = buf;
 
+       if (unlikely(card->eeh_state))
+               return -EIO;
+
        for (i = 0; cnt8 > 0; i++, cnt8 -= 4) {
                /*
                 * Firmware implementation makes it necessary to byte swap on
@@ -76,10 +79,12 @@ static void copy_to_creg_data(struct rsxx_cardinfo *card,
                else
                        iowrite32(data[i], card->regmap + CREG_DATA(i));
        }
+
+       return 0;
 }
 
 
-static void copy_from_creg_data(struct rsxx_cardinfo *card,
+static int copy_from_creg_data(struct rsxx_cardinfo *card,
                                int cnt8,
                                void *buf,
                                unsigned int stream)
@@ -87,6 +92,9 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card,
        int i = 0;
        u32 *data = buf;
 
+       if (unlikely(card->eeh_state))
+               return -EIO;
+
        for (i = 0; cnt8 > 0; i++, cnt8 -= 4) {
                /*
                 * Firmware implementation makes it necessary to byte swap on
@@ -97,41 +105,31 @@ static void copy_from_creg_data(struct rsxx_cardinfo *card,
                else
                        data[i] = ioread32(card->regmap + CREG_DATA(i));
        }
-}
-
-static struct creg_cmd *pop_active_cmd(struct rsxx_cardinfo *card)
-{
-       struct creg_cmd *cmd;
 
-       /*
-        * Spin lock is needed because this can be called in atomic/interrupt
-        * context.
-        */
-       spin_lock_bh(&card->creg_ctrl.lock);
-       cmd = card->creg_ctrl.active_cmd;
-       card->creg_ctrl.active_cmd = NULL;
-       spin_unlock_bh(&card->creg_ctrl.lock);
-
-       return cmd;
+       return 0;
 }
 
 static void creg_issue_cmd(struct rsxx_cardinfo *card, struct creg_cmd *cmd)
 {
+       int st;
+
+       if (unlikely(card->eeh_state))
+               return;
+
        iowrite32(cmd->addr, card->regmap + CREG_ADD);
        iowrite32(cmd->cnt8, card->regmap + CREG_CNT);
 
        if (cmd->op == CREG_OP_WRITE) {
-               if (cmd->buf)
-                       copy_to_creg_data(card, cmd->cnt8,
-                                         cmd->buf, cmd->stream);
+               if (cmd->buf) {
+                       st = copy_to_creg_data(card, cmd->cnt8,
+                                              cmd->buf, cmd->stream);
+                       if (st)
+                               return;
+               }
        }
 
-       /*
-        * Data copy must complete before initiating the command. This is
-        * needed for weakly ordered processors (i.e. PowerPC), so that all
-        * neccessary registers are written before we kick the hardware.
-        */
-       wmb();
+       if (unlikely(card->eeh_state))
+               return;
 
        /* Setting the valid bit will kick off the command. */
        iowrite32(cmd->op, card->regmap + CREG_CMD);
@@ -196,11 +194,11 @@ static int creg_queue_cmd(struct rsxx_cardinfo *card,
        cmd->cb_private = cb_private;
        cmd->status     = 0;
 
-       spin_lock(&card->creg_ctrl.lock);
+       spin_lock_bh(&card->creg_ctrl.lock);
        list_add_tail(&cmd->list, &card->creg_ctrl.queue);
        card->creg_ctrl.q_depth++;
        creg_kick_queue(card);
-       spin_unlock(&card->creg_ctrl.lock);
+       spin_unlock_bh(&card->creg_ctrl.lock);
 
        return 0;
 }
@@ -210,7 +208,11 @@ static void creg_cmd_timed_out(unsigned long data)
        struct rsxx_cardinfo *card = (struct rsxx_cardinfo *) data;
        struct creg_cmd *cmd;
 
-       cmd = pop_active_cmd(card);
+       spin_lock(&card->creg_ctrl.lock);
+       cmd = card->creg_ctrl.active_cmd;
+       card->creg_ctrl.active_cmd = NULL;
+       spin_unlock(&card->creg_ctrl.lock);
+
        if (cmd == NULL) {
                card->creg_ctrl.creg_stats.creg_timeout++;
                dev_warn(CARD_TO_DEV(card),
@@ -247,7 +249,11 @@ static void creg_cmd_done(struct work_struct *work)
        if (del_timer_sync(&card->creg_ctrl.cmd_timer) == 0)
                card->creg_ctrl.creg_stats.failed_cancel_timer++;
 
-       cmd = pop_active_cmd(card);
+       spin_lock_bh(&card->creg_ctrl.lock);
+       cmd = card->creg_ctrl.active_cmd;
+       card->creg_ctrl.active_cmd = NULL;
+       spin_unlock_bh(&card->creg_ctrl.lock);
+
        if (cmd == NULL) {
                dev_err(CARD_TO_DEV(card),
                        "Spurious creg interrupt!\n");
@@ -287,7 +293,7 @@ static void creg_cmd_done(struct work_struct *work)
                        goto creg_done;
                }
 
-               copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream);
+               st = copy_from_creg_data(card, cnt8, cmd->buf, cmd->stream);
        }
 
 creg_done:
@@ -296,10 +302,10 @@ creg_done:
 
        kmem_cache_free(creg_cmd_pool, cmd);
 
-       spin_lock(&card->creg_ctrl.lock);
+       spin_lock_bh(&card->creg_ctrl.lock);
        card->creg_ctrl.active = 0;
        creg_kick_queue(card);
-       spin_unlock(&card->creg_ctrl.lock);
+       spin_unlock_bh(&card->creg_ctrl.lock);
 }
 
 static void creg_reset(struct rsxx_cardinfo *card)
@@ -324,7 +330,7 @@ static void creg_reset(struct rsxx_cardinfo *card)
                "Resetting creg interface for recovery\n");
 
        /* Cancel outstanding commands */
-       spin_lock(&card->creg_ctrl.lock);
+       spin_lock_bh(&card->creg_ctrl.lock);
        list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) {
                list_del(&cmd->list);
                card->creg_ctrl.q_depth--;
@@ -345,7 +351,7 @@ static void creg_reset(struct rsxx_cardinfo *card)
 
                card->creg_ctrl.active = 0;
        }
-       spin_unlock(&card->creg_ctrl.lock);
+       spin_unlock_bh(&card->creg_ctrl.lock);
 
        card->creg_ctrl.reset = 0;
        spin_lock_irqsave(&card->irq_lock, flags);
@@ -399,12 +405,12 @@ static int __issue_creg_rw(struct rsxx_cardinfo *card,
                return st;
 
        /*
-        * This timeout is neccessary for unresponsive hardware. The additional
+        * This timeout is necessary for unresponsive hardware. The additional
         * 20 seconds to used to guarantee that each cregs requests has time to
         * complete.
         */
-       timeout = msecs_to_jiffies((CREG_TIMEOUT_MSEC *
-                               card->creg_ctrl.q_depth) + 20000);
+       timeout = msecs_to_jiffies(CREG_TIMEOUT_MSEC *
+                                  card->creg_ctrl.q_depth + 20000);
 
        /*
         * The creg interface is guaranteed to complete. It has a timeout
@@ -690,6 +696,32 @@ int rsxx_reg_access(struct rsxx_cardinfo *card,
        return 0;
 }
 
+void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card)
+{
+       struct creg_cmd *cmd = NULL;
+
+       cmd = card->creg_ctrl.active_cmd;
+       card->creg_ctrl.active_cmd = NULL;
+
+       if (cmd) {
+               del_timer_sync(&card->creg_ctrl.cmd_timer);
+
+               spin_lock_bh(&card->creg_ctrl.lock);
+               list_add(&cmd->list, &card->creg_ctrl.queue);
+               card->creg_ctrl.q_depth++;
+               card->creg_ctrl.active = 0;
+               spin_unlock_bh(&card->creg_ctrl.lock);
+       }
+}
+
+void rsxx_kick_creg_queue(struct rsxx_cardinfo *card)
+{
+       spin_lock_bh(&card->creg_ctrl.lock);
+       if (!list_empty(&card->creg_ctrl.queue))
+               creg_kick_queue(card);
+       spin_unlock_bh(&card->creg_ctrl.lock);
+}
+
 /*------------ Initialization & Setup --------------*/
 int rsxx_creg_setup(struct rsxx_cardinfo *card)
 {
@@ -712,7 +744,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card)
        int cnt = 0;
 
        /* Cancel outstanding commands */
-       spin_lock(&card->creg_ctrl.lock);
+       spin_lock_bh(&card->creg_ctrl.lock);
        list_for_each_entry_safe(cmd, tmp, &card->creg_ctrl.queue, list) {
                list_del(&cmd->list);
                if (cmd->cb)
@@ -737,7 +769,7 @@ void rsxx_creg_destroy(struct rsxx_cardinfo *card)
                        "Canceled active creg command\n");
                kmem_cache_free(creg_cmd_pool, cmd);
        }
-       spin_unlock(&card->creg_ctrl.lock);
+       spin_unlock_bh(&card->creg_ctrl.lock);
 
        cancel_work_sync(&card->creg_ctrl.done_work);
 }
index 63176e6..0607513 100644 (file)
@@ -28,7 +28,7 @@
 struct rsxx_dma {
        struct list_head         list;
        u8                       cmd;
-       unsigned int             laddr;     /* Logical address on the ramsan */
+       unsigned int             laddr;     /* Logical address */
        struct {
                u32              off;
                u32              cnt;
@@ -81,9 +81,6 @@ enum rsxx_hw_status {
        HW_STATUS_FAULT         = 0x08,
 };
 
-#define STATUS_BUFFER_SIZE8     4096
-#define COMMAND_BUFFER_SIZE8    4096
-
 static struct kmem_cache *rsxx_dma_pool;
 
 struct dma_tracker {
@@ -122,7 +119,7 @@ static unsigned int rsxx_get_dma_tgt(struct rsxx_cardinfo *card, u64 addr8)
        return tgt;
 }
 
-static void rsxx_dma_queue_reset(struct rsxx_cardinfo *card)
+void rsxx_dma_queue_reset(struct rsxx_cardinfo *card)
 {
        /* Reset all DMA Command/Status Queues */
        iowrite32(DMA_QUEUE_RESET, card->regmap + RESET);
@@ -210,7 +207,8 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card)
        u32 q_depth = 0;
        u32 intr_coal;
 
-       if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE)
+       if (card->config.data.intr_coal.mode != RSXX_INTR_COAL_AUTO_TUNE ||
+           unlikely(card->eeh_state))
                return;
 
        for (i = 0; i < card->n_targets; i++)
@@ -223,31 +221,26 @@ static void dma_intr_coal_auto_tune(struct rsxx_cardinfo *card)
 }
 
 /*----------------- RSXX DMA Handling -------------------*/
-static void rsxx_complete_dma(struct rsxx_cardinfo *card,
+static void rsxx_complete_dma(struct rsxx_dma_ctrl *ctrl,
                                  struct rsxx_dma *dma,
                                  unsigned int status)
 {
        if (status & DMA_SW_ERR)
-               printk_ratelimited(KERN_ERR
-                                  "SW Error in DMA(cmd x%02x, laddr x%08x)\n",
-                                  dma->cmd, dma->laddr);
+               ctrl->stats.dma_sw_err++;
        if (status & DMA_HW_FAULT)
-               printk_ratelimited(KERN_ERR
-                                  "HW Fault in DMA(cmd x%02x, laddr x%08x)\n",
-                                  dma->cmd, dma->laddr);
+               ctrl->stats.dma_hw_fault++;
        if (status & DMA_CANCELLED)
-               printk_ratelimited(KERN_ERR
-                                  "DMA Cancelled(cmd x%02x, laddr x%08x)\n",
-                                  dma->cmd, dma->laddr);
+               ctrl->stats.dma_cancelled++;
 
        if (dma->dma_addr)
-               pci_unmap_page(card->dev, dma->dma_addr, get_dma_size(dma),
+               pci_unmap_page(ctrl->card->dev, dma->dma_addr,
+                              get_dma_size(dma),
                               dma->cmd == HW_CMD_BLK_WRITE ?
                                           PCI_DMA_TODEVICE :
                                           PCI_DMA_FROMDEVICE);
 
        if (dma->cb)
-               dma->cb(card, dma->cb_data, status ? 1 : 0);
+               dma->cb(ctrl->card, dma->cb_data, status ? 1 : 0);
 
        kmem_cache_free(rsxx_dma_pool, dma);
 }
@@ -330,14 +323,15 @@ static void rsxx_handle_dma_error(struct rsxx_dma_ctrl *ctrl,
        if (requeue_cmd)
                rsxx_requeue_dma(ctrl, dma);
        else
-               rsxx_complete_dma(ctrl->card, dma, status);
+               rsxx_complete_dma(ctrl, dma, status);
 }
 
 static void dma_engine_stalled(unsigned long data)
 {
        struct rsxx_dma_ctrl *ctrl = (struct rsxx_dma_ctrl *)data;
 
-       if (atomic_read(&ctrl->stats.hw_q_depth) == 0)
+       if (atomic_read(&ctrl->stats.hw_q_depth) == 0 ||
+           unlikely(ctrl->card->eeh_state))
                return;
 
        if (ctrl->cmd.idx != ioread32(ctrl->regmap + SW_CMD_IDX)) {
@@ -369,7 +363,8 @@ static void rsxx_issue_dmas(struct work_struct *work)
        ctrl = container_of(work, struct rsxx_dma_ctrl, issue_dma_work);
        hw_cmd_buf = ctrl->cmd.buf;
 
-       if (unlikely(ctrl->card->halt))
+       if (unlikely(ctrl->card->halt) ||
+           unlikely(ctrl->card->eeh_state))
                return;
 
        while (1) {
@@ -397,7 +392,7 @@ static void rsxx_issue_dmas(struct work_struct *work)
                 */
                if (unlikely(ctrl->card->dma_fault)) {
                        push_tracker(ctrl->trackers, tag);
-                       rsxx_complete_dma(ctrl->card, dma, DMA_CANCELLED);
+                       rsxx_complete_dma(ctrl, dma, DMA_CANCELLED);
                        continue;
                }
 
@@ -432,19 +427,15 @@ static void rsxx_issue_dmas(struct work_struct *work)
 
        /* Let HW know we've queued commands. */
        if (cmds_pending) {
-               /*
-                * We must guarantee that the CPU writes to 'ctrl->cmd.buf'
-                * (which is in PCI-consistent system-memory) from the loop
-                * above make it into the coherency domain before the
-                * following PIO "trigger" updating the cmd.idx.  A WMB is
-                * sufficient. We need not explicitly CPU cache-flush since
-                * the memory is a PCI-consistent (ie; coherent) mapping.
-                */
-               wmb();
-
                atomic_add(cmds_pending, &ctrl->stats.hw_q_depth);
                mod_timer(&ctrl->activity_timer,
                          jiffies + DMA_ACTIVITY_TIMEOUT);
+
+               if (unlikely(ctrl->card->eeh_state)) {
+                       del_timer_sync(&ctrl->activity_timer);
+                       return;
+               }
+
                iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX);
        }
 }
@@ -463,7 +454,8 @@ static void rsxx_dma_done(struct work_struct *work)
        hw_st_buf = ctrl->status.buf;
 
        if (unlikely(ctrl->card->halt) ||
-           unlikely(ctrl->card->dma_fault))
+           unlikely(ctrl->card->dma_fault) ||
+           unlikely(ctrl->card->eeh_state))
                return;
 
        count = le16_to_cpu(hw_st_buf[ctrl->status.idx].count);
@@ -508,7 +500,7 @@ static void rsxx_dma_done(struct work_struct *work)
                if (status)
                        rsxx_handle_dma_error(ctrl, dma, status);
                else
-                       rsxx_complete_dma(ctrl->card, dma, 0);
+                       rsxx_complete_dma(ctrl, dma, 0);
 
                push_tracker(ctrl->trackers, tag);
 
@@ -727,20 +719,54 @@ bvec_err:
 
 
 /*----------------- DMA Engine Initialization & Setup -------------------*/
+int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl)
+{
+       ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8,
+                               &ctrl->status.dma_addr);
+       ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8,
+                               &ctrl->cmd.dma_addr);
+       if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL)
+               return -ENOMEM;
+
+       memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8);
+       iowrite32(lower_32_bits(ctrl->status.dma_addr),
+               ctrl->regmap + SB_ADD_LO);
+       iowrite32(upper_32_bits(ctrl->status.dma_addr),
+               ctrl->regmap + SB_ADD_HI);
+
+       memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8);
+       iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO);
+       iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI);
+
+       ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT);
+       if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) {
+               dev_crit(&dev->dev, "Failed reading status cnt x%x\n",
+                       ctrl->status.idx);
+               return -EINVAL;
+       }
+       iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT);
+       iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT);
+
+       ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX);
+       if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) {
+               dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n",
+                       ctrl->status.idx);
+               return -EINVAL;
+       }
+       iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX);
+       iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX);
+
+       return 0;
+}
+
 static int rsxx_dma_ctrl_init(struct pci_dev *dev,
                                  struct rsxx_dma_ctrl *ctrl)
 {
        int i;
+       int st;
 
        memset(&ctrl->stats, 0, sizeof(ctrl->stats));
 
-       ctrl->status.buf = pci_alloc_consistent(dev, STATUS_BUFFER_SIZE8,
-                                               &ctrl->status.dma_addr);
-       ctrl->cmd.buf = pci_alloc_consistent(dev, COMMAND_BUFFER_SIZE8,
-                                            &ctrl->cmd.dma_addr);
-       if (ctrl->status.buf == NULL || ctrl->cmd.buf == NULL)
-               return -ENOMEM;
-
        ctrl->trackers = vmalloc(DMA_TRACKER_LIST_SIZE8);
        if (!ctrl->trackers)
                return -ENOMEM;
@@ -770,35 +796,9 @@ static int rsxx_dma_ctrl_init(struct pci_dev *dev,
        INIT_WORK(&ctrl->issue_dma_work, rsxx_issue_dmas);
        INIT_WORK(&ctrl->dma_done_work, rsxx_dma_done);
 
-       memset(ctrl->status.buf, 0xac, STATUS_BUFFER_SIZE8);
-       iowrite32(lower_32_bits(ctrl->status.dma_addr),
-                 ctrl->regmap + SB_ADD_LO);
-       iowrite32(upper_32_bits(ctrl->status.dma_addr),
-                 ctrl->regmap + SB_ADD_HI);
-
-       memset(ctrl->cmd.buf, 0x83, COMMAND_BUFFER_SIZE8);
-       iowrite32(lower_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_LO);
-       iowrite32(upper_32_bits(ctrl->cmd.dma_addr), ctrl->regmap + CB_ADD_HI);
-
-       ctrl->status.idx = ioread32(ctrl->regmap + HW_STATUS_CNT);
-       if (ctrl->status.idx > RSXX_MAX_OUTSTANDING_CMDS) {
-               dev_crit(&dev->dev, "Failed reading status cnt x%x\n",
-                        ctrl->status.idx);
-               return -EINVAL;
-       }
-       iowrite32(ctrl->status.idx, ctrl->regmap + HW_STATUS_CNT);
-       iowrite32(ctrl->status.idx, ctrl->regmap + SW_STATUS_CNT);
-
-       ctrl->cmd.idx = ioread32(ctrl->regmap + HW_CMD_IDX);
-       if (ctrl->cmd.idx > RSXX_MAX_OUTSTANDING_CMDS) {
-               dev_crit(&dev->dev, "Failed reading cmd cnt x%x\n",
-                        ctrl->status.idx);
-               return -EINVAL;
-       }
-       iowrite32(ctrl->cmd.idx, ctrl->regmap + HW_CMD_IDX);
-       iowrite32(ctrl->cmd.idx, ctrl->regmap + SW_CMD_IDX);
-
-       wmb();
+       st = rsxx_hw_buffers_init(dev, ctrl);
+       if (st)
+               return st;
 
        return 0;
 }
@@ -834,7 +834,7 @@ static int rsxx_dma_stripe_setup(struct rsxx_cardinfo *card,
        return 0;
 }
 
-static int rsxx_dma_configure(struct rsxx_cardinfo *card)
+int rsxx_dma_configure(struct rsxx_cardinfo *card)
 {
        u32 intr_coal;
 
@@ -980,6 +980,103 @@ void rsxx_dma_destroy(struct rsxx_cardinfo *card)
        }
 }
 
+int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card)
+{
+       int i;
+       int j;
+       int cnt;
+       struct rsxx_dma *dma;
+       struct list_head *issued_dmas;
+
+       issued_dmas = kzalloc(sizeof(*issued_dmas) * card->n_targets,
+                             GFP_KERNEL);
+       if (!issued_dmas)
+               return -ENOMEM;
+
+       for (i = 0; i < card->n_targets; i++) {
+               INIT_LIST_HEAD(&issued_dmas[i]);
+               cnt = 0;
+               for (j = 0; j < RSXX_MAX_OUTSTANDING_CMDS; j++) {
+                       dma = get_tracker_dma(card->ctrl[i].trackers, j);
+                       if (dma == NULL)
+                               continue;
+
+                       if (dma->cmd == HW_CMD_BLK_WRITE)
+                               card->ctrl[i].stats.writes_issued--;
+                       else if (dma->cmd == HW_CMD_BLK_DISCARD)
+                               card->ctrl[i].stats.discards_issued--;
+                       else
+                               card->ctrl[i].stats.reads_issued--;
+
+                       list_add_tail(&dma->list, &issued_dmas[i]);
+                       push_tracker(card->ctrl[i].trackers, j);
+                       cnt++;
+               }
+
+               spin_lock(&card->ctrl[i].queue_lock);
+               list_splice(&issued_dmas[i], &card->ctrl[i].queue);
+
+               atomic_sub(cnt, &card->ctrl[i].stats.hw_q_depth);
+               card->ctrl[i].stats.sw_q_depth += cnt;
+               card->ctrl[i].e_cnt = 0;
+
+               list_for_each_entry(dma, &card->ctrl[i].queue, list) {
+                       if (dma->dma_addr)
+                               pci_unmap_page(card->dev, dma->dma_addr,
+                                              get_dma_size(dma),
+                                              dma->cmd == HW_CMD_BLK_WRITE ?
+                                              PCI_DMA_TODEVICE :
+                                              PCI_DMA_FROMDEVICE);
+               }
+               spin_unlock(&card->ctrl[i].queue_lock);
+       }
+
+       kfree(issued_dmas);
+
+       return 0;
+}
+
+void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card)
+{
+       struct rsxx_dma *dma;
+       struct rsxx_dma *tmp;
+       int i;
+
+       for (i = 0; i < card->n_targets; i++) {
+               spin_lock(&card->ctrl[i].queue_lock);
+               list_for_each_entry_safe(dma, tmp, &card->ctrl[i].queue, list) {
+                       list_del(&dma->list);
+
+                       rsxx_complete_dma(&card->ctrl[i], dma, DMA_CANCELLED);
+               }
+               spin_unlock(&card->ctrl[i].queue_lock);
+       }
+}
+
+int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card)
+{
+       struct rsxx_dma *dma;
+       int i;
+
+       for (i = 0; i < card->n_targets; i++) {
+               spin_lock(&card->ctrl[i].queue_lock);
+               list_for_each_entry(dma, &card->ctrl[i].queue, list) {
+                       dma->dma_addr = pci_map_page(card->dev, dma->page,
+                                       dma->pg_off, get_dma_size(dma),
+                                       dma->cmd == HW_CMD_BLK_WRITE ?
+                                       PCI_DMA_TODEVICE :
+                                       PCI_DMA_FROMDEVICE);
+                       if (!dma->dma_addr) {
+                               spin_unlock(&card->ctrl[i].queue_lock);
+                               kmem_cache_free(rsxx_dma_pool, dma);
+                               return -ENOMEM;
+                       }
+               }
+               spin_unlock(&card->ctrl[i].queue_lock);
+       }
+
+       return 0;
+}
 
 int rsxx_dma_init(void)
 {
index 2e50b65..24ba364 100644 (file)
 
 /*----------------- IOCTL Definitions -------------------*/
 
+#define RSXX_MAX_DATA 8
+
 struct rsxx_reg_access {
        __u32 addr;
        __u32 cnt;
        __u32 stat;
        __u32 stream;
-       __u32 data[8];
+       __u32 data[RSXX_MAX_DATA];
 };
 
-#define RSXX_MAX_REG_CNT       (8 * (sizeof(__u32)))
+#define RSXX_MAX_REG_CNT       (RSXX_MAX_DATA * (sizeof(__u32)))
 
 #define RSXX_IOC_MAGIC 'r'
 
index c025fe5..f384c94 100644 (file)
@@ -58,7 +58,7 @@ struct rsxx_card_cfg {
 };
 
 /* Vendor ID Values */
-#define RSXX_VENDOR_ID_TMS_IBM         0
+#define RSXX_VENDOR_ID_IBM             0
 #define RSXX_VENDOR_ID_DSI             1
 #define RSXX_VENDOR_COUNT              2
 
index a1ac907..382e8bf 100644 (file)
 
 struct proc_cmd;
 
-#define PCI_VENDOR_ID_TMS_IBM          0x15B6
-#define PCI_DEVICE_ID_RS70_FLASH       0x0019
-#define PCI_DEVICE_ID_RS70D_FLASH      0x001A
-#define PCI_DEVICE_ID_RS80_FLASH       0x001C
-#define PCI_DEVICE_ID_RS81_FLASH       0x001E
+#define PCI_DEVICE_ID_FS70_FLASH       0x04A9
+#define PCI_DEVICE_ID_FS80_FLASH       0x04AA
 
 #define RS70_PCI_REV_SUPPORTED 4
 
 #define DRIVER_NAME "rsxx"
-#define DRIVER_VERSION "3.7"
+#define DRIVER_VERSION "4.0"
 
 /* Block size is 4096 */
 #define RSXX_HW_BLK_SHIFT              12
@@ -67,6 +64,9 @@ struct proc_cmd;
 #define RSXX_MAX_OUTSTANDING_CMDS      255
 #define RSXX_CS_IDX_MASK               0xff
 
+#define STATUS_BUFFER_SIZE8     4096
+#define COMMAND_BUFFER_SIZE8    4096
+
 #define RSXX_MAX_TARGETS       8
 
 struct dma_tracker_list;
@@ -91,6 +91,9 @@ struct rsxx_dma_stats {
        u32 discards_failed;
        u32 done_rescheduled;
        u32 issue_rescheduled;
+       u32 dma_sw_err;
+       u32 dma_hw_fault;
+       u32 dma_cancelled;
        u32 sw_q_depth;         /* Number of DMAs on the SW queue. */
        atomic_t hw_q_depth;    /* Number of DMAs queued to HW. */
 };
@@ -116,6 +119,7 @@ struct rsxx_dma_ctrl {
 struct rsxx_cardinfo {
        struct pci_dev          *dev;
        unsigned int            halt;
+       unsigned int            eeh_state;
 
        void                    __iomem *regmap;
        spinlock_t              irq_lock;
@@ -224,6 +228,7 @@ enum rsxx_pci_regmap {
        PERF_RD512_HI   = 0xac,
        PERF_WR512_LO   = 0xb0,
        PERF_WR512_HI   = 0xb4,
+       PCI_RECONFIG    = 0xb8,
 };
 
 enum rsxx_intr {
@@ -237,6 +242,8 @@ enum rsxx_intr {
        CR_INTR_DMA5    = 0x00000080,
        CR_INTR_DMA6    = 0x00000100,
        CR_INTR_DMA7    = 0x00000200,
+       CR_INTR_ALL_C   = 0x0000003f,
+       CR_INTR_ALL_G   = 0x000003ff,
        CR_INTR_DMA_ALL = 0x000003f5,
        CR_INTR_ALL     = 0xffffffff,
 };
@@ -253,8 +260,14 @@ enum rsxx_pci_reset {
        DMA_QUEUE_RESET         = 0x00000001,
 };
 
+enum rsxx_hw_fifo_flush {
+       RSXX_FLUSH_BUSY         = 0x00000002,
+       RSXX_FLUSH_TIMEOUT      = 0x00000004,
+};
+
 enum rsxx_pci_revision {
        RSXX_DISCARD_SUPPORT = 2,
+       RSXX_EEH_SUPPORT     = 3,
 };
 
 enum rsxx_creg_cmd {
@@ -360,11 +373,17 @@ int rsxx_dma_setup(struct rsxx_cardinfo *card);
 void rsxx_dma_destroy(struct rsxx_cardinfo *card);
 int rsxx_dma_init(void);
 void rsxx_dma_cleanup(void);
+void rsxx_dma_queue_reset(struct rsxx_cardinfo *card);
+int rsxx_dma_configure(struct rsxx_cardinfo *card);
 int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
                           struct bio *bio,
                           atomic_t *n_dmas,
                           rsxx_dma_cb cb,
                           void *cb_data);
+int rsxx_hw_buffers_init(struct pci_dev *dev, struct rsxx_dma_ctrl *ctrl);
+int rsxx_eeh_save_issued_dmas(struct rsxx_cardinfo *card);
+void rsxx_eeh_cancel_dmas(struct rsxx_cardinfo *card);
+int rsxx_eeh_remap_dmas(struct rsxx_cardinfo *card);
 
 /***** cregs.c *****/
 int rsxx_creg_write(struct rsxx_cardinfo *card, u32 addr,
@@ -389,10 +408,11 @@ int rsxx_creg_setup(struct rsxx_cardinfo *card);
 void rsxx_creg_destroy(struct rsxx_cardinfo *card);
 int rsxx_creg_init(void);
 void rsxx_creg_cleanup(void);
-
 int rsxx_reg_access(struct rsxx_cardinfo *card,
                        struct rsxx_reg_access __user *ucmd,
                        int read);
+void rsxx_eeh_save_issued_creg(struct rsxx_cardinfo *card);
+void rsxx_kick_creg_queue(struct rsxx_cardinfo *card);
 
 
 
index de1f319..dd5b2fe 100644 (file)
@@ -164,7 +164,7 @@ static void make_response(struct xen_blkif *blkif, u64 id,
 
 #define foreach_grant_safe(pos, n, rbtree, node) \
        for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \
-            (n) = rb_next(&(pos)->node); \
+            (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL; \
             &(pos)->node != NULL; \
             (pos) = container_of(n, typeof(*(pos)), node), \
             (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL)
@@ -381,8 +381,8 @@ irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
 
 static void print_stats(struct xen_blkif *blkif)
 {
-       pr_info("xen-blkback (%s): oo %3d  |  rd %4d  |  wr %4d  |  f %4d"
-                "  |  ds %4d\n",
+       pr_info("xen-blkback (%s): oo %3llu  |  rd %4llu  |  wr %4llu  |  f %4llu"
+                "  |  ds %4llu\n",
                 current->comm, blkif->st_oo_req,
                 blkif->st_rd_req, blkif->st_wr_req,
                 blkif->st_f_req, blkif->st_ds_req);
@@ -442,7 +442,7 @@ int xen_blkif_schedule(void *arg)
 }
 
 struct seg_buf {
-       unsigned long buf;
+       unsigned int offset;
        unsigned int nsec;
 };
 /*
@@ -621,30 +621,21 @@ static int xen_blkbk_map(struct blkif_request *req,
                                 * If this is a new persistent grant
                                 * save the handler
                                 */
-                               persistent_gnts[i]->handle = map[j].handle;
-                               persistent_gnts[i]->dev_bus_addr =
-                                       map[j++].dev_bus_addr;
+                               persistent_gnts[i]->handle = map[j++].handle;
                        }
                        pending_handle(pending_req, i) =
                                persistent_gnts[i]->handle;
 
                        if (ret)
                                continue;
-
-                       seg[i].buf = persistent_gnts[i]->dev_bus_addr |
-                               (req->u.rw.seg[i].first_sect << 9);
                } else {
-                       pending_handle(pending_req, i) = map[j].handle;
+                       pending_handle(pending_req, i) = map[j++].handle;
                        bitmap_set(pending_req->unmap_seg, i, 1);
 
-                       if (ret) {
-                               j++;
+                       if (ret)
                                continue;
-                       }
-
-                       seg[i].buf = map[j++].dev_bus_addr |
-                               (req->u.rw.seg[i].first_sect << 9);
                }
+               seg[i].offset = (req->u.rw.seg[i].first_sect << 9);
        }
        return ret;
 }
@@ -679,6 +670,16 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
        return err;
 }
 
+static int dispatch_other_io(struct xen_blkif *blkif,
+                            struct blkif_request *req,
+                            struct pending_req *pending_req)
+{
+       free_req(pending_req);
+       make_response(blkif, req->u.other.id, req->operation,
+                     BLKIF_RSP_EOPNOTSUPP);
+       return -EIO;
+}
+
 static void xen_blk_drain_io(struct xen_blkif *blkif)
 {
        atomic_set(&blkif->drain, 1);
@@ -800,17 +801,30 @@ __do_block_io_op(struct xen_blkif *blkif)
 
                /* Apply all sanity checks to /private copy/ of request. */
                barrier();
-               if (unlikely(req.operation == BLKIF_OP_DISCARD)) {
+
+               switch (req.operation) {
+               case BLKIF_OP_READ:
+               case BLKIF_OP_WRITE:
+               case BLKIF_OP_WRITE_BARRIER:
+               case BLKIF_OP_FLUSH_DISKCACHE:
+                       if (dispatch_rw_block_io(blkif, &req, pending_req))
+                               goto done;
+                       break;
+               case BLKIF_OP_DISCARD:
                        free_req(pending_req);
                        if (dispatch_discard_io(blkif, &req))
-                               break;
-               } else if (dispatch_rw_block_io(blkif, &req, pending_req))
+                               goto done;
                        break;
+               default:
+                       if (dispatch_other_io(blkif, &req, pending_req))
+                               goto done;
+                       break;
+               }
 
                /* Yield point for this unbounded loop. */
                cond_resched();
        }
-
+done:
        return more_to_do;
 }
 
@@ -904,7 +918,8 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n",
                         operation == READ ? "read" : "write",
                         preq.sector_number,
-                        preq.sector_number + preq.nr_sects, preq.dev);
+                        preq.sector_number + preq.nr_sects,
+                        blkif->vbd.pdevice);
                goto fail_response;
        }
 
@@ -947,7 +962,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                       (bio_add_page(bio,
                                     pages[i],
                                     seg[i].nsec << 9,
-                                    seg[i].buf & ~PAGE_MASK) == 0)) {
+                                    seg[i].offset) == 0)) {
 
                        bio = bio_alloc(GFP_KERNEL, nseg-i);
                        if (unlikely(bio == NULL))
@@ -977,13 +992,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                bio->bi_end_io  = end_block_io_op;
        }
 
-       /*
-        * We set it one so that the last submit_bio does not have to call
-        * atomic_inc.
-        */
        atomic_set(&pending_req->pendcnt, nbio);
-
-       /* Get a reference count for the disk queue and start sending I/O */
        blk_start_plug(&plug);
 
        for (i = 0; i < nbio; i++)
@@ -1011,6 +1020,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
  fail_put_bio:
        for (i = 0; i < nbio; i++)
                bio_put(biolist[i]);
+       atomic_set(&pending_req->pendcnt, 1);
        __end_block_io_op(pending_req, -EINVAL);
        msleep(1); /* back off a bit */
        return -EIO;
index 6072390..60103e2 100644 (file)
@@ -77,11 +77,18 @@ struct blkif_x86_32_request_discard {
        uint64_t       nr_sectors;
 } __attribute__((__packed__));
 
+struct blkif_x86_32_request_other {
+       uint8_t        _pad1;
+       blkif_vdev_t   _pad2;
+       uint64_t       id;           /* private guest value, echoed in resp  */
+} __attribute__((__packed__));
+
 struct blkif_x86_32_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
        union {
                struct blkif_x86_32_request_rw rw;
                struct blkif_x86_32_request_discard discard;
+               struct blkif_x86_32_request_other other;
        } u;
 } __attribute__((__packed__));
 
@@ -113,11 +120,19 @@ struct blkif_x86_64_request_discard {
        uint64_t       nr_sectors;
 } __attribute__((__packed__));
 
+struct blkif_x86_64_request_other {
+       uint8_t        _pad1;
+       blkif_vdev_t   _pad2;
+       uint32_t       _pad3;        /* offsetof(blkif_..,u.discard.id)==8   */
+       uint64_t       id;           /* private guest value, echoed in resp  */
+} __attribute__((__packed__));
+
 struct blkif_x86_64_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
        union {
                struct blkif_x86_64_request_rw rw;
                struct blkif_x86_64_request_discard discard;
+               struct blkif_x86_64_request_other other;
        } u;
 } __attribute__((__packed__));
 
@@ -172,7 +187,6 @@ struct persistent_gnt {
        struct page *page;
        grant_ref_t gnt;
        grant_handle_t handle;
-       uint64_t dev_bus_addr;
        struct rb_node node;
 };
 
@@ -208,13 +222,13 @@ struct xen_blkif {
 
        /* statistics */
        unsigned long           st_print;
-       int                     st_rd_req;
-       int                     st_wr_req;
-       int                     st_oo_req;
-       int                     st_f_req;
-       int                     st_ds_req;
-       int                     st_rd_sect;
-       int                     st_wr_sect;
+       unsigned long long                      st_rd_req;
+       unsigned long long                      st_wr_req;
+       unsigned long long                      st_oo_req;
+       unsigned long long                      st_f_req;
+       unsigned long long                      st_ds_req;
+       unsigned long long                      st_rd_sect;
+       unsigned long long                      st_wr_sect;
 
        wait_queue_head_t       waiting_to_free;
 };
@@ -278,6 +292,11 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
        default:
+               /*
+                * Don't know how to translate this op. Only get the
+                * ID so failure can be reported to the frontend.
+                */
+               dst->u.other.id = src->u.other.id;
                break;
        }
 }
@@ -309,6 +328,11 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
                dst->u.discard.nr_sectors = src->u.discard.nr_sectors;
                break;
        default:
+               /*
+                * Don't know how to translate this op. Only get the
+                * ID so failure can be reported to the frontend.
+                */
+               dst->u.other.id = src->u.other.id;
                break;
        }
 }
index 5e237f6..8bfd1bc 100644 (file)
@@ -230,13 +230,13 @@ int __init xen_blkif_interface_init(void)
        }                                                               \
        static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
-VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
-VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
-VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
-VBD_SHOW(f_req,  "%d\n", be->blkif->st_f_req);
-VBD_SHOW(ds_req,  "%d\n", be->blkif->st_ds_req);
-VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
-VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
+VBD_SHOW(oo_req,  "%llu\n", be->blkif->st_oo_req);
+VBD_SHOW(rd_req,  "%llu\n", be->blkif->st_rd_req);
+VBD_SHOW(wr_req,  "%llu\n", be->blkif->st_wr_req);
+VBD_SHOW(f_req,  "%llu\n", be->blkif->st_f_req);
+VBD_SHOW(ds_req,  "%llu\n", be->blkif->st_ds_req);
+VBD_SHOW(rd_sect, "%llu\n", be->blkif->st_rd_sect);
+VBD_SHOW(wr_sect, "%llu\n", be->blkif->st_wr_sect);
 
 static struct attribute *xen_vbdstat_attrs[] = {
        &dev_attr_oo_req.attr,
index c3dae2e..a894f88 100644 (file)
@@ -44,7 +44,7 @@
 #include <linux/mutex.h>
 #include <linux/scatterlist.h>
 #include <linux/bitmap.h>
-#include <linux/llist.h>
+#include <linux/list.h>
 
 #include <xen/xen.h>
 #include <xen/xenbus.h>
@@ -68,13 +68,12 @@ enum blkif_state {
 struct grant {
        grant_ref_t gref;
        unsigned long pfn;
-       struct llist_node node;
+       struct list_head node;
 };
 
 struct blk_shadow {
        struct blkif_request req;
        struct request *request;
-       unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        struct grant *grants_used[BLKIF_MAX_SEGMENTS_PER_REQUEST];
 };
 
@@ -105,7 +104,7 @@ struct blkfront_info
        struct work_struct work;
        struct gnttab_free_callback callback;
        struct blk_shadow shadow[BLK_RING_SIZE];
-       struct llist_head persistent_gnts;
+       struct list_head persistent_gnts;
        unsigned int persistent_gnts_c;
        unsigned long shadow_free;
        unsigned int feature_flush;
@@ -165,6 +164,69 @@ static int add_id_to_freelist(struct blkfront_info *info,
        return 0;
 }
 
+static int fill_grant_buffer(struct blkfront_info *info, int num)
+{
+       struct page *granted_page;
+       struct grant *gnt_list_entry, *n;
+       int i = 0;
+
+       while(i < num) {
+               gnt_list_entry = kzalloc(sizeof(struct grant), GFP_NOIO);
+               if (!gnt_list_entry)
+                       goto out_of_memory;
+
+               granted_page = alloc_page(GFP_NOIO);
+               if (!granted_page) {
+                       kfree(gnt_list_entry);
+                       goto out_of_memory;
+               }
+
+               gnt_list_entry->pfn = page_to_pfn(granted_page);
+               gnt_list_entry->gref = GRANT_INVALID_REF;
+               list_add(&gnt_list_entry->node, &info->persistent_gnts);
+               i++;
+       }
+
+       return 0;
+
+out_of_memory:
+       list_for_each_entry_safe(gnt_list_entry, n,
+                                &info->persistent_gnts, node) {
+               list_del(&gnt_list_entry->node);
+               __free_page(pfn_to_page(gnt_list_entry->pfn));
+               kfree(gnt_list_entry);
+               i--;
+       }
+       BUG_ON(i != 0);
+       return -ENOMEM;
+}
+
+static struct grant *get_grant(grant_ref_t *gref_head,
+                               struct blkfront_info *info)
+{
+       struct grant *gnt_list_entry;
+       unsigned long buffer_mfn;
+
+       BUG_ON(list_empty(&info->persistent_gnts));
+       gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant,
+                                         node);
+       list_del(&gnt_list_entry->node);
+
+       if (gnt_list_entry->gref != GRANT_INVALID_REF) {
+               info->persistent_gnts_c--;
+               return gnt_list_entry;
+       }
+
+       /* Assign a gref to this page */
+       gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
+       BUG_ON(gnt_list_entry->gref == -ENOSPC);
+       buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
+       gnttab_grant_foreign_access_ref(gnt_list_entry->gref,
+                                       info->xbdev->otherend_id,
+                                       buffer_mfn, 0);
+       return gnt_list_entry;
+}
+
 static const char *op_name(int op)
 {
        static const char *const names[] = {
@@ -293,7 +355,6 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
 static int blkif_queue_request(struct request *req)
 {
        struct blkfront_info *info = req->rq_disk->private_data;
-       unsigned long buffer_mfn;
        struct blkif_request *ring_req;
        unsigned long id;
        unsigned int fsect, lsect;
@@ -306,7 +367,6 @@ static int blkif_queue_request(struct request *req)
         */
        bool new_persistent_gnts;
        grant_ref_t gref_head;
-       struct page *granted_page;
        struct grant *gnt_list_entry = NULL;
        struct scatterlist *sg;
 
@@ -370,41 +430,8 @@ static int blkif_queue_request(struct request *req)
                        fsect = sg->offset >> 9;
                        lsect = fsect + (sg->length >> 9) - 1;
 
-                       if (info->persistent_gnts_c) {
-                               BUG_ON(llist_empty(&info->persistent_gnts));
-                               gnt_list_entry = llist_entry(
-                                       llist_del_first(&info->persistent_gnts),
-                                       struct grant, node);
-
-                               ref = gnt_list_entry->gref;
-                               buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
-                               info->persistent_gnts_c--;
-                       } else {
-                               ref = gnttab_claim_grant_reference(&gref_head);
-                               BUG_ON(ref == -ENOSPC);
-
-                               gnt_list_entry =
-                                       kmalloc(sizeof(struct grant),
-                                                        GFP_ATOMIC);
-                               if (!gnt_list_entry)
-                                       return -ENOMEM;
-
-                               granted_page = alloc_page(GFP_ATOMIC);
-                               if (!granted_page) {
-                                       kfree(gnt_list_entry);
-                                       return -ENOMEM;
-                               }
-
-                               gnt_list_entry->pfn =
-                                       page_to_pfn(granted_page);
-                               gnt_list_entry->gref = ref;
-
-                               buffer_mfn = pfn_to_mfn(page_to_pfn(
-                                                               granted_page));
-                               gnttab_grant_foreign_access_ref(ref,
-                                       info->xbdev->otherend_id,
-                                       buffer_mfn, 0);
-                       }
+                       gnt_list_entry = get_grant(&gref_head, info);
+                       ref = gnt_list_entry->gref;
 
                        info->shadow[id].grants_used[i] = gnt_list_entry;
 
@@ -435,7 +462,6 @@ static int blkif_queue_request(struct request *req)
                                kunmap_atomic(shared_data);
                        }
 
-                       info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
                        ring_req->u.rw.seg[i] =
                                        (struct blkif_request_segment) {
                                                .gref       = ref,
@@ -790,9 +816,8 @@ static void blkif_restart_queue(struct work_struct *work)
 
 static void blkif_free(struct blkfront_info *info, int suspend)
 {
-       struct llist_node *all_gnts;
-       struct grant *persistent_gnt, *tmp;
-       struct llist_node *n;
+       struct grant *persistent_gnt;
+       struct grant *n;
 
        /* Prevent new requests being issued until we fix things up. */
        spin_lock_irq(&info->io_lock);
@@ -803,22 +828,20 @@ static void blkif_free(struct blkfront_info *info, int suspend)
                blk_stop_queue(info->rq);
 
        /* Remove all persistent grants */
-       if (info->persistent_gnts_c) {
-               all_gnts = llist_del_all(&info->persistent_gnts);
-               persistent_gnt = llist_entry(all_gnts, typeof(*(persistent_gnt)), node);
-               while (persistent_gnt) {
-                       gnttab_end_foreign_access(persistent_gnt->gref, 0, 0UL);
+       if (!list_empty(&info->persistent_gnts)) {
+               list_for_each_entry_safe(persistent_gnt, n,
+                                        &info->persistent_gnts, node) {
+                       list_del(&persistent_gnt->node);
+                       if (persistent_gnt->gref != GRANT_INVALID_REF) {
+                               gnttab_end_foreign_access(persistent_gnt->gref,
+                                                         0, 0UL);
+                               info->persistent_gnts_c--;
+                       }
                        __free_page(pfn_to_page(persistent_gnt->pfn));
-                       tmp = persistent_gnt;
-                       n = persistent_gnt->node.next;
-                       if (n)
-                               persistent_gnt = llist_entry(n, typeof(*(persistent_gnt)), node);
-                       else
-                               persistent_gnt = NULL;
-                       kfree(tmp);
+                       kfree(persistent_gnt);
                }
-               info->persistent_gnts_c = 0;
        }
+       BUG_ON(info->persistent_gnts_c != 0);
 
        /* No more gnttab callback work. */
        gnttab_cancel_free_callback(&info->callback);
@@ -875,7 +898,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
        }
        /* Add the persistent grant into the list of free grants */
        for (i = 0; i < s->req.u.rw.nr_segments; i++) {
-               llist_add(&s->grants_used[i]->node, &info->persistent_gnts);
+               list_add(&s->grants_used[i]->node, &info->persistent_gnts);
                info->persistent_gnts_c++;
        }
 }
@@ -1013,6 +1036,12 @@ static int setup_blkring(struct xenbus_device *dev,
 
        sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
 
+       /* Allocate memory for grants */
+       err = fill_grant_buffer(info, BLK_RING_SIZE *
+                                     BLKIF_MAX_SEGMENTS_PER_REQUEST);
+       if (err)
+               goto fail;
+
        err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
        if (err < 0) {
                free_page((unsigned long)sring);
@@ -1171,7 +1200,7 @@ static int blkfront_probe(struct xenbus_device *dev,
        spin_lock_init(&info->io_lock);
        info->xbdev = dev;
        info->vdevice = vdevice;
-       init_llist_head(&info->persistent_gnts);
+       INIT_LIST_HEAD(&info->persistent_gnts);
        info->persistent_gnts_c = 0;
        info->connected = BLKIF_STATE_DISCONNECTED;
        INIT_WORK(&info->work, blkif_restart_queue);
@@ -1203,11 +1232,10 @@ static int blkif_recover(struct blkfront_info *info)
        int j;
 
        /* Stage 1: Make a safe copy of the shadow state. */
-       copy = kmalloc(sizeof(info->shadow),
+       copy = kmemdup(info->shadow, sizeof(info->shadow),
                       GFP_NOIO | __GFP_REPEAT | __GFP_HIGH);
        if (!copy)
                return -ENOMEM;
-       memcpy(copy, info->shadow, sizeof(info->shadow));
 
        /* Stage 2: Set up free list. */
        memset(&info->shadow, 0, sizeof(info->shadow));
@@ -1236,7 +1264,7 @@ static int blkif_recover(struct blkfront_info *info)
                                gnttab_grant_foreign_access_ref(
                                        req->u.rw.seg[j].gref,
                                        info->xbdev->otherend_id,
-                                       pfn_to_mfn(info->shadow[req->u.rw.id].frame[j]),
+                                       pfn_to_mfn(copy[i].grants_used[j]->pfn),
                                        0);
                }
                info->shadow[req->u.rw.id].req = *req;
index b282af1..6aab00e 100644 (file)
@@ -73,9 +73,11 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x03F0, 0x311D) },
 
        /* Atheros AR3012 with sflash firmware*/
+       { USB_DEVICE(0x0CF3, 0x0036) },
        { USB_DEVICE(0x0CF3, 0x3004) },
        { USB_DEVICE(0x0CF3, 0x3008) },
        { USB_DEVICE(0x0CF3, 0x311D) },
+       { USB_DEVICE(0x0CF3, 0x817a) },
        { USB_DEVICE(0x13d3, 0x3375) },
        { USB_DEVICE(0x04CA, 0x3004) },
        { USB_DEVICE(0x04CA, 0x3005) },
@@ -107,9 +109,11 @@ MODULE_DEVICE_TABLE(usb, ath3k_table);
 static struct usb_device_id ath3k_blist_tbl[] = {
 
        /* Atheros AR3012 with sflash firmware*/
+       { USB_DEVICE(0x0CF3, 0x0036), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x311D), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0CF3, 0x817a), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
index e547851..2cc5f77 100644 (file)
@@ -131,9 +131,11 @@ static struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
 
        /* Atheros 3012 with sflash firmware */
+       { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0cf3, 0x817a), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3375), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
index 69ae597..a0f7724 100644 (file)
@@ -380,6 +380,15 @@ void hwrng_unregister(struct hwrng *rng)
 }
 EXPORT_SYMBOL_GPL(hwrng_unregister);
 
+static void __exit hwrng_exit(void)
+{
+       mutex_lock(&rng_mutex);
+       BUG_ON(current_rng);
+       kfree(rng_buffer);
+       mutex_unlock(&rng_mutex);
+}
+
+module_exit(hwrng_exit);
 
 MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
 MODULE_LICENSE("GPL");
index e905d5f..ce5f3fc 100644 (file)
@@ -149,7 +149,8 @@ struct ports_device {
        spinlock_t ports_lock;
 
        /* To protect the vq operations for the control channel */
-       spinlock_t cvq_lock;
+       spinlock_t c_ivq_lock;
+       spinlock_t c_ovq_lock;
 
        /* The current config space is stored here */
        struct virtio_console_config config;
@@ -569,11 +570,14 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
        vq = portdev->c_ovq;
 
        sg_init_one(sg, &cpkt, sizeof(cpkt));
+
+       spin_lock(&portdev->c_ovq_lock);
        if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) {
                virtqueue_kick(vq);
                while (!virtqueue_get_buf(vq, &len))
                        cpu_relax();
        }
+       spin_unlock(&portdev->c_ovq_lock);
        return 0;
 }
 
@@ -1436,7 +1440,7 @@ static int add_port(struct ports_device *portdev, u32 id)
                 * rproc_serial does not want the console port, only
                 * the generic port implementation.
                 */
-               port->host_connected = port->guest_connected = true;
+               port->host_connected = true;
        else if (!use_multiport(port->portdev)) {
                /*
                 * If we're not using multiport support,
@@ -1709,23 +1713,23 @@ static void control_work_handler(struct work_struct *work)
        portdev = container_of(work, struct ports_device, control_work);
        vq = portdev->c_ivq;
 
-       spin_lock(&portdev->cvq_lock);
+       spin_lock(&portdev->c_ivq_lock);
        while ((buf = virtqueue_get_buf(vq, &len))) {
-               spin_unlock(&portdev->cvq_lock);
+               spin_unlock(&portdev->c_ivq_lock);
 
                buf->len = len;
                buf->offset = 0;
 
                handle_control_message(portdev, buf);
 
-               spin_lock(&portdev->cvq_lock);
+               spin_lock(&portdev->c_ivq_lock);
                if (add_inbuf(portdev->c_ivq, buf) < 0) {
                        dev_warn(&portdev->vdev->dev,
                                 "Error adding buffer to queue\n");
                        free_buf(buf, false);
                }
        }
-       spin_unlock(&portdev->cvq_lock);
+       spin_unlock(&portdev->c_ivq_lock);
 }
 
 static void out_intr(struct virtqueue *vq)
@@ -1752,13 +1756,23 @@ static void in_intr(struct virtqueue *vq)
        port->inbuf = get_inbuf(port);
 
        /*
-        * Don't queue up data when port is closed.  This condition
+        * Normally the port should not accept data when the port is
+        * closed. For generic serial ports, the host won't (shouldn't)
+        * send data till the guest is connected. But this condition
         * can be reached when a console port is not yet connected (no
-        * tty is spawned) and the host sends out data to console
-        * ports.  For generic serial ports, the host won't
-        * (shouldn't) send data till the guest is connected.
+        * tty is spawned) and the other side sends out data over the
+        * vring, or when a remote devices start sending data before
+        * the ports are opened.
+        *
+        * A generic serial port will discard data if not connected,
+        * while console ports and rproc-serial ports accepts data at
+        * any time. rproc-serial is initiated with guest_connected to
+        * false because port_fops_open expects this. Console ports are
+        * hooked up with an HVC console and is initialized with
+        * guest_connected to true.
         */
-       if (!port->guest_connected)
+
+       if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
                discard_port_data(port);
 
        spin_unlock_irqrestore(&port->inbuf_lock, flags);
@@ -1986,10 +2000,12 @@ static int virtcons_probe(struct virtio_device *vdev)
        if (multiport) {
                unsigned int nr_added_bufs;
 
-               spin_lock_init(&portdev->cvq_lock);
+               spin_lock_init(&portdev->c_ivq_lock);
+               spin_lock_init(&portdev->c_ovq_lock);
                INIT_WORK(&portdev->control_work, &control_work_handler);
 
-               nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               nr_added_bufs = fill_queue(portdev->c_ivq,
+                                          &portdev->c_ivq_lock);
                if (!nr_added_bufs) {
                        dev_err(&vdev->dev,
                                "Error allocating buffers for control queue\n");
@@ -2140,7 +2156,7 @@ static int virtcons_restore(struct virtio_device *vdev)
                return ret;
 
        if (use_multiport(portdev))
-               fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
 
        list_for_each_entry(port, &portdev->ports, list) {
                port->in_vq = portdev->in_vqs[port->id];
index 1e2de73..f873dce 100644 (file)
@@ -703,7 +703,7 @@ static void tegra20_pll_init(void)
        clks[pll_a_out0] = clk;
 
        /* PLLE */
-       clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, NULL,
+       clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, pmc_base,
                             0, 100000000, &pll_e_params,
                             0, pll_e_freq_table, NULL);
        clk_register_clkdev(clk, "pll_e", NULL);
index 937bc28..57a8774 100644 (file)
@@ -730,7 +730,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
            policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
                cpumask_copy(policy->cpus, perf->shared_cpu_map);
        }
-       cpumask_copy(policy->related_cpus, perf->shared_cpu_map);
 
 #ifdef CONFIG_SMP
        dmi_check_system(sw_any_bug_dmi_table);
@@ -742,7 +741,6 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
        if (check_amd_hwpstate_cpu(cpu) && !acpi_pstate_strict) {
                cpumask_clear(policy->cpus);
                cpumask_set_cpu(cpu, policy->cpus);
-               cpumask_copy(policy->related_cpus, cpu_sibling_mask(cpu));
                policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
                pr_info_once(PFX "overriding BIOS provided _PSD data\n");
        }
index 4e5b7fb..37d23a0 100644 (file)
@@ -178,10 +178,16 @@ static struct cpufreq_driver cpu0_cpufreq_driver = {
 
 static int cpu0_cpufreq_probe(struct platform_device *pdev)
 {
-       struct device_node *np;
+       struct device_node *np, *parent;
        int ret;
 
-       for_each_child_of_node(of_find_node_by_path("/cpus"), np) {
+       parent = of_find_node_by_path("/cpus");
+       if (!parent) {
+               pr_err("failed to find OF /cpus\n");
+               return -ENOENT;
+       }
+
+       for_each_child_of_node(parent, np) {
                if (of_get_property(np, "operating-points", NULL))
                        break;
        }
index 46bde01..cc4bd2f 100644 (file)
@@ -14,8 +14,8 @@
  * published by the Free Software Foundation.
  */
 
-#ifndef _CPUFREQ_GOVERNER_H
-#define _CPUFREQ_GOVERNER_H
+#ifndef _CPUFREQ_GOVERNOR_H
+#define _CPUFREQ_GOVERNOR_H
 
 #include <linux/cpufreq.h>
 #include <linux/kobject.h>
@@ -175,4 +175,4 @@ bool need_load_eval(struct cpu_dbs_common_info *cdbs,
                unsigned int sampling_rate);
 int cpufreq_governor_dbs(struct dbs_data *dbs_data,
                struct cpufreq_policy *policy, unsigned int event);
-#endif /* _CPUFREQ_GOVERNER_H */
+#endif /* _CPUFREQ_GOVERNOR_H */
index 2fd779e..bfd6273 100644 (file)
@@ -180,15 +180,19 @@ static void cpufreq_stats_free_sysfs(unsigned int cpu)
 {
        struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
 
-       if (!cpufreq_frequency_get_table(cpu))
+       if (!policy)
                return;
 
-       if (policy && !policy_is_shared(policy)) {
+       if (!cpufreq_frequency_get_table(cpu))
+               goto put_ref;
+
+       if (!policy_is_shared(policy)) {
                pr_debug("%s: Free sysfs stat\n", __func__);
                sysfs_remove_group(&policy->kobj, &stats_attr_group);
        }
-       if (policy)
-               cpufreq_cpu_put(policy);
+
+put_ref:
+       cpufreq_cpu_put(policy);
 }
 
 static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
index f6dd1e7..ad72922 100644 (file)
@@ -358,14 +358,14 @@ static void intel_pstate_sysfs_expose_params(void)
 static int intel_pstate_min_pstate(void)
 {
        u64 value;
-       rdmsrl(0xCE, value);
+       rdmsrl(MSR_PLATFORM_INFO, value);
        return (value >> 40) & 0xFF;
 }
 
 static int intel_pstate_max_pstate(void)
 {
        u64 value;
-       rdmsrl(0xCE, value);
+       rdmsrl(MSR_PLATFORM_INFO, value);
        return (value >> 8) & 0xFF;
 }
 
@@ -373,7 +373,7 @@ static int intel_pstate_turbo_pstate(void)
 {
        u64 value;
        int nont, ret;
-       rdmsrl(0x1AD, value);
+       rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
        nont = intel_pstate_max_pstate();
        ret = ((value) & 255);
        if (ret <= nont)
@@ -454,7 +454,7 @@ static inline void intel_pstate_calc_busy(struct cpudata *cpu,
                                        sample->idletime_us * 100,
                                        sample->duration_us);
        core_pct = div64_u64(sample->aperf * 100, sample->mperf);
-       sample->freq = cpu->pstate.turbo_pstate * core_pct * 1000;
+       sample->freq = cpu->pstate.max_pstate * core_pct * 1000;
 
        sample->core_pct_busy = div_s64((sample->pstate_pct_busy * core_pct),
                                        100);
@@ -752,6 +752,29 @@ static struct cpufreq_driver intel_pstate_driver = {
 
 static int __initdata no_load;
 
+static int intel_pstate_msrs_not_valid(void)
+{
+       /* Check that all the msr's we are using are valid. */
+       u64 aperf, mperf, tmp;
+
+       rdmsrl(MSR_IA32_APERF, aperf);
+       rdmsrl(MSR_IA32_MPERF, mperf);
+
+       if (!intel_pstate_min_pstate() ||
+               !intel_pstate_max_pstate() ||
+               !intel_pstate_turbo_pstate())
+               return -ENODEV;
+
+       rdmsrl(MSR_IA32_APERF, tmp);
+       if (!(tmp - aperf))
+               return -ENODEV;
+
+       rdmsrl(MSR_IA32_MPERF, tmp);
+       if (!(tmp - mperf))
+               return -ENODEV;
+
+       return 0;
+}
 static int __init intel_pstate_init(void)
 {
        int cpu, rc = 0;
@@ -764,6 +787,9 @@ static int __init intel_pstate_init(void)
        if (!id)
                return -ENODEV;
 
+       if (intel_pstate_msrs_not_valid())
+               return -ENODEV;
+
        pr_info("Intel P-state driver initializing.\n");
 
        all_cpu_data = vmalloc(sizeof(void *) * num_possible_cpus());
index b2a0a07..cf268b1 100644 (file)
@@ -1650,11 +1650,7 @@ struct caam_alg_template {
 };
 
 static struct caam_alg_template driver_algs[] = {
-       /*
-        * single-pass ipsec_esp descriptor
-        * authencesn(*,*) is also registered, although not present
-        * explicitly here.
-        */
+       /* single-pass ipsec_esp descriptor */
        {
                .name = "authenc(hmac(md5),cbc(aes))",
                .driver_name = "authenc-hmac-md5-cbc-aes-caam",
@@ -2217,9 +2213,7 @@ static int __init caam_algapi_init(void)
        for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
                /* TODO: check if h/w supports alg */
                struct caam_crypto_alg *t_alg;
-               bool done = false;
 
-authencesn:
                t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]);
                if (IS_ERR(t_alg)) {
                        err = PTR_ERR(t_alg);
@@ -2233,25 +2227,8 @@ authencesn:
                        dev_warn(ctrldev, "%s alg registration failed\n",
                                t_alg->crypto_alg.cra_driver_name);
                        kfree(t_alg);
-               } else {
+               } else
                        list_add_tail(&t_alg->entry, &priv->alg_list);
-                       if (driver_algs[i].type == CRYPTO_ALG_TYPE_AEAD &&
-                           !memcmp(driver_algs[i].name, "authenc", 7) &&
-                           !done) {
-                               char *name;
-
-                               name = driver_algs[i].name;
-                               memmove(name + 10, name + 7, strlen(name) - 7);
-                               memcpy(name + 7, "esn", 3);
-
-                               name = driver_algs[i].driver_name;
-                               memmove(name + 10, name + 7, strlen(name) - 7);
-                               memcpy(name + 7, "esn", 3);
-
-                               done = true;
-                               goto authencesn;
-                       }
-               }
        }
        if (!list_empty(&priv->alg_list))
                dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n",
index cf15e78..762aeff 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/types.h>
 #include <linux/debugfs.h>
 #include <linux/circ_buf.h>
-#include <linux/string.h>
 #include <net/xfrm.h>
 
 #include <crypto/algapi.h>
index 09b184a..5b2b5e6 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/spinlock.h>
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
-#include <linux/string.h>
 
 #include <crypto/algapi.h>
 #include <crypto/aes.h>
@@ -1974,11 +1973,7 @@ struct talitos_alg_template {
 };
 
 static struct talitos_alg_template driver_algs[] = {
-       /*
-        * AEAD algorithms. These use a single-pass ipsec_esp descriptor.
-        * authencesn(*,*) is also registered, although not present
-        * explicitly here.
-        */
+       /* AEAD algorithms.  These use a single-pass ipsec_esp descriptor */
        {       .type = CRYPTO_ALG_TYPE_AEAD,
                .alg.crypto = {
                        .cra_name = "authenc(hmac(sha1),cbc(aes))",
@@ -2820,9 +2815,7 @@ static int talitos_probe(struct platform_device *ofdev)
                if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
                        struct talitos_crypto_alg *t_alg;
                        char *name = NULL;
-                       bool authenc = false;
 
-authencesn:
                        t_alg = talitos_alg_alloc(dev, &driver_algs[i]);
                        if (IS_ERR(t_alg)) {
                                err = PTR_ERR(t_alg);
@@ -2837,8 +2830,6 @@ authencesn:
                                err = crypto_register_alg(
                                                &t_alg->algt.alg.crypto);
                                name = t_alg->algt.alg.crypto.cra_driver_name;
-                               authenc = authenc ? !authenc :
-                                         !(bool)memcmp(name, "authenc", 7);
                                break;
                        case CRYPTO_ALG_TYPE_AHASH:
                                err = crypto_register_ahash(
@@ -2851,25 +2842,8 @@ authencesn:
                                dev_err(dev, "%s alg registration failed\n",
                                        name);
                                kfree(t_alg);
-                       } else {
+                       } else
                                list_add_tail(&t_alg->entry, &priv->alg_list);
-                               if (authenc) {
-                                       struct crypto_alg *alg =
-                                               &driver_algs[i].alg.crypto;
-
-                                       name = alg->cra_name;
-                                       memmove(name + 10, name + 7,
-                                               strlen(name) - 7);
-                                       memcpy(name + 7, "esn", 3);
-
-                                       name = alg->cra_driver_name;
-                                       memmove(name + 10, name + 7,
-                                               strlen(name) - 7);
-                                       memcpy(name + 7, "esn", 3);
-
-                                       goto authencesn;
-                               }
-                       }
                }
        }
        if (!list_empty(&priv->alg_list))
index 80b6997..aeaea32 100644 (file)
@@ -83,6 +83,7 @@ config INTEL_IOP_ADMA
 
 config DW_DMAC
        tristate "Synopsys DesignWare AHB DMA support"
+       depends on GENERIC_HARDIRQS
        select DMA_ENGINE
        default y if CPU_AT32AP7000
        help
index c599558..43a5329 100644 (file)
@@ -1001,6 +1001,13 @@ static inline void convert_burst(u32 *maxburst)
                *maxburst = 0;
 }
 
+static inline void convert_slave_id(struct dw_dma_chan *dwc)
+{
+       struct dw_dma *dw = to_dw_dma(dwc->chan.device);
+
+       dwc->dma_sconfig.slave_id -= dw->request_line_base;
+}
+
 static int
 set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 {
@@ -1015,6 +1022,7 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
 
        convert_burst(&dwc->dma_sconfig.src_maxburst);
        convert_burst(&dwc->dma_sconfig.dst_maxburst);
+       convert_slave_id(dwc);
 
        return 0;
 }
@@ -1276,9 +1284,9 @@ static struct dma_chan *dw_dma_xlate(struct of_phandle_args *dma_spec,
        if (dma_spec->args_count != 3)
                return NULL;
 
-       fargs.req = be32_to_cpup(dma_spec->args+0);
-       fargs.src = be32_to_cpup(dma_spec->args+1);
-       fargs.dst = be32_to_cpup(dma_spec->args+2);
+       fargs.req = dma_spec->args[0];
+       fargs.src = dma_spec->args[1];
+       fargs.dst = dma_spec->args[2];
 
        if (WARN_ON(fargs.req >= DW_DMA_MAX_NR_REQUESTS ||
                    fargs.src >= dw->nr_masters ||
@@ -1628,6 +1636,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
 
 static int dw_probe(struct platform_device *pdev)
 {
+       const struct platform_device_id *match;
        struct dw_dma_platform_data *pdata;
        struct resource         *io;
        struct dw_dma           *dw;
@@ -1711,6 +1720,11 @@ static int dw_probe(struct platform_device *pdev)
                memcpy(dw->data_width, pdata->data_width, 4);
        }
 
+       /* Get the base request line if set */
+       match = platform_get_device_id(pdev);
+       if (match)
+               dw->request_line_base = (unsigned int)match->driver_data;
+
        /* Calculate all channel mask before DMA setup */
        dw->all_chan_mask = (1 << nr_channels) - 1;
 
@@ -1906,7 +1920,8 @@ MODULE_DEVICE_TABLE(of, dw_dma_id_table);
 #endif
 
 static const struct platform_device_id dw_dma_ids[] = {
-       { "INTL9C60", 0 },
+       /* Name,        Request Line Base */
+       { "INTL9C60",   (kernel_ulong_t)16 },
        { }
 };
 
index cf0ce5c..4d02c36 100644 (file)
@@ -247,6 +247,7 @@ struct dw_dma {
        /* hardware configuration */
        unsigned char           nr_masters;
        unsigned char           data_width[4];
+       unsigned int            request_line_base;
 
        struct dw_dma_chan      chan[0];
 };
index cdae207..6c3fca9 100644 (file)
 /* There is only *one* pci_eisa device per machine, right ? */
 static struct eisa_root_device pci_eisa_root;
 
-static int __init pci_eisa_init(struct pci_dev *pdev,
-                               const struct pci_device_id *ent)
+static int __init pci_eisa_init(struct pci_dev *pdev)
 {
-       int rc;
+       int rc, i;
+       struct resource *res, *bus_res = NULL;
 
        if ((rc = pci_enable_device (pdev))) {
                printk (KERN_ERR "pci_eisa : Could not enable device %s\n",
@@ -30,9 +30,30 @@ static int __init pci_eisa_init(struct pci_dev *pdev,
                return rc;
        }
 
+       /*
+        * The Intel 82375 PCI-EISA bridge is a subtractive-decode PCI
+        * device, so the resources available on EISA are the same as those
+        * available on the 82375 bus.  This works the same as a PCI-PCI
+        * bridge in subtractive-decode mode (see pci_read_bridge_bases()).
+        * We assume other PCI-EISA bridges are similar.
+        *
+        * eisa_root_register() can only deal with a single io port resource,
+       *  so we use the first valid io port resource.
+        */
+       pci_bus_for_each_resource(pdev->bus, res, i)
+               if (res && (res->flags & IORESOURCE_IO)) {
+                       bus_res = res;
+                       break;
+               }
+
+       if (!bus_res) {
+               dev_err(&pdev->dev, "No resources available\n");
+               return -1;
+       }
+
        pci_eisa_root.dev              = &pdev->dev;
-       pci_eisa_root.res              = pdev->bus->resource[0];
-       pci_eisa_root.bus_base_addr    = pdev->bus->resource[0]->start;
+       pci_eisa_root.res              = bus_res;
+       pci_eisa_root.bus_base_addr    = bus_res->start;
        pci_eisa_root.slots            = EISA_MAX_SLOTS;
        pci_eisa_root.dma_mask         = pdev->dma_mask;
        dev_set_drvdata(pci_eisa_root.dev, &pci_eisa_root);
@@ -45,22 +66,26 @@ static int __init pci_eisa_init(struct pci_dev *pdev,
        return 0;
 }
 
-static struct pci_device_id pci_eisa_pci_tbl[] = {
-       { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
-         PCI_CLASS_BRIDGE_EISA << 8, 0xffff00, 0 },
-       { 0, }
-};
+/*
+ * We have to call pci_eisa_init_early() before pnpacpi_init()/isapnp_init().
+ *   Otherwise pnp resource will get enabled early and could prevent eisa
+ *   to be initialized.
+ * Also need to make sure pci_eisa_init_early() is called after
+ * x86/pci_subsys_init().
+ * So need to use subsys_initcall_sync with it.
+ */
+static int __init pci_eisa_init_early(void)
+{
+       struct pci_dev *dev = NULL;
+       int ret;
 
-static struct pci_driver __refdata pci_eisa_driver = {
-       .name           = "pci_eisa",
-       .id_table       = pci_eisa_pci_tbl,
-       .probe          = pci_eisa_init,
-};
+       for_each_pci_dev(dev)
+               if ((dev->class >> 8) == PCI_CLASS_BRIDGE_EISA) {
+                       ret = pci_eisa_init(dev);
+                       if (ret)
+                               return ret;
+               }
 
-static int __init pci_eisa_init_module (void)
-{
-       return pci_register_driver (&pci_eisa_driver);
+       return 0;
 }
-
-device_initcall(pci_eisa_init_module);
-MODULE_DEVICE_TABLE(pci, pci_eisa_pci_tbl);
+subsys_initcall_sync(pci_eisa_init_early);
index dc357a4..b289279 100644 (file)
@@ -100,6 +100,55 @@ static const char *arizona_cable[] = {
        NULL,
 };
 
+static void arizona_extcon_do_magic(struct arizona_extcon_info *info,
+                                   unsigned int magic)
+{
+       struct arizona *arizona = info->arizona;
+       int ret;
+
+       mutex_lock(&arizona->dapm->card->dapm_mutex);
+
+       arizona->hpdet_magic = magic;
+
+       /* Keep the HP output stages disabled while doing the magic */
+       if (magic) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, 0);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                               "Failed to disable headphone outputs: %d\n",
+                                ret);
+       }
+
+       ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
+                                magic);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to do magic: %d\n",
+                                ret);
+
+       ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
+                                magic);
+       if (ret != 0)
+               dev_warn(arizona->dev, "Failed to do magic: %d\n",
+                        ret);
+
+       /* Restore the desired state while not doing the magic */
+       if (!magic) {
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT1L_ENA |
+                                        ARIZONA_OUT1R_ENA, arizona->hp_ena);
+               if (ret != 0)
+                       dev_warn(arizona->dev,
+                                "Failed to restore headphone outputs: %d\n",
+                                ret);
+       }
+
+       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+}
+
 static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode)
 {
        struct arizona *arizona = info->arizona;
@@ -484,7 +533,6 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
        struct arizona *arizona = info->arizona;
        int id_gpio = arizona->pdata.hpdet_id_gpio;
        int report = ARIZONA_CABLE_HEADPHONE;
-       unsigned int val;
        int ret, reading;
 
        mutex_lock(&info->lock);
@@ -539,28 +587,7 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data)
                dev_err(arizona->dev, "Failed to report HP/line: %d\n",
                        ret);
 
-       mutex_lock(&arizona->dapm->card->dapm_mutex);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read output enables: %d\n",
-                       ret);
-               val = 0;
-       }
-
-       if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
-               ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to undo magic: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to undo magic: %d\n",
-                                ret);
-       }
-
-       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+       arizona_extcon_do_magic(info, 0);
 
 done:
        if (id_gpio)
@@ -606,13 +633,7 @@ static void arizona_identify_headphone(struct arizona_extcon_info *info)
        if (info->mic)
                arizona_stop_mic(info);
 
-       ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000, 0x4000);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
-
-       ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000, 0x4000);
-       if (ret != 0)
-               dev_warn(arizona->dev, "Failed to do magic: %d\n", ret);
+       arizona_extcon_do_magic(info, 0x4000);
 
        ret = regmap_update_bits(arizona->regmap,
                                 ARIZONA_ACCESSORY_DETECT_MODE_1,
@@ -653,7 +674,6 @@ err:
 static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
 {
        struct arizona *arizona = info->arizona;
-       unsigned int val;
        int ret;
 
        dev_dbg(arizona->dev, "Starting identification via HPDET\n");
@@ -665,30 +685,7 @@ static void arizona_start_hpdet_acc_id(struct arizona_extcon_info *info)
 
        arizona_extcon_pulse_micbias(info);
 
-       mutex_lock(&arizona->dapm->card->dapm_mutex);
-
-       ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &val);
-       if (ret != 0) {
-               dev_err(arizona->dev, "Failed to read output enables: %d\n",
-                       ret);
-               val = 0;
-       }
-
-       if (!(val & (ARIZONA_OUT1L_ENA | ARIZONA_OUT1R_ENA))) {
-               ret = regmap_update_bits(arizona->regmap, 0x225, 0x4000,
-                                        0x4000);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do magic: %d\n",
-                                ret);
-
-               ret = regmap_update_bits(arizona->regmap, 0x226, 0x4000,
-                                        0x4000);
-               if (ret != 0)
-                       dev_warn(arizona->dev, "Failed to do magic: %d\n",
-                                ret);
-       }
-
-       mutex_unlock(&arizona->dapm->card->dapm_mutex);
+       arizona_extcon_do_magic(info, 0x4000);
 
        ret = regmap_update_bits(arizona->regmap,
                                 ARIZONA_ACCESSORY_DETECT_MODE_1,
index b70e381..8f3c947 100644 (file)
 #define        DEV_NAME                        "max77693-muic"
 #define        DELAY_MS_DEFAULT                20000           /* unit: millisecond */
 
+/*
+ * Default value of MAX77693 register to bring up MUIC device.
+ * If user don't set some initial value for MUIC device through platform data,
+ * extcon-max77693 driver use 'default_init_data' to bring up base operation
+ * of MAX77693 MUIC device.
+ */
+struct max77693_reg_data default_init_data[] = {
+       {
+               /* STATUS2 - [3]ChgDetRun */
+               .addr = MAX77693_MUIC_REG_STATUS2,
+               .data = STATUS2_CHGDETRUN_MASK,
+       }, {
+               /* INTMASK1 - Unmask [3]ADC1KM,[0]ADCM */
+               .addr = MAX77693_MUIC_REG_INTMASK1,
+               .data = INTMASK1_ADC1K_MASK
+                       | INTMASK1_ADC_MASK,
+       }, {
+               /* INTMASK2 - Unmask [0]ChgTypM */
+               .addr = MAX77693_MUIC_REG_INTMASK2,
+               .data = INTMASK2_CHGTYP_MASK,
+       }, {
+               /* INTMASK3 - Mask all of interrupts */
+               .addr = MAX77693_MUIC_REG_INTMASK3,
+               .data = 0x0,
+       }, {
+               /* CDETCTRL2 */
+               .addr = MAX77693_MUIC_REG_CDETCTRL2,
+               .data = CDETCTRL2_VIDRMEN_MASK
+                       | CDETCTRL2_DXOVPEN_MASK,
+       },
+};
+
 enum max77693_muic_adc_debounce_time {
        ADC_DEBOUNCE_TIME_5MS = 0,
        ADC_DEBOUNCE_TIME_10MS,
@@ -1045,8 +1077,9 @@ static int max77693_muic_probe(struct platform_device *pdev)
 {
        struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
        struct max77693_platform_data *pdata = dev_get_platdata(max77693->dev);
-       struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
        struct max77693_muic_info *info;
+       struct max77693_reg_data *init_data;
+       int num_init_data;
        int delay_jiffies;
        int ret;
        int i;
@@ -1145,15 +1178,25 @@ static int max77693_muic_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
-       /* Initialize MUIC register by using platform data */
-       for (i = 0 ; i < muic_pdata->num_init_data ; i++) {
-               enum max77693_irq_source irq_src = MAX77693_IRQ_GROUP_NR;
+
+       /* Initialize MUIC register by using platform data or default data */
+       if (pdata->muic_data) {
+               init_data = pdata->muic_data->init_data;
+               num_init_data = pdata->muic_data->num_init_data;
+       } else {
+               init_data = default_init_data;
+               num_init_data = ARRAY_SIZE(default_init_data);
+       }
+
+       for (i = 0 ; i < num_init_data ; i++) {
+               enum max77693_irq_source irq_src
+                               = MAX77693_IRQ_GROUP_NR;
 
                max77693_write_reg(info->max77693->regmap_muic,
-                               muic_pdata->init_data[i].addr,
-                               muic_pdata->init_data[i].data);
+                               init_data[i].addr,
+                               init_data[i].data);
 
-               switch (muic_pdata->init_data[i].addr) {
+               switch (init_data[i].addr) {
                case MAX77693_MUIC_REG_INTMASK1:
                        irq_src = MUIC_INT1;
                        break;
@@ -1167,22 +1210,40 @@ static int max77693_muic_probe(struct platform_device *pdev)
 
                if (irq_src < MAX77693_IRQ_GROUP_NR)
                        info->max77693->irq_masks_cur[irq_src]
-                               = muic_pdata->init_data[i].data;
+                               = init_data[i].data;
        }
 
-       /*
-        * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
-        * h/w path of COMP2/COMN1 on CONTROL1 register.
-        */
-       if (muic_pdata->path_uart)
-               info->path_uart = muic_pdata->path_uart;
-       else
-               info->path_uart = CONTROL1_SW_UART;
+       if (pdata->muic_data) {
+               struct max77693_muic_platform_data *muic_pdata = pdata->muic_data;
 
-       if (muic_pdata->path_usb)
-               info->path_usb = muic_pdata->path_usb;
-       else
+               /*
+                * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+                * h/w path of COMP2/COMN1 on CONTROL1 register.
+                */
+               if (muic_pdata->path_uart)
+                       info->path_uart = muic_pdata->path_uart;
+               else
+                       info->path_uart = CONTROL1_SW_UART;
+
+               if (muic_pdata->path_usb)
+                       info->path_usb = muic_pdata->path_usb;
+               else
+                       info->path_usb = CONTROL1_SW_USB;
+
+               /*
+                * Default delay time for detecting cable state
+                * after certain time.
+                */
+               if (muic_pdata->detcable_delay_ms)
+                       delay_jiffies =
+                               msecs_to_jiffies(muic_pdata->detcable_delay_ms);
+               else
+                       delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+       } else {
                info->path_usb = CONTROL1_SW_USB;
+               info->path_uart = CONTROL1_SW_UART;
+               delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+       }
 
        /* Set initial path for UART */
         max77693_muic_set_path(info, info->path_uart, true);
@@ -1208,10 +1269,6 @@ static int max77693_muic_probe(struct platform_device *pdev)
         * driver should notify cable state to upper layer.
         */
        INIT_DELAYED_WORK(&info->wq_detcable, max77693_muic_detect_cable_wq);
-       if (muic_pdata->detcable_delay_ms)
-               delay_jiffies = msecs_to_jiffies(muic_pdata->detcable_delay_ms);
-       else
-               delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
        schedule_delayed_work(&info->wq_detcable, delay_jiffies);
 
        return ret;
index e636d95..69641bc 100644 (file)
@@ -712,29 +712,45 @@ static int max8997_muic_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
-       /* Initialize registers according to platform data */
        if (pdata->muic_pdata) {
-               struct max8997_muic_platform_data *mdata = info->muic_pdata;
-
-               for (i = 0; i < mdata->num_init_data; i++) {
-                       max8997_write_reg(info->muic, mdata->init_data[i].addr,
-                                       mdata->init_data[i].data);
+               struct max8997_muic_platform_data *muic_pdata
+                       = pdata->muic_pdata;
+
+               /* Initialize registers according to platform data */
+               for (i = 0; i < muic_pdata->num_init_data; i++) {
+                       max8997_write_reg(info->muic,
+                                       muic_pdata->init_data[i].addr,
+                                       muic_pdata->init_data[i].data);
                }
-       }
 
-       /*
-        * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
-        * h/w path of COMP2/COMN1 on CONTROL1 register.
-        */
-       if (pdata->muic_pdata->path_uart)
-               info->path_uart = pdata->muic_pdata->path_uart;
-       else
-               info->path_uart = CONTROL1_SW_UART;
+               /*
+                * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
+                * h/w path of COMP2/COMN1 on CONTROL1 register.
+                */
+               if (muic_pdata->path_uart)
+                       info->path_uart = muic_pdata->path_uart;
+               else
+                       info->path_uart = CONTROL1_SW_UART;
 
-       if (pdata->muic_pdata->path_usb)
-               info->path_usb = pdata->muic_pdata->path_usb;
-       else
+               if (muic_pdata->path_usb)
+                       info->path_usb = muic_pdata->path_usb;
+               else
+                       info->path_usb = CONTROL1_SW_USB;
+
+               /*
+                * Default delay time for detecting cable state
+                * after certain time.
+                */
+               if (muic_pdata->detcable_delay_ms)
+                       delay_jiffies =
+                               msecs_to_jiffies(muic_pdata->detcable_delay_ms);
+               else
+                       delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+       } else {
+               info->path_uart = CONTROL1_SW_UART;
                info->path_usb = CONTROL1_SW_USB;
+               delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
+       }
 
        /* Set initial path for UART */
         max8997_muic_set_path(info, info->path_uart, true);
@@ -751,10 +767,6 @@ static int max8997_muic_probe(struct platform_device *pdev)
         * driver should notify cable state to upper layer.
         */
        INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
-       if (pdata->muic_pdata->detcable_delay_ms)
-               delay_jiffies = msecs_to_jiffies(pdata->muic_pdata->detcable_delay_ms);
-       else
-               delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
        schedule_delayed_work(&info->wq_detcable, delay_jiffies);
 
        return 0;
index 9b00072..42c759a 100644 (file)
@@ -53,6 +53,24 @@ config EFI_VARS
          Subsequent efibootmgr releases may be found at:
          <http://linux.dell.com/efibootmgr>
 
+config EFI_VARS_PSTORE
+       bool "Register efivars backend for pstore"
+       depends on EFI_VARS && PSTORE
+       default y
+       help
+         Say Y here to enable use efivars as a backend to pstore. This
+         will allow writing console messages, crash dumps, or anything
+         else supported by pstore to EFI variables.
+
+config EFI_VARS_PSTORE_DEFAULT_DISABLE
+       bool "Disable using efivars as a pstore backend by default"
+       depends on EFI_VARS_PSTORE
+       default n
+       help
+         Saying Y here will disable the use of efivars as a storage
+         backend for pstore by default. This setting can be overridden
+         using the efivars module's pstore_disable parameter.
+
 config EFI_PCDP
        bool "Console device selection via EFI PCDP or HCDP table"
        depends on ACPI && EFI && IA64
index fe62aa3..7acafb8 100644 (file)
@@ -103,6 +103,11 @@ MODULE_VERSION(EFIVARS_VERSION);
  */
 #define GUID_LEN 36
 
+static bool efivars_pstore_disable =
+       IS_ENABLED(CONFIG_EFI_VARS_PSTORE_DEFAULT_DISABLE);
+
+module_param_named(pstore_disable, efivars_pstore_disable, bool, 0644);
+
 /*
  * The maximum size of VariableName + Data = 1024
  * Therefore, it's reasonable to save that much
@@ -165,6 +170,7 @@ efivar_create_sysfs_entry(struct efivars *efivars,
 
 static void efivar_update_sysfs_entries(struct work_struct *);
 static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
+static bool efivar_wq_enabled = true;
 
 /* Return the number of unicode characters in data */
 static unsigned long
@@ -1309,9 +1315,7 @@ static const struct inode_operations efivarfs_dir_inode_operations = {
        .create = efivarfs_create,
 };
 
-static struct pstore_info efi_pstore_info;
-
-#ifdef CONFIG_PSTORE
+#ifdef CONFIG_EFI_VARS_PSTORE
 
 static int efi_pstore_open(struct pstore_info *psi)
 {
@@ -1441,7 +1445,7 @@ static int efi_pstore_write(enum pstore_type_id type,
 
        spin_unlock_irqrestore(&efivars->lock, flags);
 
-       if (reason == KMSG_DUMP_OOPS)
+       if (reason == KMSG_DUMP_OOPS && efivar_wq_enabled)
                schedule_work(&efivar_work);
 
        *id = part;
@@ -1514,38 +1518,6 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
 
        return 0;
 }
-#else
-static int efi_pstore_open(struct pstore_info *psi)
-{
-       return 0;
-}
-
-static int efi_pstore_close(struct pstore_info *psi)
-{
-       return 0;
-}
-
-static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, int *count,
-                              struct timespec *timespec,
-                              char **buf, struct pstore_info *psi)
-{
-       return -1;
-}
-
-static int efi_pstore_write(enum pstore_type_id type,
-               enum kmsg_dump_reason reason, u64 *id,
-               unsigned int part, int count, size_t size,
-               struct pstore_info *psi)
-{
-       return 0;
-}
-
-static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
-                           struct timespec time, struct pstore_info *psi)
-{
-       return 0;
-}
-#endif
 
 static struct pstore_info efi_pstore_info = {
        .owner          = THIS_MODULE,
@@ -1557,6 +1529,24 @@ static struct pstore_info efi_pstore_info = {
        .erase          = efi_pstore_erase,
 };
 
+static void efivar_pstore_register(struct efivars *efivars)
+{
+       efivars->efi_pstore_info = efi_pstore_info;
+       efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
+       if (efivars->efi_pstore_info.buf) {
+               efivars->efi_pstore_info.bufsize = 1024;
+               efivars->efi_pstore_info.data = efivars;
+               spin_lock_init(&efivars->efi_pstore_info.buf_lock);
+               pstore_register(&efivars->efi_pstore_info);
+       }
+}
+#else
+static void efivar_pstore_register(struct efivars *efivars)
+{
+       return;
+}
+#endif
+
 static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
                             struct bin_attribute *bin_attr,
                             char *buf, loff_t pos, size_t count)
@@ -1716,6 +1706,31 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
        return found;
 }
 
+/*
+ * Returns the size of variable_name, in bytes, including the
+ * terminating NULL character, or variable_name_size if no NULL
+ * character is found among the first variable_name_size bytes.
+ */
+static unsigned long var_name_strnsize(efi_char16_t *variable_name,
+                                      unsigned long variable_name_size)
+{
+       unsigned long len;
+       efi_char16_t c;
+
+       /*
+        * The variable name is, by definition, a NULL-terminated
+        * string, so make absolutely sure that variable_name_size is
+        * the value we expect it to be. If not, return the real size.
+        */
+       for (len = 2; len <= variable_name_size; len += sizeof(c)) {
+               c = variable_name[(len / sizeof(c)) - 1];
+               if (!c)
+                       break;
+       }
+
+       return min(len, variable_name_size);
+}
+
 static void efivar_update_sysfs_entries(struct work_struct *work)
 {
        struct efivars *efivars = &__efivars;
@@ -1756,10 +1771,13 @@ static void efivar_update_sysfs_entries(struct work_struct *work)
                if (!found) {
                        kfree(variable_name);
                        break;
-               } else
+               } else {
+                       variable_name_size = var_name_strnsize(variable_name,
+                                                              variable_name_size);
                        efivar_create_sysfs_entry(efivars,
                                                  variable_name_size,
                                                  variable_name, &vendor);
+               }
        }
 }
 
@@ -1958,6 +1976,35 @@ void unregister_efivars(struct efivars *efivars)
 }
 EXPORT_SYMBOL_GPL(unregister_efivars);
 
+/*
+ * Print a warning when duplicate EFI variables are encountered and
+ * disable the sysfs workqueue since the firmware is buggy.
+ */
+static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid,
+                            unsigned long len16)
+{
+       size_t i, len8 = len16 / sizeof(efi_char16_t);
+       char *s8;
+
+       /*
+        * Disable the workqueue since the algorithm it uses for
+        * detecting new variables won't work with this buggy
+        * implementation of GetNextVariableName().
+        */
+       efivar_wq_enabled = false;
+
+       s8 = kzalloc(len8, GFP_KERNEL);
+       if (!s8)
+               return;
+
+       for (i = 0; i < len8; i++)
+               s8[i] = s16[i];
+
+       printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n",
+              s8, vendor_guid);
+       kfree(s8);
+}
+
 int register_efivars(struct efivars *efivars,
                     const struct efivar_operations *ops,
                     struct kobject *parent_kobj)
@@ -2006,6 +2053,24 @@ int register_efivars(struct efivars *efivars,
                                                &vendor_guid);
                switch (status) {
                case EFI_SUCCESS:
+                       variable_name_size = var_name_strnsize(variable_name,
+                                                              variable_name_size);
+
+                       /*
+                        * Some firmware implementations return the
+                        * same variable name on multiple calls to
+                        * get_next_variable(). Terminate the loop
+                        * immediately as there is no guarantee that
+                        * we'll ever see a different variable name,
+                        * and may end up looping here forever.
+                        */
+                       if (variable_is_present(variable_name, &vendor_guid)) {
+                               dup_variable_bug(variable_name, &vendor_guid,
+                                                variable_name_size);
+                               status = EFI_NOT_FOUND;
+                               break;
+                       }
+
                        efivar_create_sysfs_entry(efivars,
                                                  variable_name_size,
                                                  variable_name,
@@ -2025,15 +2090,8 @@ int register_efivars(struct efivars *efivars,
        if (error)
                unregister_efivars(efivars);
 
-       efivars->efi_pstore_info = efi_pstore_info;
-
-       efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL);
-       if (efivars->efi_pstore_info.buf) {
-               efivars->efi_pstore_info.bufsize = 1024;
-               efivars->efi_pstore_info.data = efivars;
-               spin_lock_init(&efivars->efi_pstore_info.buf_lock);
-               pstore_register(&efivars->efi_pstore_info);
-       }
+       if (!efivars_pstore_disable)
+               efivar_pstore_register(efivars);
 
        register_filesystem(&efivarfs_type);
 
index f9dbd50..de3c317 100644 (file)
@@ -214,7 +214,7 @@ static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
         * If it can't be trusted, assume that the pin can be used as a GPIO.
         */
        if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f)))
-               return 1;
+               return 0;
 
        return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
 }
index 770476a..3ce5bc3 100644 (file)
@@ -307,11 +307,15 @@ static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = {
        .xlate = irq_domain_xlate_twocell,
 };
 
-static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
+static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio,
+               struct device_node *np)
 {
-       int base = stmpe_gpio->irq_base;
+       int base = 0;
 
-       stmpe_gpio->domain = irq_domain_add_simple(NULL,
+       if (!np)
+               base = stmpe_gpio->irq_base;
+
+       stmpe_gpio->domain = irq_domain_add_simple(np,
                                stmpe_gpio->chip.ngpio, base,
                                &stmpe_gpio_irq_simple_ops, stmpe_gpio);
        if (!stmpe_gpio->domain) {
@@ -346,6 +350,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
        stmpe_gpio->chip = template_chip;
        stmpe_gpio->chip.ngpio = stmpe->num_gpios;
        stmpe_gpio->chip.dev = &pdev->dev;
+#ifdef CONFIG_OF
+       stmpe_gpio->chip.of_node = np;
+#endif
        stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
 
        if (pdata)
@@ -366,7 +373,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
                goto out_free;
 
        if (irq >= 0) {
-               ret = stmpe_gpio_irq_init(stmpe_gpio);
+               ret = stmpe_gpio_irq_init(stmpe_gpio, np);
                if (ret)
                        goto out_disable;
 
index a71a54a..5150df6 100644 (file)
@@ -193,7 +193,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
        if (!np)
                return;
 
-       do {
+       for (;; index++) {
                ret = of_parse_phandle_with_args(np, "gpio-ranges",
                                "#gpio-range-cells", index, &pinspec);
                if (ret)
@@ -222,8 +222,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
 
                if (ret)
                        break;
-
-       } while (index++);
+       }
 }
 
 #else
index 792c3e3..dd64a06 100644 (file)
@@ -2326,7 +2326,6 @@ int drm_mode_addfb(struct drm_device *dev,
        fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
        if (IS_ERR(fb)) {
                DRM_DEBUG_KMS("could not create framebuffer\n");
-               drm_modeset_unlock_all(dev);
                return PTR_ERR(fb);
        }
 
@@ -2506,7 +2505,6 @@ int drm_mode_addfb2(struct drm_device *dev,
        fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
        if (IS_ERR(fb)) {
                DRM_DEBUG_KMS("could not create framebuffer\n");
-               drm_modeset_unlock_all(dev);
                return PTR_ERR(fb);
        }
 
index 13fdcd1..429e07d 100644 (file)
@@ -123,6 +123,7 @@ int drm_open(struct inode *inode, struct file *filp)
        int retcode = 0;
        int need_setup = 0;
        struct address_space *old_mapping;
+       struct address_space *old_imapping;
 
        minor = idr_find(&drm_minors_idr, minor_id);
        if (!minor)
@@ -137,6 +138,7 @@ int drm_open(struct inode *inode, struct file *filp)
        if (!dev->open_count++)
                need_setup = 1;
        mutex_lock(&dev->struct_mutex);
+       old_imapping = inode->i_mapping;
        old_mapping = dev->dev_mapping;
        if (old_mapping == NULL)
                dev->dev_mapping = &inode->i_data;
@@ -159,8 +161,8 @@ int drm_open(struct inode *inode, struct file *filp)
 
 err_undo:
        mutex_lock(&dev->struct_mutex);
-       filp->f_mapping = old_mapping;
-       inode->i_mapping = old_mapping;
+       filp->f_mapping = old_imapping;
+       inode->i_mapping = old_imapping;
        iput(container_of(dev->dev_mapping, struct inode, i_data));
        dev->dev_mapping = old_mapping;
        mutex_unlock(&dev->struct_mutex);
index 36493ce..98cc147 100644 (file)
 /* position control register for hardware window 0, 2 ~ 4.*/
 #define VIDOSD_A(win)          (VIDOSD_BASE + 0x00 + (win) * 16)
 #define VIDOSD_B(win)          (VIDOSD_BASE + 0x04 + (win) * 16)
-/* size control register for hardware window 0. */
-#define VIDOSD_C_SIZE_W0       (VIDOSD_BASE + 0x08)
-/* alpha control register for hardware window 1 ~ 4. */
-#define VIDOSD_C(win)          (VIDOSD_BASE + 0x18 + (win) * 16)
-/* size control register for hardware window 1 ~ 4. */
+/*
+ * size control register for hardware windows 0 and alpha control register
+ * for hardware windows 1 ~ 4
+ */
+#define VIDOSD_C(win)          (VIDOSD_BASE + 0x08 + (win) * 16)
+/* size control register for hardware windows 1 ~ 2. */
 #define VIDOSD_D(win)          (VIDOSD_BASE + 0x0C + (win) * 16)
 
 #define VIDWx_BUF_START(win, buf)      (VIDW_BUF_START(buf) + (win) * 8)
@@ -50,9 +51,9 @@
 #define VIDWx_BUF_SIZE(win, buf)       (VIDW_BUF_SIZE(buf) + (win) * 4)
 
 /* color key control register for hardware window 1 ~ 4. */
-#define WKEYCON0_BASE(x)               ((WKEYCON0 + 0x140) + (x * 8))
+#define WKEYCON0_BASE(x)               ((WKEYCON0 + 0x140) + ((x - 1) * 8))
 /* color key value register for hardware window 1 ~ 4. */
-#define WKEYCON1_BASE(x)               ((WKEYCON1 + 0x140) + (x * 8))
+#define WKEYCON1_BASE(x)               ((WKEYCON1 + 0x140) + ((x - 1) * 8))
 
 /* FIMD has totally five hardware windows. */
 #define WINDOWS_NR     5
@@ -109,9 +110,9 @@ struct fimd_context {
 
 #ifdef CONFIG_OF
 static const struct of_device_id fimd_driver_dt_match[] = {
-       { .compatible = "samsung,exynos4-fimd",
+       { .compatible = "samsung,exynos4210-fimd",
          .data = &exynos4_fimd_driver_data },
-       { .compatible = "samsung,exynos5-fimd",
+       { .compatible = "samsung,exynos5250-fimd",
          .data = &exynos5_fimd_driver_data },
        {},
 };
@@ -581,7 +582,7 @@ static void fimd_win_commit(struct device *dev, int zpos)
        if (win != 3 && win != 4) {
                u32 offset = VIDOSD_D(win);
                if (win == 0)
-                       offset = VIDOSD_C_SIZE_W0;
+                       offset = VIDOSD_C(win);
                val = win_data->ovl_width * win_data->ovl_height;
                writel(val, ctx->regs + offset);
 
index 3b0da03..47a493c 100644 (file)
 
 /* registers for base address */
 #define G2D_SRC_BASE_ADDR              0x0304
+#define G2D_SRC_COLOR_MODE             0x030C
+#define G2D_SRC_LEFT_TOP               0x0310
+#define G2D_SRC_RIGHT_BOTTOM           0x0314
 #define G2D_SRC_PLANE2_BASE_ADDR       0x0318
 #define G2D_DST_BASE_ADDR              0x0404
+#define G2D_DST_COLOR_MODE             0x040C
+#define G2D_DST_LEFT_TOP               0x0410
+#define G2D_DST_RIGHT_BOTTOM           0x0414
 #define G2D_DST_PLANE2_BASE_ADDR       0x0418
 #define G2D_PAT_BASE_ADDR              0x0500
 #define G2D_MSK_BASE_ADDR              0x0520
@@ -82,7 +88,7 @@
 #define G2D_DMA_LIST_DONE_COUNT_OFFSET 17
 
 /* G2D_DMA_HOLD_CMD */
-#define G2D_USET_HOLD                  (1 << 2)
+#define G2D_USER_HOLD                  (1 << 2)
 #define G2D_LIST_HOLD                  (1 << 1)
 #define G2D_BITBLT_HOLD                        (1 << 0)
 
 #define G2D_START_NHOLT                        (1 << 1)
 #define G2D_START_BITBLT               (1 << 0)
 
+/* buffer color format */
+#define G2D_FMT_XRGB8888               0
+#define G2D_FMT_ARGB8888               1
+#define G2D_FMT_RGB565                 2
+#define G2D_FMT_XRGB1555               3
+#define G2D_FMT_ARGB1555               4
+#define G2D_FMT_XRGB4444               5
+#define G2D_FMT_ARGB4444               6
+#define G2D_FMT_PACKED_RGB888          7
+#define G2D_FMT_A8                     11
+#define G2D_FMT_L8                     12
+
+/* buffer valid length */
+#define G2D_LEN_MIN                    1
+#define G2D_LEN_MAX                    8000
+
 #define G2D_CMDLIST_SIZE               (PAGE_SIZE / 4)
 #define G2D_CMDLIST_NUM                        64
 #define G2D_CMDLIST_POOL_SIZE          (G2D_CMDLIST_SIZE * G2D_CMDLIST_NUM)
 #define G2D_CMDLIST_DATA_NUM           (G2D_CMDLIST_SIZE / sizeof(u32) - 2)
 
-#define MAX_BUF_ADDR_NR                        6
-
 /* maximum buffer pool size of userptr is 64MB as default */
 #define MAX_POOL               (64 * 1024 * 1024)
 
@@ -106,6 +126,17 @@ enum {
        BUF_TYPE_USERPTR,
 };
 
+enum g2d_reg_type {
+       REG_TYPE_NONE = -1,
+       REG_TYPE_SRC,
+       REG_TYPE_SRC_PLANE2,
+       REG_TYPE_DST,
+       REG_TYPE_DST_PLANE2,
+       REG_TYPE_PAT,
+       REG_TYPE_MSK,
+       MAX_REG_TYPE_NR
+};
+
 /* cmdlist data structure */
 struct g2d_cmdlist {
        u32             head;
@@ -113,6 +144,42 @@ struct g2d_cmdlist {
        u32             last;   /* last data offset */
 };
 
+/*
+ * A structure of buffer description
+ *
+ * @format: color format
+ * @left_x: the x coordinates of left top corner
+ * @top_y: the y coordinates of left top corner
+ * @right_x: the x coordinates of right bottom corner
+ * @bottom_y: the y coordinates of right bottom corner
+ *
+ */
+struct g2d_buf_desc {
+       unsigned int    format;
+       unsigned int    left_x;
+       unsigned int    top_y;
+       unsigned int    right_x;
+       unsigned int    bottom_y;
+};
+
+/*
+ * A structure of buffer information
+ *
+ * @map_nr: manages the number of mapped buffers
+ * @reg_types: stores regitster type in the order of requested command
+ * @handles: stores buffer handle in its reg_type position
+ * @types: stores buffer type in its reg_type position
+ * @descs: stores buffer description in its reg_type position
+ *
+ */
+struct g2d_buf_info {
+       unsigned int            map_nr;
+       enum g2d_reg_type       reg_types[MAX_REG_TYPE_NR];
+       unsigned long           handles[MAX_REG_TYPE_NR];
+       unsigned int            types[MAX_REG_TYPE_NR];
+       struct g2d_buf_desc     descs[MAX_REG_TYPE_NR];
+};
+
 struct drm_exynos_pending_g2d_event {
        struct drm_pending_event        base;
        struct drm_exynos_g2d_event     event;
@@ -131,14 +198,11 @@ struct g2d_cmdlist_userptr {
        bool                    in_pool;
        bool                    out_of_list;
 };
-
 struct g2d_cmdlist_node {
        struct list_head        list;
        struct g2d_cmdlist      *cmdlist;
-       unsigned int            map_nr;
-       unsigned long           handles[MAX_BUF_ADDR_NR];
-       unsigned int            obj_type[MAX_BUF_ADDR_NR];
        dma_addr_t              dma_addr;
+       struct g2d_buf_info     buf_info;
 
        struct drm_exynos_pending_g2d_event     *event;
 };
@@ -188,6 +252,7 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
        struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
        int nr;
        int ret;
+       struct g2d_buf_info *buf_info;
 
        init_dma_attrs(&g2d->cmdlist_dma_attrs);
        dma_set_attr(DMA_ATTR_WRITE_COMBINE, &g2d->cmdlist_dma_attrs);
@@ -209,11 +274,17 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
        }
 
        for (nr = 0; nr < G2D_CMDLIST_NUM; nr++) {
+               unsigned int i;
+
                node[nr].cmdlist =
                        g2d->cmdlist_pool_virt + nr * G2D_CMDLIST_SIZE;
                node[nr].dma_addr =
                        g2d->cmdlist_pool + nr * G2D_CMDLIST_SIZE;
 
+               buf_info = &node[nr].buf_info;
+               for (i = 0; i < MAX_REG_TYPE_NR; i++)
+                       buf_info->reg_types[i] = REG_TYPE_NONE;
+
                list_add_tail(&node[nr].list, &g2d->free_cmdlist);
        }
 
@@ -450,7 +521,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
                                                DMA_BIDIRECTIONAL);
        if (ret < 0) {
                DRM_ERROR("failed to map sgt with dma region.\n");
-               goto err_free_sgt;
+               goto err_sg_free_table;
        }
 
        g2d_userptr->dma_addr = sgt->sgl[0].dma_address;
@@ -467,8 +538,10 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 
        return &g2d_userptr->dma_addr;
 
-err_free_sgt:
+err_sg_free_table:
        sg_free_table(sgt);
+
+err_free_sgt:
        kfree(sgt);
        sgt = NULL;
 
@@ -506,36 +579,172 @@ static void g2d_userptr_free_all(struct drm_device *drm_dev,
        g2d->current_pool = 0;
 }
 
+static enum g2d_reg_type g2d_get_reg_type(int reg_offset)
+{
+       enum g2d_reg_type reg_type;
+
+       switch (reg_offset) {
+       case G2D_SRC_BASE_ADDR:
+       case G2D_SRC_COLOR_MODE:
+       case G2D_SRC_LEFT_TOP:
+       case G2D_SRC_RIGHT_BOTTOM:
+               reg_type = REG_TYPE_SRC;
+               break;
+       case G2D_SRC_PLANE2_BASE_ADDR:
+               reg_type = REG_TYPE_SRC_PLANE2;
+               break;
+       case G2D_DST_BASE_ADDR:
+       case G2D_DST_COLOR_MODE:
+       case G2D_DST_LEFT_TOP:
+       case G2D_DST_RIGHT_BOTTOM:
+               reg_type = REG_TYPE_DST;
+               break;
+       case G2D_DST_PLANE2_BASE_ADDR:
+               reg_type = REG_TYPE_DST_PLANE2;
+               break;
+       case G2D_PAT_BASE_ADDR:
+               reg_type = REG_TYPE_PAT;
+               break;
+       case G2D_MSK_BASE_ADDR:
+               reg_type = REG_TYPE_MSK;
+               break;
+       default:
+               reg_type = REG_TYPE_NONE;
+               DRM_ERROR("Unknown register offset![%d]\n", reg_offset);
+               break;
+       };
+
+       return reg_type;
+}
+
+static unsigned long g2d_get_buf_bpp(unsigned int format)
+{
+       unsigned long bpp;
+
+       switch (format) {
+       case G2D_FMT_XRGB8888:
+       case G2D_FMT_ARGB8888:
+               bpp = 4;
+               break;
+       case G2D_FMT_RGB565:
+       case G2D_FMT_XRGB1555:
+       case G2D_FMT_ARGB1555:
+       case G2D_FMT_XRGB4444:
+       case G2D_FMT_ARGB4444:
+               bpp = 2;
+               break;
+       case G2D_FMT_PACKED_RGB888:
+               bpp = 3;
+               break;
+       default:
+               bpp = 1;
+               break;
+       }
+
+       return bpp;
+}
+
+static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc,
+                                               enum g2d_reg_type reg_type,
+                                               unsigned long size)
+{
+       unsigned int width, height;
+       unsigned long area;
+
+       /*
+        * check source and destination buffers only.
+        * so the others are always valid.
+        */
+       if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST)
+               return true;
+
+       width = buf_desc->right_x - buf_desc->left_x;
+       if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) {
+               DRM_ERROR("width[%u] is out of range!\n", width);
+               return false;
+       }
+
+       height = buf_desc->bottom_y - buf_desc->top_y;
+       if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) {
+               DRM_ERROR("height[%u] is out of range!\n", height);
+               return false;
+       }
+
+       area = (unsigned long)width * (unsigned long)height *
+                                       g2d_get_buf_bpp(buf_desc->format);
+       if (area > size) {
+               DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size);
+               return false;
+       }
+
+       return true;
+}
+
 static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
                                struct g2d_cmdlist_node *node,
                                struct drm_device *drm_dev,
                                struct drm_file *file)
 {
        struct g2d_cmdlist *cmdlist = node->cmdlist;
+       struct g2d_buf_info *buf_info = &node->buf_info;
        int offset;
+       int ret;
        int i;
 
-       for (i = 0; i < node->map_nr; i++) {
+       for (i = 0; i < buf_info->map_nr; i++) {
+               struct g2d_buf_desc *buf_desc;
+               enum g2d_reg_type reg_type;
+               int reg_pos;
                unsigned long handle;
                dma_addr_t *addr;
 
-               offset = cmdlist->last - (i * 2 + 1);
-               handle = cmdlist->data[offset];
+               reg_pos = cmdlist->last - 2 * (i + 1);
+
+               offset = cmdlist->data[reg_pos];
+               handle = cmdlist->data[reg_pos + 1];
+
+               reg_type = g2d_get_reg_type(offset);
+               if (reg_type == REG_TYPE_NONE) {
+                       ret = -EFAULT;
+                       goto err;
+               }
+
+               buf_desc = &buf_info->descs[reg_type];
+
+               if (buf_info->types[reg_type] == BUF_TYPE_GEM) {
+                       unsigned long size;
+
+                       size = exynos_drm_gem_get_size(drm_dev, handle, file);
+                       if (!size) {
+                               ret = -EFAULT;
+                               goto err;
+                       }
+
+                       if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
+                                                                       size)) {
+                               ret = -EFAULT;
+                               goto err;
+                       }
 
-               if (node->obj_type[i] == BUF_TYPE_GEM) {
                        addr = exynos_drm_gem_get_dma_addr(drm_dev, handle,
                                                                file);
                        if (IS_ERR(addr)) {
-                               node->map_nr = i;
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto err;
                        }
                } else {
                        struct drm_exynos_g2d_userptr g2d_userptr;
 
                        if (copy_from_user(&g2d_userptr, (void __user *)handle,
                                sizeof(struct drm_exynos_g2d_userptr))) {
-                               node->map_nr = i;
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto err;
+                       }
+
+                       if (!g2d_check_buf_desc_is_valid(buf_desc, reg_type,
+                                                       g2d_userptr.size)) {
+                               ret = -EFAULT;
+                               goto err;
                        }
 
                        addr = g2d_userptr_get_dma_addr(drm_dev,
@@ -544,16 +753,21 @@ static int g2d_map_cmdlist_gem(struct g2d_data *g2d,
                                                        file,
                                                        &handle);
                        if (IS_ERR(addr)) {
-                               node->map_nr = i;
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto err;
                        }
                }
 
-               cmdlist->data[offset] = *addr;
-               node->handles[i] = handle;
+               cmdlist->data[reg_pos + 1] = *addr;
+               buf_info->reg_types[i] = reg_type;
+               buf_info->handles[reg_type] = handle;
        }
 
        return 0;
+
+err:
+       buf_info->map_nr = i;
+       return ret;
 }
 
 static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
@@ -561,22 +775,33 @@ static void g2d_unmap_cmdlist_gem(struct g2d_data *g2d,
                                  struct drm_file *filp)
 {
        struct exynos_drm_subdrv *subdrv = &g2d->subdrv;
+       struct g2d_buf_info *buf_info = &node->buf_info;
        int i;
 
-       for (i = 0; i < node->map_nr; i++) {
-               unsigned long handle = node->handles[i];
+       for (i = 0; i < buf_info->map_nr; i++) {
+               struct g2d_buf_desc *buf_desc;
+               enum g2d_reg_type reg_type;
+               unsigned long handle;
+
+               reg_type = buf_info->reg_types[i];
+
+               buf_desc = &buf_info->descs[reg_type];
+               handle = buf_info->handles[reg_type];
 
-               if (node->obj_type[i] == BUF_TYPE_GEM)
+               if (buf_info->types[reg_type] == BUF_TYPE_GEM)
                        exynos_drm_gem_put_dma_addr(subdrv->drm_dev, handle,
                                                        filp);
                else
                        g2d_userptr_put_dma_addr(subdrv->drm_dev, handle,
                                                        false);
 
-               node->handles[i] = 0;
+               buf_info->reg_types[i] = REG_TYPE_NONE;
+               buf_info->handles[reg_type] = 0;
+               buf_info->types[reg_type] = 0;
+               memset(buf_desc, 0x00, sizeof(*buf_desc));
        }
 
-       node->map_nr = 0;
+       buf_info->map_nr = 0;
 }
 
 static void g2d_dma_start(struct g2d_data *g2d,
@@ -589,10 +814,6 @@ static void g2d_dma_start(struct g2d_data *g2d,
        pm_runtime_get_sync(g2d->dev);
        clk_enable(g2d->gate_clk);
 
-       /* interrupt enable */
-       writel_relaxed(G2D_INTEN_ACF | G2D_INTEN_UCF | G2D_INTEN_GCF,
-                       g2d->regs + G2D_INTEN);
-
        writel_relaxed(node->dma_addr, g2d->regs + G2D_DMA_SFR_BASE_ADDR);
        writel_relaxed(G2D_DMA_START, g2d->regs + G2D_DMA_COMMAND);
 }
@@ -643,7 +864,6 @@ static void g2d_runqueue_worker(struct work_struct *work)
        struct g2d_data *g2d = container_of(work, struct g2d_data,
                                            runqueue_work);
 
-
        mutex_lock(&g2d->runqueue_mutex);
        clk_disable(g2d->gate_clk);
        pm_runtime_put_sync(g2d->dev);
@@ -724,20 +944,14 @@ static int g2d_check_reg_offset(struct device *dev,
        int i;
 
        for (i = 0; i < nr; i++) {
-               index = cmdlist->last - 2 * (i + 1);
+               struct g2d_buf_info *buf_info = &node->buf_info;
+               struct g2d_buf_desc *buf_desc;
+               enum g2d_reg_type reg_type;
+               unsigned long value;
 
-               if (for_addr) {
-                       /* check userptr buffer type. */
-                       reg_offset = (cmdlist->data[index] &
-                                       ~0x7fffffff) >> 31;
-                       if (reg_offset) {
-                               node->obj_type[i] = BUF_TYPE_USERPTR;
-                               cmdlist->data[index] &= ~G2D_BUF_USERPTR;
-                       }
-               }
+               index = cmdlist->last - 2 * (i + 1);
 
                reg_offset = cmdlist->data[index] & ~0xfffff000;
-
                if (reg_offset < G2D_VALID_START || reg_offset > G2D_VALID_END)
                        goto err;
                if (reg_offset % 4)
@@ -753,8 +967,60 @@ static int g2d_check_reg_offset(struct device *dev,
                        if (!for_addr)
                                goto err;
 
-                       if (node->obj_type[i] != BUF_TYPE_USERPTR)
-                               node->obj_type[i] = BUF_TYPE_GEM;
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       /* check userptr buffer type. */
+                       if ((cmdlist->data[index] & ~0x7fffffff) >> 31) {
+                               buf_info->types[reg_type] = BUF_TYPE_USERPTR;
+                               cmdlist->data[index] &= ~G2D_BUF_USERPTR;
+                       } else
+                               buf_info->types[reg_type] = BUF_TYPE_GEM;
+                       break;
+               case G2D_SRC_COLOR_MODE:
+               case G2D_DST_COLOR_MODE:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       value = cmdlist->data[index + 1];
+
+                       buf_desc->format = value & 0xf;
+                       break;
+               case G2D_SRC_LEFT_TOP:
+               case G2D_DST_LEFT_TOP:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       value = cmdlist->data[index + 1];
+
+                       buf_desc->left_x = value & 0x1fff;
+                       buf_desc->top_y = (value & 0x1fff0000) >> 16;
+                       break;
+               case G2D_SRC_RIGHT_BOTTOM:
+               case G2D_DST_RIGHT_BOTTOM:
+                       if (for_addr)
+                               goto err;
+
+                       reg_type = g2d_get_reg_type(reg_offset);
+                       if (reg_type == REG_TYPE_NONE)
+                               goto err;
+
+                       buf_desc = &buf_info->descs[reg_type];
+                       value = cmdlist->data[index + 1];
+
+                       buf_desc->right_x = value & 0x1fff;
+                       buf_desc->bottom_y = (value & 0x1fff0000) >> 16;
                        break;
                default:
                        if (for_addr)
@@ -860,9 +1126,23 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
        cmdlist->data[cmdlist->last++] = G2D_SRC_BASE_ADDR;
        cmdlist->data[cmdlist->last++] = 0;
 
+       /*
+        * 'LIST_HOLD' command should be set to the DMA_HOLD_CMD_REG
+        * and GCF bit should be set to INTEN register if user wants
+        * G2D interrupt event once current command list execution is
+        * finished.
+        * Otherwise only ACF bit should be set to INTEN register so
+        * that one interrupt is occured after all command lists
+        * have been completed.
+        */
        if (node->event) {
+               cmdlist->data[cmdlist->last++] = G2D_INTEN;
+               cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF | G2D_INTEN_GCF;
                cmdlist->data[cmdlist->last++] = G2D_DMA_HOLD_CMD;
                cmdlist->data[cmdlist->last++] = G2D_LIST_HOLD;
+       } else {
+               cmdlist->data[cmdlist->last++] = G2D_INTEN;
+               cmdlist->data[cmdlist->last++] = G2D_INTEN_ACF;
        }
 
        /* Check size of cmdlist: last 2 is about G2D_BITBLT_START */
@@ -887,7 +1167,7 @@ int exynos_g2d_set_cmdlist_ioctl(struct drm_device *drm_dev, void *data,
        if (ret < 0)
                goto err_free_event;
 
-       node->map_nr = req->cmd_buf_nr;
+       node->buf_info.map_nr = req->cmd_buf_nr;
        if (req->cmd_buf_nr) {
                struct drm_exynos_g2d_cmd *cmd_buf;
 
index 67e17ce..0e6fe00 100644 (file)
@@ -164,6 +164,27 @@ out:
        exynos_gem_obj = NULL;
 }
 
+unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
+                                               unsigned int gem_handle,
+                                               struct drm_file *file_priv)
+{
+       struct exynos_drm_gem_obj *exynos_gem_obj;
+       struct drm_gem_object *obj;
+
+       obj = drm_gem_object_lookup(dev, file_priv, gem_handle);
+       if (!obj) {
+               DRM_ERROR("failed to lookup gem object.\n");
+               return 0;
+       }
+
+       exynos_gem_obj = to_exynos_gem_obj(obj);
+
+       drm_gem_object_unreference_unlocked(obj);
+
+       return exynos_gem_obj->buffer->size;
+}
+
+
 struct exynos_drm_gem_obj *exynos_drm_gem_init(struct drm_device *dev,
                                                      unsigned long size)
 {
index 35ebac4..468766b 100644 (file)
@@ -130,6 +130,11 @@ int exynos_drm_gem_userptr_ioctl(struct drm_device *dev, void *data,
 int exynos_drm_gem_get_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file_priv);
 
+/* get buffer size to gem handle. */
+unsigned long exynos_drm_gem_get_size(struct drm_device *dev,
+                                               unsigned int gem_handle,
+                                               struct drm_file *file_priv);
+
 /* initialize gem object. */
 int exynos_drm_gem_init_object(struct drm_gem_object *obj);
 
index 13ccbd4..9504b0c 100644 (file)
@@ -117,13 +117,12 @@ static struct edid *vidi_get_edid(struct device *dev,
        }
 
        edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
-       edid = kzalloc(edid_len, GFP_KERNEL);
+       edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
        if (!edid) {
                DRM_DEBUG_KMS("failed to allocate edid\n");
                return ERR_PTR(-ENOMEM);
        }
 
-       memcpy(edid, ctx->raw_edid, edid_len);
        return edid;
 }
 
@@ -563,12 +562,11 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
                        return -EINVAL;
                }
                edid_len = (1 + raw_edid->extensions) * EDID_LENGTH;
-               ctx->raw_edid = kzalloc(edid_len, GFP_KERNEL);
+               ctx->raw_edid = kmemdup(raw_edid, edid_len, GFP_KERNEL);
                if (!ctx->raw_edid) {
                        DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
                        return -ENOMEM;
                }
-               memcpy(ctx->raw_edid, raw_edid, edid_len);
        } else {
                /*
                 * with connection = 0, free raw_edid
index e919aba..2f4f72f 100644 (file)
@@ -818,7 +818,7 @@ static void mixer_win_disable(void *ctx, int win)
        mixer_ctx->win_data[win].enabled = false;
 }
 
-int mixer_check_timing(void *ctx, struct fb_videomode *timing)
+static int mixer_check_timing(void *ctx, struct fb_videomode *timing)
 {
        struct mixer_context *mixer_ctx = ctx;
        u32 w, h;
index 0a8eceb..e9b5789 100644 (file)
@@ -125,6 +125,11 @@ MODULE_PARM_DESC(preliminary_hw_support,
                "Enable Haswell and ValleyView Support. "
                "(default: false)");
 
+int i915_disable_power_well __read_mostly = 0;
+module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
+MODULE_PARM_DESC(disable_power_well,
+                "Disable the power well when possible (default: false)");
+
 static struct drm_driver driver;
 extern int intel_agp_enabled;
 
index e95337c..01769e2 100644 (file)
@@ -1398,6 +1398,7 @@ extern int i915_enable_fbc __read_mostly;
 extern bool i915_enable_hangcheck __read_mostly;
 extern int i915_enable_ppgtt __read_mostly;
 extern unsigned int i915_preliminary_hw_support __read_mostly;
+extern int i915_disable_power_well __read_mostly;
 
 extern int i915_suspend(struct drm_device *dev, pm_message_t state);
 extern int i915_resume(struct drm_device *dev);
index 3b11ab0..9a48e1a 100644 (file)
@@ -57,7 +57,7 @@ eb_create(struct drm_i915_gem_execbuffer2 *args)
        if (eb == NULL) {
                int size = args->buffer_count;
                int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
-               BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head)));
+               BUILD_BUG_ON_NOT_POWER_OF_2(PAGE_SIZE / sizeof(struct hlist_head));
                while (count > 2*size)
                        count >>= 1;
                eb = kzalloc(count*sizeof(struct hlist_head) +
index 32a3693..1ce45a0 100644 (file)
@@ -45,6 +45,9 @@
 
 struct intel_crt {
        struct intel_encoder base;
+       /* DPMS state is stored in the connector, which we need in the
+        * encoder's enable/disable callbacks */
+       struct intel_connector *connector;
        bool force_hotplug_required;
        u32 adpa_reg;
 };
@@ -81,29 +84,6 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
        return true;
 }
 
-static void intel_disable_crt(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       u32 temp;
-
-       temp = I915_READ(crt->adpa_reg);
-       temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE;
-       temp &= ~ADPA_DAC_ENABLE;
-       I915_WRITE(crt->adpa_reg, temp);
-}
-
-static void intel_enable_crt(struct intel_encoder *encoder)
-{
-       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
-       struct intel_crt *crt = intel_encoder_to_crt(encoder);
-       u32 temp;
-
-       temp = I915_READ(crt->adpa_reg);
-       temp |= ADPA_DAC_ENABLE;
-       I915_WRITE(crt->adpa_reg, temp);
-}
-
 /* Note: The caller is required to filter out dpms modes not supported by the
  * platform. */
 static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -135,6 +115,19 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
        I915_WRITE(crt->adpa_reg, temp);
 }
 
+static void intel_disable_crt(struct intel_encoder *encoder)
+{
+       intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void intel_enable_crt(struct intel_encoder *encoder)
+{
+       struct intel_crt *crt = intel_encoder_to_crt(encoder);
+
+       intel_crt_set_dpms(encoder, crt->connector->base.dpms);
+}
+
+
 static void intel_crt_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_device *dev = connector->dev;
@@ -746,6 +739,7 @@ void intel_crt_init(struct drm_device *dev)
        }
 
        connector = &intel_connector->base;
+       crt->connector = intel_connector;
        drm_connector_init(dev, &intel_connector->base,
                           &intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
 
index 287b42c..b20d501 100644 (file)
@@ -5771,6 +5771,11 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
                num_connectors++;
        }
 
+       if (is_cpu_edp)
+               intel_crtc->cpu_transcoder = TRANSCODER_EDP;
+       else
+               intel_crtc->cpu_transcoder = pipe;
+
        /* We are not sure yet this won't happen. */
        WARN(!HAS_PCH_LPT(dev), "Unexpected PCH type %d\n",
             INTEL_PCH_TYPE(dev));
@@ -5837,11 +5842,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        int pipe = intel_crtc->pipe;
        int ret;
 
-       if (IS_HASWELL(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
-               intel_crtc->cpu_transcoder = TRANSCODER_EDP;
-       else
-               intel_crtc->cpu_transcoder = pipe;
-
        drm_vblank_pre_modeset(dev, pipe);
 
        ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
index d7d4afe..8fc93f9 100644 (file)
@@ -2559,12 +2559,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 {
        struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
        struct intel_dp *intel_dp = &intel_dig_port->dp;
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
        i2c_del_adapter(&intel_dp->adapter);
        drm_encoder_cleanup(encoder);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
+               mutex_lock(&dev->mode_config.mutex);
                ironlake_panel_vdd_off_sync(intel_dp);
+               mutex_unlock(&dev->mode_config.mutex);
        }
        kfree(intel_dig_port);
 }
index a3730e0..bee8cb6 100644 (file)
@@ -321,9 +321,6 @@ void intel_panel_enable_backlight(struct drm_device *dev,
        if (dev_priv->backlight_level == 0)
                dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
-       dev_priv->backlight_enabled = true;
-       intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
-
        if (INTEL_INFO(dev)->gen >= 4) {
                uint32_t reg, tmp;
 
@@ -359,12 +356,12 @@ void intel_panel_enable_backlight(struct drm_device *dev,
        }
 
 set_level:
-       /* Check the current backlight level and try to set again if it's zero.
-        * On some machines, BLC_PWM_CPU_CTL is cleared to zero automatically
-        * when BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1 are written.
+       /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
+        * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
+        * registers are set.
         */
-       if (!intel_panel_get_backlight(dev))
-               intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
+       dev_priv->backlight_enabled = true;
+       intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
 }
 
 static void intel_panel_init_backlight(struct drm_device *dev)
index a1794c6..adca007 100644 (file)
@@ -4079,6 +4079,9 @@ void intel_set_power_well(struct drm_device *dev, bool enable)
        if (!IS_HASWELL(dev))
                return;
 
+       if (!i915_disable_power_well && !enable)
+               return;
+
        tmp = I915_READ(HSW_PWR_WELL_DRIVER);
        is_enabled = tmp & HSW_PWR_WELL_STATE;
        enable_requested = tmp & HSW_PWR_WELL_ENABLE;
index e816f06..0e2c1a4 100644 (file)
@@ -248,6 +248,22 @@ nouveau_bios_shadow_pci(struct nouveau_bios *bios)
        }
 }
 
+static void
+nouveau_bios_shadow_platform(struct nouveau_bios *bios)
+{
+       struct pci_dev *pdev = nv_device(bios)->pdev;
+       size_t size;
+
+       void __iomem *rom = pci_platform_rom(pdev, &size);
+       if (rom && size) {
+               bios->data = kmalloc(size, GFP_KERNEL);
+               if (bios->data) {
+                       memcpy_fromio(bios->data, rom, size);
+                       bios->size = size;
+               }
+       }
+}
+
 static int
 nouveau_bios_score(struct nouveau_bios *bios, const bool writeable)
 {
@@ -288,6 +304,7 @@ nouveau_bios_shadow(struct nouveau_bios *bios)
                { "PROM", nouveau_bios_shadow_prom, false, 0, 0, NULL },
                { "ACPI", nouveau_bios_shadow_acpi, true, 0, 0, NULL },
                { "PCIROM", nouveau_bios_shadow_pci, true, 0, 0, NULL },
+               { "PLATFORM", nouveau_bios_shadow_platform, true, 0, 0, NULL },
                {}
        };
        struct methods *mthd, *best;
index 3b6dc88..5eb3e0d 100644 (file)
@@ -391,7 +391,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_device *device = nv_device(drm->device);
        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
-       struct nouveau_abi16_chan *chan, *temp;
+       struct nouveau_abi16_chan *chan = NULL, *temp;
        struct nouveau_abi16_ntfy *ntfy;
        struct nouveau_object *object;
        struct nv_dma_class args = {};
@@ -404,10 +404,11 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
        if (unlikely(nv_device(abi16->device)->card_type >= NV_C0))
                return nouveau_abi16_put(abi16, -EINVAL);
 
-       list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
-               if (chan->chan->handle == (NVDRM_CHAN | info->channel))
+       list_for_each_entry(temp, &abi16->channels, head) {
+               if (temp->chan->handle == (NVDRM_CHAN | info->channel)) {
+                       chan = temp;
                        break;
-               chan = NULL;
+               }
        }
 
        if (!chan)
@@ -459,17 +460,18 @@ nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
 {
        struct drm_nouveau_gpuobj_free *fini = data;
        struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev);
-       struct nouveau_abi16_chan *chan, *temp;
+       struct nouveau_abi16_chan *chan = NULL, *temp;
        struct nouveau_abi16_ntfy *ntfy;
        int ret;
 
        if (unlikely(!abi16))
                return -ENOMEM;
 
-       list_for_each_entry_safe(chan, temp, &abi16->channels, head) {
-               if (chan->chan->handle == (NVDRM_CHAN | fini->channel))
+       list_for_each_entry(temp, &abi16->channels, head) {
+               if (temp->chan->handle == (NVDRM_CHAN | fini->channel)) {
+                       chan = temp;
                        break;
-               chan = NULL;
+               }
        }
 
        if (!chan)
index d109936..c95decf 100644 (file)
@@ -71,12 +71,26 @@ module_param_named(modeset, nouveau_modeset, int, 0400);
 
 static struct drm_driver driver;
 
+static int
+nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
+{
+       struct nouveau_drm *drm =
+               container_of(event, struct nouveau_drm, vblank[head]);
+       drm_handle_vblank(drm->dev, head);
+       return NVKM_EVENT_KEEP;
+}
+
 static int
 nouveau_drm_vblank_enable(struct drm_device *dev, int head)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_disp *pdisp = nouveau_disp(drm->device);
-       nouveau_event_get(pdisp->vblank, head, &drm->vblank);
+
+       if (WARN_ON_ONCE(head > ARRAY_SIZE(drm->vblank)))
+               return -EIO;
+       WARN_ON_ONCE(drm->vblank[head].func);
+       drm->vblank[head].func = nouveau_drm_vblank_handler;
+       nouveau_event_get(pdisp->vblank, head, &drm->vblank[head]);
        return 0;
 }
 
@@ -85,16 +99,11 @@ nouveau_drm_vblank_disable(struct drm_device *dev, int head)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_disp *pdisp = nouveau_disp(drm->device);
-       nouveau_event_put(pdisp->vblank, head, &drm->vblank);
-}
-
-static int
-nouveau_drm_vblank_handler(struct nouveau_eventh *event, int head)
-{
-       struct nouveau_drm *drm =
-               container_of(event, struct nouveau_drm, vblank);
-       drm_handle_vblank(drm->dev, head);
-       return NVKM_EVENT_KEEP;
+       if (drm->vblank[head].func)
+               nouveau_event_put(pdisp->vblank, head, &drm->vblank[head]);
+       else
+               WARN_ON_ONCE(1);
+       drm->vblank[head].func = NULL;
 }
 
 static u64
@@ -292,7 +301,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 
        dev->dev_private = drm;
        drm->dev = dev;
-       drm->vblank.func = nouveau_drm_vblank_handler;
 
        INIT_LIST_HEAD(&drm->clients);
        spin_lock_init(&drm->tile.lock);
index b25df37..9c39baf 100644 (file)
@@ -113,7 +113,7 @@ struct nouveau_drm {
        struct nvbios vbios;
        struct nouveau_display *display;
        struct backlight_device *backlight;
-       struct nouveau_eventh vblank;
+       struct nouveau_eventh vblank[4];
 
        /* power management */
        struct nouveau_pm *pm;
index b801591..fa3c56f 100644 (file)
@@ -99,6 +99,29 @@ static bool radeon_read_bios(struct radeon_device *rdev)
        return true;
 }
 
+static bool radeon_read_platform_bios(struct radeon_device *rdev)
+{
+       uint8_t __iomem *bios;
+       size_t size;
+
+       rdev->bios = NULL;
+
+       bios = pci_platform_rom(rdev->pdev, &size);
+       if (!bios) {
+               return false;
+       }
+
+       if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+               return false;
+       }
+       rdev->bios = kmemdup(bios, size, GFP_KERNEL);
+       if (rdev->bios == NULL) {
+               return false;
+       }
+
+       return true;
+}
+
 #ifdef CONFIG_ACPI
 /* ATRM is used to get the BIOS on the discrete cards in
  * dual-gpu systems.
@@ -620,6 +643,9 @@ bool radeon_get_bios(struct radeon_device *rdev)
        if (r == false) {
                r = radeon_read_disabled_bios(rdev);
        }
+       if (r == false) {
+               r = radeon_read_platform_bios(rdev);
+       }
        if (r == false || rdev->bios == NULL) {
                DRM_ERROR("Unable to locate a BIOS ROM\n");
                rdev->bios = NULL;
index 512b01c..aa341d1 100644 (file)
@@ -2077,7 +2077,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_MASTERKIT, USB_DEVICE_ID_MASTERKIT_MA901RADIO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
@@ -2244,6 +2243,18 @@ bool hid_ignore(struct hid_device *hdev)
                     hdev->product <= USB_DEVICE_ID_VELLEMAN_K8061_LAST))
                        return true;
                break;
+       case USB_VENDOR_ID_ATMEL_V_USB:
+               /* Masterkit MA901 usb radio based on Atmel tiny85 chip and
+                * it has the same USB ID as many Atmel V-USB devices. This
+                * usb radio is handled by radio-ma901.c driver so we want
+                * ignore the hid. Check the name, bus, product and ignore
+                * if we have MA901 usb radio.
+                */
+               if (hdev->product == USB_DEVICE_ID_ATMEL_V_USB &&
+                       hdev->bus == BUS_USB &&
+                       strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0)
+                       return true;
+               break;
        }
 
        if (hdev->type == HID_TYPE_USBMOUSE &&
index 92e47e5..5309fd5 100644 (file)
 #define USB_VENDOR_ID_ATMEL            0x03eb
 #define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
 #define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER      0x2118
+#define USB_VENDOR_ID_ATMEL_V_USB      0x16c0
+#define USB_DEVICE_ID_ATMEL_V_USB      0x05df
 
 #define USB_VENDOR_ID_AUREAL           0x0755
 #define USB_DEVICE_ID_AUREAL_W01RN     0x2626
 #define USB_VENDOR_ID_MADCATZ          0x0738
 #define USB_DEVICE_ID_MADCATZ_BEATPAD  0x4540
 
-#define USB_VENDOR_ID_MASTERKIT                        0x16c0
-#define USB_DEVICE_ID_MASTERKIT_MA901RADIO     0x05df
-
 #define USB_VENDOR_ID_MCC              0x09db
 #define USB_DEVICE_ID_MCC_PMD1024LS    0x0076
 #define USB_DEVICE_ID_MCC_PMD1208LS    0x007a
 #define USB_VENDOR_ID_MONTEREY         0x0566
 #define USB_DEVICE_ID_GENIUS_KB29E     0x3004
 
+#define USB_VENDOR_ID_MSI              0x1770
+#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL     0xff00
+
 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
 #define USB_DEVICE_ID_N_S_HARMONY      0xc359
 
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001                0x3001
 #define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008                0x3008
 
+#define USB_VENDOR_ID_REALTEK          0x0bda
+#define USB_DEVICE_ID_REALTEK_READER   0x0152
+
 #define USB_VENDOR_ID_ROCCAT           0x1e7d
 #define USB_DEVICE_ID_ROCCAT_ARVO      0x30d4
 #define USB_DEVICE_ID_ROCCAT_ISKU      0x319c
index f7f113b..a8ce442 100644 (file)
@@ -462,6 +462,21 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
        return 0;
 }
 
+static void magicmouse_input_configured(struct hid_device *hdev,
+               struct hid_input *hi)
+
+{
+       struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+       int ret = magicmouse_setup_input(msc->input, hdev);
+       if (ret) {
+               hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
+               /* clean msc->input to notify probe() of the failure */
+               msc->input = NULL;
+       }
+}
+
+
 static int magicmouse_probe(struct hid_device *hdev,
        const struct hid_device_id *id)
 {
@@ -493,15 +508,10 @@ static int magicmouse_probe(struct hid_device *hdev,
                goto err_free;
        }
 
-       /* We do this after hid-input is done parsing reports so that
-        * hid-input uses the most natural button and axis IDs.
-        */
-       if (msc->input) {
-               ret = magicmouse_setup_input(msc->input, hdev);
-               if (ret) {
-                       hid_err(hdev, "magicmouse setup input failed (%d)\n", ret);
-                       goto err_stop_hw;
-               }
+       if (!msc->input) {
+               hid_err(hdev, "magicmouse input not registered\n");
+               ret = -ENOMEM;
+               goto err_stop_hw;
        }
 
        if (id->product == USB_DEVICE_ID_APPLE_MAGICMOUSE)
@@ -568,6 +578,7 @@ static struct hid_driver magicmouse_driver = {
        .remove = magicmouse_remove,
        .raw_event = magicmouse_raw_event,
        .input_mapping = magicmouse_input_mapping,
+       .input_configured = magicmouse_input_configured,
 };
 module_hid_driver(magicmouse_driver);
 
index 7a1ebb8..82e9211 100644 (file)
@@ -621,6 +621,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 {
        struct mt_device *td = hid_get_drvdata(hid);
        __s32 quirks = td->mtclass.quirks;
+       struct input_dev *input = field->hidinput->input;
 
        if (hid->claimed & HID_CLAIMED_INPUT) {
                switch (usage->hid) {
@@ -670,13 +671,16 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
                        break;
 
                default:
+                       if (usage->type)
+                               input_event(input, usage->type, usage->code,
+                                               value);
                        return;
                }
 
                if (usage->usage_index + 1 == field->report_count) {
                        /* we only take into account the last report. */
                        if (usage->hid == td->last_slot_field)
-                               mt_complete_slot(td, field->hidinput->input);
+                               mt_complete_slot(td, input);
 
                        if (field->index == td->last_field_index
                                && td->num_received >= td->num_expected)
index e0e6abf..19b8360 100644 (file)
@@ -73,6 +73,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
@@ -80,6 +81,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008, HID_QUIRK_NOGET },
+       { USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
index 0ceb6e1..e3085c4 100644 (file)
@@ -182,7 +182,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
        adap->algo = &i2c_dw_algo;
        adap->dev.parent = &pdev->dev;
        adap->dev.of_node = pdev->dev.of_node;
-       ACPI_HANDLE_SET(&adap->dev, ACPI_HANDLE(&pdev->dev));
 
        r = i2c_add_numbered_adapter(adap);
        if (r) {
index 17ba4f8..70b1808 100644 (file)
@@ -186,8 +186,10 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
        wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
                                          wq->rq.memsize, &(wq->rq.dma_addr),
                                          GFP_KERNEL);
-       if (!wq->rq.queue)
+       if (!wq->rq.queue) {
+               ret = -ENOMEM;
                goto free_sq;
+       }
        PDBG("%s sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
                __func__, wq->sq.queue,
                (unsigned long long)virt_to_phys(wq->sq.queue),
index 439c35d..ea93870 100644 (file)
@@ -620,7 +620,7 @@ void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data,
                goto bail;
        }
 
-       opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
+       opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0x7f;
        dev->opstats[opcode].n_bytes += tlen;
        dev->opstats[opcode].n_packets++;
 
index 8349f9c..1e603a3 100644 (file)
@@ -1,7 +1,7 @@
 config INFINIBAND_QIB
-       tristate "QLogic PCIe HCA support"
+       tristate "Intel PCIe HCA support"
        depends on 64BIT
        ---help---
-       This is a low-level driver for QLogic PCIe QLE InfiniBand host
-       channel adapters.  This driver does not support the QLogic
+       This is a low-level driver for Intel PCIe QLE InfiniBand host
+       channel adapters.  This driver does not support the Intel
        HyperTransport card (model QHT7140).
index 5423edc..2160924 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2013 Intel Corporation. All rights reserved.
  * Copyright (c) 2006, 2007, 2008, 2009 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -63,8 +64,8 @@ MODULE_PARM_DESC(compat_ddr_negotiate,
                 "Attempt pre-IBTA 1.2 DDR speed negotiation");
 
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("QLogic <support@qlogic.com>");
-MODULE_DESCRIPTION("QLogic IB driver");
+MODULE_AUTHOR("Intel <ibsupport@intel.com>");
+MODULE_DESCRIPTION("Intel IB driver");
 MODULE_VERSION(QIB_DRIVER_VERSION);
 
 /*
index a099ac1..0232ae5 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2013 Intel Corporation. All rights reserved.
  * Copyright (c) 2006, 2007, 2008, 2009, 2010 QLogic Corporation.
  * All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
@@ -51,7 +52,7 @@ static u32 qib_6120_iblink_state(u64);
 
 /*
  * This file contains all the chip-specific register information and
- * access functions for the QLogic QLogic_IB PCI-Express chip.
+ * access functions for the Intel Intel_IB PCI-Express chip.
  *
  */
 
index 50e33aa..173f805 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation.  All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -1138,7 +1138,7 @@ void qib_disable_after_error(struct qib_devdata *dd)
 static void qib_remove_one(struct pci_dev *);
 static int qib_init_one(struct pci_dev *, const struct pci_device_id *);
 
-#define DRIVER_LOAD_MSG "QLogic " QIB_DRV_NAME " loaded: "
+#define DRIVER_LOAD_MSG "Intel " QIB_DRV_NAME " loaded: "
 #define PFX QIB_DRV_NAME ": "
 
 static DEFINE_PCI_DEVICE_TABLE(qib_pci_tbl) = {
@@ -1355,7 +1355,7 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                dd = qib_init_iba6120_funcs(pdev, ent);
 #else
                qib_early_err(&pdev->dev,
-                       "QLogic PCIE device 0x%x cannot work if CONFIG_PCI_MSI is not enabled\n",
+                       "Intel PCIE device 0x%x cannot work if CONFIG_PCI_MSI is not enabled\n",
                        ent->device);
                dd = ERR_PTR(-ENODEV);
 #endif
@@ -1371,7 +1371,7 @@ static int qib_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        default:
                qib_early_err(&pdev->dev,
-                       "Failing on unknown QLogic deviceid 0x%x\n",
+                       "Failing on unknown Intel deviceid 0x%x\n",
                        ent->device);
                ret = -ENODEV;
        }
index 50a8a0d..911205d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Intel Corporation. All rights reserved.
+ * Copyright (c) 2013 Intel Corporation. All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
  *
index ba51a47..7c0ab16 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Intel Corporation.  All rights reserved.
+ * Copyright (c) 2012, 2013 Intel Corporation.  All rights reserved.
  * Copyright (c) 2006 - 2012 QLogic Corporation. All rights reserved.
  * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
  *
@@ -2224,7 +2224,7 @@ int qib_register_ib_device(struct qib_devdata *dd)
        ibdev->dma_ops = &qib_dma_mapping_ops;
 
        snprintf(ibdev->node_desc, sizeof(ibdev->node_desc),
-                "QLogic Infiniband HCA %s", init_utsname()->nodename);
+                "Intel Infiniband HCA %s", init_utsname()->nodename);
 
        ret = ib_register_device(ibdev, qib_create_port_files);
        if (ret)
index 67b0c1d..1ef880d 100644 (file)
@@ -758,9 +758,13 @@ void ipoib_cm_send(struct net_device *dev, struct sk_buff *skb, struct ipoib_cm_
                if (++priv->tx_outstanding == ipoib_sendq_size) {
                        ipoib_dbg(priv, "TX ring 0x%x full, stopping kernel net queue\n",
                                  tx->qp->qp_num);
-                       if (ib_req_notify_cq(priv->send_cq, IB_CQ_NEXT_COMP))
-                               ipoib_warn(priv, "request notify on send CQ failed\n");
                        netif_stop_queue(dev);
+                       rc = ib_req_notify_cq(priv->send_cq,
+                               IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS);
+                       if (rc < 0)
+                               ipoib_warn(priv, "request notify on send CQ failed\n");
+                       else if (rc)
+                               ipoib_send_comp_handler(priv->send_cq, dev);
                }
        }
 }
index 5c514d0..c332fb9 100644 (file)
@@ -130,7 +130,7 @@ config IRQ_REMAP
 # OMAP IOMMU support
 config OMAP_IOMMU
        bool "OMAP IOMMU Support"
-       depends on ARCH_OMAP
+       depends on ARCH_OMAP2PLUS
        select IOMMU_API
 
 config OMAP_IOVMM
index 98f555d..b287ca3 100644 (file)
@@ -2466,18 +2466,16 @@ static int device_change_notifier(struct notifier_block *nb,
 
                /* allocate a protection domain if a device is added */
                dma_domain = find_protection_domain(devid);
-               if (dma_domain)
-                       goto out;
-               dma_domain = dma_ops_domain_alloc();
-               if (!dma_domain)
-                       goto out;
-               dma_domain->target_dev = devid;
-
-               spin_lock_irqsave(&iommu_pd_list_lock, flags);
-               list_add_tail(&dma_domain->list, &iommu_pd_list);
-               spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
-
-               dev_data = get_dev_data(dev);
+               if (!dma_domain) {
+                       dma_domain = dma_ops_domain_alloc();
+                       if (!dma_domain)
+                               goto out;
+                       dma_domain->target_dev = devid;
+
+                       spin_lock_irqsave(&iommu_pd_list_lock, flags);
+                       list_add_tail(&dma_domain->list, &iommu_pd_list);
+                       spin_unlock_irqrestore(&iommu_pd_list_lock, flags);
+               }
 
                dev->archdata.dma_ops = &amd_iommu_dma_ops;
 
index b6ecddb..e3c2d74 100644 (file)
@@ -980,7 +980,7 @@ static void __init free_iommu_all(void)
  *     BIOS should disable L2B micellaneous clock gating by setting
  *     L2_L2B_CK_GATE_CONTROL[CKGateL2BMiscDisable](D0F2xF4_x90[2]) = 1b
  */
-static void __init amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
+static void amd_iommu_erratum_746_workaround(struct amd_iommu *iommu)
 {
        u32 value;
 
index d56f8c1..7c11ff3 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/cpumask.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/cpumask.h>
 #include <linux/errno.h>
 #include <linux/msi.h>
 #include <linux/irq.h>
index 66120bd..1074409 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "dm.h"
 #include "dm-bio-prison.h"
+#include "dm-bio-record.h"
 #include "dm-cache-metadata.h"
 
 #include <linux/dm-io.h>
@@ -201,10 +202,15 @@ struct per_bio_data {
        unsigned req_nr:2;
        struct dm_deferred_entry *all_io_entry;
 
-       /* writethrough fields */
+       /*
+        * writethrough fields.  These MUST remain at the end of this
+        * structure and the 'cache' member must be the first as it
+        * is used to determine the offsetof the writethrough fields.
+        */
        struct cache *cache;
        dm_cblock_t cblock;
        bio_end_io_t *saved_bi_end_io;
+       struct dm_bio_details bio_details;
 };
 
 struct dm_cache_migration {
@@ -513,16 +519,28 @@ static void save_stats(struct cache *cache)
 /*----------------------------------------------------------------
  * Per bio data
  *--------------------------------------------------------------*/
-static struct per_bio_data *get_per_bio_data(struct bio *bio)
+
+/*
+ * If using writeback, leave out struct per_bio_data's writethrough fields.
+ */
+#define PB_DATA_SIZE_WB (offsetof(struct per_bio_data, cache))
+#define PB_DATA_SIZE_WT (sizeof(struct per_bio_data))
+
+static size_t get_per_bio_data_size(struct cache *cache)
+{
+       return cache->features.write_through ? PB_DATA_SIZE_WT : PB_DATA_SIZE_WB;
+}
+
+static struct per_bio_data *get_per_bio_data(struct bio *bio, size_t data_size)
 {
-       struct per_bio_data *pb = dm_per_bio_data(bio, sizeof(struct per_bio_data));
+       struct per_bio_data *pb = dm_per_bio_data(bio, data_size);
        BUG_ON(!pb);
        return pb;
 }
 
-static struct per_bio_data *init_per_bio_data(struct bio *bio)
+static struct per_bio_data *init_per_bio_data(struct bio *bio, size_t data_size)
 {
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       struct per_bio_data *pb = get_per_bio_data(bio, data_size);
 
        pb->tick = false;
        pb->req_nr = dm_bio_get_target_bio_nr(bio);
@@ -556,7 +574,8 @@ static void remap_to_cache(struct cache *cache, struct bio *bio,
 static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio)
 {
        unsigned long flags;
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       size_t pb_data_size = get_per_bio_data_size(cache);
+       struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
 
        spin_lock_irqsave(&cache->lock, flags);
        if (cache->need_tick_bio &&
@@ -635,7 +654,7 @@ static void defer_writethrough_bio(struct cache *cache, struct bio *bio)
 
 static void writethrough_endio(struct bio *bio, int err)
 {
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT);
        bio->bi_end_io = pb->saved_bi_end_io;
 
        if (err) {
@@ -643,6 +662,7 @@ static void writethrough_endio(struct bio *bio, int err)
                return;
        }
 
+       dm_bio_restore(&pb->bio_details, bio);
        remap_to_cache(pb->cache, bio, pb->cblock);
 
        /*
@@ -662,11 +682,12 @@ static void writethrough_endio(struct bio *bio, int err)
 static void remap_to_origin_then_cache(struct cache *cache, struct bio *bio,
                                       dm_oblock_t oblock, dm_cblock_t cblock)
 {
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       struct per_bio_data *pb = get_per_bio_data(bio, PB_DATA_SIZE_WT);
 
        pb->cache = cache;
        pb->cblock = cblock;
        pb->saved_bi_end_io = bio->bi_end_io;
+       dm_bio_record(&pb->bio_details, bio);
        bio->bi_end_io = writethrough_endio;
 
        remap_to_origin_clear_discard(pb->cache, bio, oblock);
@@ -1035,7 +1056,8 @@ static void defer_bio(struct cache *cache, struct bio *bio)
 
 static void process_flush_bio(struct cache *cache, struct bio *bio)
 {
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       size_t pb_data_size = get_per_bio_data_size(cache);
+       struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
 
        BUG_ON(bio->bi_size);
        if (!pb->req_nr)
@@ -1107,7 +1129,8 @@ static void process_bio(struct cache *cache, struct prealloc *structs,
        dm_oblock_t block = get_bio_block(cache, bio);
        struct dm_bio_prison_cell *cell_prealloc, *old_ocell, *new_ocell;
        struct policy_result lookup_result;
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       size_t pb_data_size = get_per_bio_data_size(cache);
+       struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
        bool discarded_block = is_discarded_oblock(cache, block);
        bool can_migrate = discarded_block || spare_migration_bandwidth(cache);
 
@@ -1881,7 +1904,6 @@ static int cache_create(struct cache_args *ca, struct cache **result)
 
        cache->ti = ca->ti;
        ti->private = cache;
-       ti->per_bio_data_size = sizeof(struct per_bio_data);
        ti->num_flush_bios = 2;
        ti->flush_supported = true;
 
@@ -1890,6 +1912,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
        ti->discard_zeroes_data_unsupported = true;
 
        memcpy(&cache->features, &ca->features, sizeof(cache->features));
+       ti->per_bio_data_size = get_per_bio_data_size(cache);
 
        cache->callbacks.congested_fn = cache_is_congested;
        dm_table_add_target_callbacks(ti->table, &cache->callbacks);
@@ -2092,6 +2115,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
 
        int r;
        dm_oblock_t block = get_bio_block(cache, bio);
+       size_t pb_data_size = get_per_bio_data_size(cache);
        bool can_migrate = false;
        bool discarded_block;
        struct dm_bio_prison_cell *cell;
@@ -2108,7 +2132,7 @@ static int cache_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
        }
 
-       pb = init_per_bio_data(bio);
+       pb = init_per_bio_data(bio, pb_data_size);
 
        if (bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD)) {
                defer_bio(cache, bio);
@@ -2193,7 +2217,8 @@ static int cache_end_io(struct dm_target *ti, struct bio *bio, int error)
 {
        struct cache *cache = ti->private;
        unsigned long flags;
-       struct per_bio_data *pb = get_per_bio_data(bio);
+       size_t pb_data_size = get_per_bio_data_size(cache);
+       struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
 
        if (pb->tick) {
                policy_tick(cache->policy);
index d4e7567..0b899cb 100644 (file)
@@ -724,7 +724,7 @@ static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
        if (enable) {
                if (is_code(code, M5MOLS_RESTYPE_MONITOR))
                        ret = m5mols_start_monitor(info);
-               if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
+               else if (is_code(code, M5MOLS_RESTYPE_CAPTURE))
                        ret = m5mols_start_capture(info);
                else
                        ret = -EINVAL;
index ccd18e4..54579e4 100644 (file)
@@ -250,17 +250,19 @@ static u8 SRAM_Table[][60] =
    vdelay      start of active video in 2 * field lines relative to
                trailing edge of /VRESET pulse (VDELAY register).
    sheight     height of active video in 2 * field lines.
+   extraheight Added to sheight for cropcap.bounds.height only
    videostart0 ITU-R frame line number of the line corresponding
                to vdelay in the first field. */
 #define CROPCAP(minhdelayx1, hdelayx1, swidth, totalwidth, sqwidth,     \
-               vdelay, sheight, videostart0)                            \
+               vdelay, sheight, extraheight, videostart0)               \
        .cropcap.bounds.left = minhdelayx1,                              \
        /* * 2 because vertically we count field lines times two, */     \
        /* e.g. 23 * 2 to 23 * 2 + 576 in PAL-BGHI defrect. */           \
        .cropcap.bounds.top = (videostart0) * 2 - (vdelay) + MIN_VDELAY, \
        /* 4 is a safety margin at the end of the line. */               \
        .cropcap.bounds.width = (totalwidth) - (minhdelayx1) - 4,        \
-       .cropcap.bounds.height = (sheight) + (vdelay) - MIN_VDELAY,      \
+       .cropcap.bounds.height = (sheight) + (extraheight) + (vdelay) -  \
+                                MIN_VDELAY,                             \
        .cropcap.defrect.left = hdelayx1,                                \
        .cropcap.defrect.top = (videostart0) * 2,                        \
        .cropcap.defrect.width = swidth,                                 \
@@ -301,9 +303,10 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* totalwidth */ 1135,
                        /* sqwidth */ 944,
                        /* vdelay */ 0x20,
-               /* bt878 (and bt848?) can capture another
-                  line below active video. */
-                       /* sheight */ (576 + 2) + 0x20 - 2,
+                       /* sheight */ 576,
+                       /* bt878 (and bt848?) can capture another
+                          line below active video. */
+                       /* extraheight */ 2,
                        /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR,
@@ -330,6 +333,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 780,
                        /* vdelay */ 0x1a,
                        /* sheight */ 480,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_SECAM,
@@ -355,6 +359,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 944,
                        /* vdelay */ 0x20,
                        /* sheight */ 576,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_PAL_Nc,
@@ -380,6 +385,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 780,
                        /* vdelay */ 0x1a,
                        /* sheight */ 576,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_PAL_M,
@@ -405,6 +411,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 780,
                        /* vdelay */ 0x1a,
                        /* sheight */ 480,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_PAL_N,
@@ -430,6 +437,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 944,
                        /* vdelay */ 0x20,
                        /* sheight */ 576,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        },{
                .v4l2_id        = V4L2_STD_NTSC_M_JP,
@@ -455,6 +463,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 780,
                        /* vdelay */ 0x16,
                        /* sheight */ 480,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        },{
                /* that one hopefully works with the strange timing
@@ -484,6 +493,7 @@ const struct bttv_tvnorm bttv_tvnorms[] = {
                        /* sqwidth */ 944,
                        /* vdelay */ 0x1a,
                        /* sheight */ 480,
+                       /* extraheight */ 0,
                        /* videostart0 */ 23)
        }
 };
index 05d7b63..a0639e7 100644 (file)
@@ -204,7 +204,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
 
 config VIDEO_SH_VEU
        tristate "SuperH VEU mem2mem video processing driver"
-       depends on VIDEO_DEV && VIDEO_V4L2
+       depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
index 82d9f6a..33b5ffc 100644 (file)
@@ -1054,16 +1054,18 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc)
 
 static int gsc_m2m_resume(struct gsc_dev *gsc)
 {
+       struct gsc_ctx *ctx;
        unsigned long flags;
 
        spin_lock_irqsave(&gsc->slock, flags);
        /* Clear for full H/W setup in first run after resume */
+       ctx = gsc->m2m.ctx;
        gsc->m2m.ctx = NULL;
        spin_unlock_irqrestore(&gsc->slock, flags);
 
        if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state))
-               gsc_m2m_job_finish(gsc->m2m.ctx,
-                                   VB2_BUF_STATE_ERROR);
+               gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
        return 0;
 }
 
@@ -1204,7 +1206,7 @@ static int gsc_resume(struct device *dev)
        /* Do not resume if the device was idle before system suspend */
        spin_lock_irqsave(&gsc->slock, flags);
        if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) ||
-           !gsc_m2m_active(gsc)) {
+           !gsc_m2m_opened(gsc)) {
                spin_unlock_irqrestore(&gsc->slock, flags);
                return 0;
        }
index e3916bd..0f513dd 100644 (file)
@@ -850,16 +850,18 @@ static int fimc_m2m_suspend(struct fimc_dev *fimc)
 
 static int fimc_m2m_resume(struct fimc_dev *fimc)
 {
+       struct fimc_ctx *ctx;
        unsigned long flags;
 
        spin_lock_irqsave(&fimc->slock, flags);
        /* Clear for full H/W setup in first run after resume */
+       ctx = fimc->m2m.ctx;
        fimc->m2m.ctx = NULL;
        spin_unlock_irqrestore(&fimc->slock, flags);
 
        if (test_and_clear_bit(ST_M2M_SUSPENDED, &fimc->state))
-               fimc_m2m_job_finish(fimc->m2m.ctx,
-                                   VB2_BUF_STATE_ERROR);
+               fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
+
        return 0;
 }
 
index f0af075..ac9663c 100644 (file)
@@ -128,10 +128,10 @@ static const u32 src_pixfmt_map[8][3] = {
 void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
 {
        enum v4l2_mbus_pixelcode pixelcode = dev->fmt->mbus_code;
-       unsigned int i = ARRAY_SIZE(src_pixfmt_map);
+       int i = ARRAY_SIZE(src_pixfmt_map);
        u32 cfg;
 
-       while (i-- >= 0) {
+       while (--i >= 0) {
                if (src_pixfmt_map[i][0] == pixelcode)
                        break;
        }
@@ -224,9 +224,9 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
                { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
        };
        u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
-       unsigned int i = ARRAY_SIZE(pixcode);
+       int i = ARRAY_SIZE(pixcode);
 
-       while (i-- >= 0)
+       while (--i >= 0)
                if (pixcode[i][0] == dev->fmt->mbus_code)
                        break;
        cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
index bfc4206..bbc35de 100644 (file)
@@ -1408,6 +1408,7 @@ static const struct v4l2_ctrl_config fimc_lite_ctrl = {
        .id     = V4L2_CTRL_CLASS_USER | 0x1001,
        .type   = V4L2_CTRL_TYPE_BOOLEAN,
        .name   = "Test Pattern 640x480",
+       .step   = 1,
 };
 
 static int fimc_lite_create_capture_subdev(struct fimc_lite *fimc)
index a17fcb2..cd38d70 100644 (file)
@@ -827,7 +827,7 @@ static int fimc_md_link_notify(struct media_pad *source,
        struct fimc_pipeline *pipeline;
        struct v4l2_subdev *sd;
        struct mutex *lock;
-       int ret = 0;
+       int i, ret = 0;
        int ref_count;
 
        if (media_entity_type(sink->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
@@ -854,29 +854,28 @@ static int fimc_md_link_notify(struct media_pad *source,
                return 0;
        }
 
+       mutex_lock(lock);
+       ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
+
        if (!(flags & MEDIA_LNK_FL_ENABLED)) {
-               int i;
-               mutex_lock(lock);
-               ret = __fimc_pipeline_close(pipeline);
+               if (ref_count > 0) {
+                       ret = __fimc_pipeline_close(pipeline);
+                       if (!ret && fimc)
+                               fimc_ctrls_delete(fimc->vid_cap.ctx);
+               }
                for (i = 0; i < IDX_MAX; i++)
                        pipeline->subdevs[i] = NULL;
-               if (fimc)
-                       fimc_ctrls_delete(fimc->vid_cap.ctx);
-               mutex_unlock(lock);
-               return ret;
+       } else if (ref_count > 0) {
+               /*
+                * Link activation. Enable power of pipeline elements only if
+                * the pipeline is already in use, i.e. its video node is open.
+                * Recreate the controls destroyed during the link deactivation.
+                */
+               ret = __fimc_pipeline_open(pipeline,
+                                          source->entity, true);
+               if (!ret && fimc)
+                       ret = fimc_capture_ctrls_create(fimc);
        }
-       /*
-        * Link activation. Enable power of pipeline elements only if the
-        * pipeline is already in use, i.e. its video node is opened.
-        * Recreate the controls destroyed during the link deactivation.
-        */
-       mutex_lock(lock);
-
-       ref_count = fimc ? fimc->vid_cap.refcnt : fimc_lite->ref_count;
-       if (ref_count > 0)
-               ret = __fimc_pipeline_open(pipeline, source->entity, true);
-       if (!ret && fimc)
-               ret = fimc_capture_ctrls_create(fimc);
 
        mutex_unlock(lock);
        return ret ? -EPIPE : ret;
index e84703c..1cb6d57 100644 (file)
@@ -276,7 +276,7 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
        unsigned int frame_type;
 
        dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
-       frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev);
+       frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_disp_frame_type, ctx);
 
        /* If frame is same as previous then skip and do not dequeue */
        if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
index 2356fd5..4f6b553 100644 (file)
@@ -232,6 +232,7 @@ static struct mfc_control controls[] = {
                .minimum = 0,
                .maximum = 1,
                .default_value = 0,
+               .step = 1,
                .menu_skip_mask = 0,
        },
        {
index c61f590..348dafc 100644 (file)
@@ -347,9 +347,20 @@ static void usb_ma901radio_release(struct v4l2_device *v4l2_dev)
 static int usb_ma901radio_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
 {
+       struct usb_device *dev = interface_to_usbdev(intf);
        struct ma901radio_device *radio;
        int retval = 0;
 
+       /* Masterkit MA901 usb radio has the same USB ID as many others
+        * Atmel V-USB devices. Let's make additional checks to be sure
+        * that this is our device.
+        */
+
+       if (dev->product && dev->manufacturer &&
+               (strncmp(dev->product, "MA901", 5) != 0
+               || strncmp(dev->manufacturer, "www.masterkit.ru", 16) != 0))
+               return -ENODEV;
+
        radio = kzalloc(sizeof(struct ma901radio_device), GFP_KERNEL);
        if (!radio) {
                dev_err(&intf->dev, "kzalloc for ma901radio_device failed\n");
index 19f3563..5a79c33 100644 (file)
@@ -291,7 +291,7 @@ config IR_TTUSBIR
 
 config IR_RX51
        tristate "Nokia N900 IR transmitter diode"
-       depends on OMAP_DM_TIMER && LIRC && !ARCH_MULTIPLATFORM
+       depends on OMAP_DM_TIMER && ARCH_OMAP2PLUS && LIRC && !ARCH_MULTIPLATFORM
        ---help---
           Say Y or M here if you want to enable support for the IR
           transmitter diode built in the Nokia N900 (RX51) device.
index a9d3552..768aaf6 100644 (file)
@@ -10,7 +10,7 @@ ifeq ($(CONFIG_COMPAT),y)
   videodev-objs += v4l2-compat-ioctl32.o
 endif
 
-obj-$(CONFIG_VIDEO_DEV) += videodev.o
+obj-$(CONFIG_VIDEO_V4L2) += videodev.o
 obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o
 obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
 
index a433f58..7d01069 100644 (file)
@@ -290,12 +290,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000176, 0x0000 },   /* R374   - FLL1 Control 6 */ 
        { 0x00000177, 0x0181 },   /* R375   - FLL1 Loop Filter Test 1 */ 
        { 0x00000178, 0x0000 },   /* R376   - FLL1 NCO Test 0 */
+       { 0x00000179, 0x0000 },   /* R377   - FLL1 Control 7 */
        { 0x00000181, 0x0000 },   /* R385   - FLL1 Synchroniser 1 */ 
        { 0x00000182, 0x0000 },   /* R386   - FLL1 Synchroniser 2 */ 
        { 0x00000183, 0x0000 },   /* R387   - FLL1 Synchroniser 3 */ 
        { 0x00000184, 0x0000 },   /* R388   - FLL1 Synchroniser 4 */ 
        { 0x00000185, 0x0000 },   /* R389   - FLL1 Synchroniser 5 */ 
        { 0x00000186, 0x0000 },   /* R390   - FLL1 Synchroniser 6 */ 
+       { 0x00000187, 0x0001 },   /* R391   - FLL1 Synchroniser 7 */
        { 0x00000189, 0x0000 },   /* R393   - FLL1 Spread Spectrum */ 
        { 0x0000018A, 0x0004 },   /* R394   - FLL1 GPIO Clock */ 
        { 0x00000191, 0x0000 },   /* R401   - FLL2 Control 1 */ 
@@ -306,12 +308,14 @@ static const struct reg_default wm5102_reg_default[] = {
        { 0x00000196, 0x0000 },   /* R406   - FLL2 Control 6 */ 
        { 0x00000197, 0x0000 },   /* R407   - FLL2 Loop Filter Test 1 */ 
        { 0x00000198, 0x0000 },   /* R408   - FLL2 NCO Test 0 */
+       { 0x00000199, 0x0000 },   /* R409   - FLL2 Control 7 */
        { 0x000001A1, 0x0000 },   /* R417   - FLL2 Synchroniser 1 */ 
        { 0x000001A2, 0x0000 },   /* R418   - FLL2 Synchroniser 2 */ 
        { 0x000001A3, 0x0000 },   /* R419   - FLL2 Synchroniser 3 */ 
        { 0x000001A4, 0x0000 },   /* R420   - FLL2 Synchroniser 4 */ 
        { 0x000001A5, 0x0000 },   /* R421   - FLL2 Synchroniser 5 */ 
        { 0x000001A6, 0x0000 },   /* R422   - FLL2 Synchroniser 6 */ 
+       { 0x000001A7, 0x0001 },   /* R423   - FLL2 Synchroniser 7 */
        { 0x000001A9, 0x0000 },   /* R425   - FLL2 Spread Spectrum */ 
        { 0x000001AA, 0x0004 },   /* R426   - FLL2 GPIO Clock */ 
        { 0x00000200, 0x0006 },   /* R512   - Mic Charge Pump 1 */ 
@@ -1051,12 +1055,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL1_CONTROL_6:
        case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
        case ARIZONA_FLL1_NCO_TEST_0:
+       case ARIZONA_FLL1_CONTROL_7:
        case ARIZONA_FLL1_SYNCHRONISER_1:
        case ARIZONA_FLL1_SYNCHRONISER_2:
        case ARIZONA_FLL1_SYNCHRONISER_3:
        case ARIZONA_FLL1_SYNCHRONISER_4:
        case ARIZONA_FLL1_SYNCHRONISER_5:
        case ARIZONA_FLL1_SYNCHRONISER_6:
+       case ARIZONA_FLL1_SYNCHRONISER_7:
        case ARIZONA_FLL1_SPREAD_SPECTRUM:
        case ARIZONA_FLL1_GPIO_CLOCK:
        case ARIZONA_FLL2_CONTROL_1:
@@ -1067,12 +1073,14 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL2_CONTROL_6:
        case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
        case ARIZONA_FLL2_NCO_TEST_0:
+       case ARIZONA_FLL2_CONTROL_7:
        case ARIZONA_FLL2_SYNCHRONISER_1:
        case ARIZONA_FLL2_SYNCHRONISER_2:
        case ARIZONA_FLL2_SYNCHRONISER_3:
        case ARIZONA_FLL2_SYNCHRONISER_4:
        case ARIZONA_FLL2_SYNCHRONISER_5:
        case ARIZONA_FLL2_SYNCHRONISER_6:
+       case ARIZONA_FLL2_SYNCHRONISER_7:
        case ARIZONA_FLL2_SPREAD_SPECTRUM:
        case ARIZONA_FLL2_GPIO_CLOCK:
        case ARIZONA_MIC_CHARGE_PUMP_1:
@@ -1161,6 +1169,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_NOISE_GATE_CONTROL:
        case ARIZONA_PDM_SPK1_CTRL_1:
        case ARIZONA_PDM_SPK1_CTRL_2:
+       case ARIZONA_SPK_CTRL_2:
+       case ARIZONA_SPK_CTRL_3:
        case ARIZONA_DAC_COMP_1:
        case ARIZONA_DAC_COMP_2:
        case ARIZONA_DAC_COMP_3:
index 45ea718..642c622 100644 (file)
@@ -151,6 +151,20 @@ static void mei_me_intr_disable(struct mei_device *dev)
        mei_hcsr_set(hw, hcsr);
 }
 
+/**
+ * mei_me_hw_reset_release - release device from the reset
+ *
+ * @dev: the device structure
+ */
+static void mei_me_hw_reset_release(struct mei_device *dev)
+{
+       struct mei_me_hw *hw = to_me_hw(dev);
+       u32 hcsr = mei_hcsr_read(hw);
+
+       hcsr |= H_IG;
+       hcsr &= ~H_RST;
+       mei_hcsr_set(hw, hcsr);
+}
 /**
  * mei_me_hw_reset - resets fw via mei csr register.
  *
@@ -169,18 +183,14 @@ static void mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
        if (intr_enable)
                hcsr |= H_IE;
        else
-               hcsr &= ~H_IE;
-
-       mei_hcsr_set(hw, hcsr);
-
-       hcsr = mei_hcsr_read(hw) | H_IG;
-       hcsr &= ~H_RST;
+               hcsr |= ~H_IE;
 
        mei_hcsr_set(hw, hcsr);
 
-       hcsr = mei_hcsr_read(hw);
+       if (dev->dev_state == MEI_DEV_POWER_DOWN)
+               mei_me_hw_reset_release(dev);
 
-       dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", hcsr);
+       dev_dbg(&dev->pdev->dev, "current HCSR = 0x%08x.\n", mei_hcsr_read(hw));
 }
 
 /**
@@ -466,7 +476,8 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
                        mutex_unlock(&dev->device_lock);
                        return IRQ_HANDLED;
                } else {
-                       dev_dbg(&dev->pdev->dev, "FW not ready.\n");
+                       dev_dbg(&dev->pdev->dev, "Reset Completed.\n");
+                       mei_me_hw_reset_release(dev);
                        mutex_unlock(&dev->device_lock);
                        return IRQ_HANDLED;
                }
index 6ec5301..3561799 100644 (file)
@@ -183,6 +183,24 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
        mei_cl_all_write_clear(dev);
 }
 
+void mei_stop(struct mei_device *dev)
+{
+       dev_dbg(&dev->pdev->dev, "stopping the device.\n");
+
+       mutex_lock(&dev->device_lock);
+
+       cancel_delayed_work(&dev->timer_work);
+
+       mei_wd_stop(dev);
+
+       dev->dev_state = MEI_DEV_POWER_DOWN;
+       mei_reset(dev, 0);
+
+       mutex_unlock(&dev->device_lock);
+
+       flush_scheduled_work();
+}
+
 
 
 
index cb80166..9787381 100644 (file)
@@ -381,6 +381,7 @@ static inline unsigned long mei_secs_to_jiffies(unsigned long sec)
 void mei_device_init(struct mei_device *dev);
 void mei_reset(struct mei_device *dev, int interrupts);
 int mei_hw_init(struct mei_device *dev);
+void mei_stop(struct mei_device *dev);
 
 /*
  *  MEI interrupt functions prototype
index b40ec06..b8b5c9c 100644 (file)
@@ -247,44 +247,14 @@ static void mei_remove(struct pci_dev *pdev)
 
        hw = to_me_hw(dev);
 
-       mutex_lock(&dev->device_lock);
-
-       cancel_delayed_work(&dev->timer_work);
 
-       mei_wd_stop(dev);
+       dev_err(&pdev->dev, "stop\n");
+       mei_stop(dev);
 
        mei_pdev = NULL;
 
-       if (dev->iamthif_cl.state == MEI_FILE_CONNECTED) {
-               dev->iamthif_cl.state = MEI_FILE_DISCONNECTING;
-               mei_cl_disconnect(&dev->iamthif_cl);
-       }
-       if (dev->wd_cl.state == MEI_FILE_CONNECTED) {
-               dev->wd_cl.state = MEI_FILE_DISCONNECTING;
-               mei_cl_disconnect(&dev->wd_cl);
-       }
-
-       /* Unregistering watchdog device */
        mei_watchdog_unregister(dev);
 
-       /* remove entry if already in list */
-       dev_dbg(&pdev->dev, "list del iamthif and wd file list.\n");
-
-       if (dev->open_handle_count > 0)
-               dev->open_handle_count--;
-       mei_cl_unlink(&dev->wd_cl);
-
-       if (dev->open_handle_count > 0)
-               dev->open_handle_count--;
-       mei_cl_unlink(&dev->iamthif_cl);
-
-       dev->iamthif_current_cb = NULL;
-       dev->me_clients_num = 0;
-
-       mutex_unlock(&dev->device_lock);
-
-       flush_scheduled_work();
-
        /* disable interrupts */
        mei_disable_interrupts(dev);
 
@@ -308,28 +278,20 @@ static int mei_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
        struct mei_device *dev = pci_get_drvdata(pdev);
-       int err;
 
        if (!dev)
                return -ENODEV;
-       mutex_lock(&dev->device_lock);
 
-       cancel_delayed_work(&dev->timer_work);
+       dev_err(&pdev->dev, "suspend\n");
 
-       /* Stop watchdog if exists */
-       err = mei_wd_stop(dev);
-       /* Set new mei state */
-       if (dev->dev_state == MEI_DEV_ENABLED ||
-           dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
-               dev->dev_state = MEI_DEV_POWER_DOWN;
-               mei_reset(dev, 0);
-       }
-       mutex_unlock(&dev->device_lock);
+       mei_stop(dev);
+
+       mei_disable_interrupts(dev);
 
        free_irq(pdev->irq, dev);
        pci_disable_msi(pdev);
 
-       return err;
+       return 0;
 }
 
 static int mei_pci_resume(struct device *device)
index ed5c433..f3cdd90 100644 (file)
@@ -42,9 +42,11 @@ struct datagram_entry {
 
 struct delayed_datagram_info {
        struct datagram_entry *entry;
-       struct vmci_datagram msg;
        struct work_struct work;
        bool in_dg_host_queue;
+       /* msg and msg_payload must be together. */
+       struct vmci_datagram msg;
+       u8 msg_payload[];
 };
 
 /* Number of in-flight host->host datagrams */
index 6bbd90e..171b10f 100644 (file)
@@ -1976,12 +1976,11 @@ static int __bond_release_one(struct net_device *bond_dev,
                return -EINVAL;
        }
 
+       write_unlock_bh(&bond->lock);
        /* unregister rx_handler early so bond_handle_frame wouldn't be called
         * for this slave anymore.
         */
        netdev_rx_handler_unregister(slave_dev);
-       write_unlock_bh(&bond->lock);
-       synchronize_net();
        write_lock_bh(&bond->lock);
 
        if (!all && !bond->params.fail_over_mac) {
@@ -4903,8 +4902,8 @@ static void __exit bonding_exit(void)
 
        bond_destroy_debugfs();
 
-       rtnl_link_unregister(&bond_link_ops);
        unregister_pernet_subsys(&bond_net_ops);
+       rtnl_link_unregister(&bond_link_ops);
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
        /*
index 1c9e09f..ea7a388 100644 (file)
@@ -183,6 +183,11 @@ int bond_create_slave_symlinks(struct net_device *master,
        sprintf(linkname, "slave_%s", slave->name);
        ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
                                linkname);
+
+       /* free the master link created earlier in case of error */
+       if (ret)
+               sysfs_remove_link(&(slave->dev.kobj), "master");
+
        return ret;
 
 }
@@ -522,7 +527,7 @@ static ssize_t bonding_store_arp_interval(struct device *d,
                goto out;
        }
        if (new_value < 0) {
-               pr_err("%s: Invalid arp_interval value %d not in range 1-%d; rejected.\n",
+               pr_err("%s: Invalid arp_interval value %d not in range 0-%d; rejected.\n",
                       bond->dev->name, new_value, INT_MAX);
                ret = -EINVAL;
                goto out;
@@ -537,14 +542,15 @@ static ssize_t bonding_store_arp_interval(struct device *d,
        pr_info("%s: Setting ARP monitoring interval to %d.\n",
                bond->dev->name, new_value);
        bond->params.arp_interval = new_value;
-       if (bond->params.miimon) {
-               pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
-                       bond->dev->name, bond->dev->name);
-               bond->params.miimon = 0;
-       }
-       if (!bond->params.arp_targets[0]) {
-               pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
-                       bond->dev->name);
+       if (new_value) {
+               if (bond->params.miimon) {
+                       pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n",
+                               bond->dev->name, bond->dev->name);
+                       bond->params.miimon = 0;
+               }
+               if (!bond->params.arp_targets[0])
+                       pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n",
+                               bond->dev->name);
        }
        if (bond->dev->flags & IFF_UP) {
                /* If the interface is up, we may need to fire off
@@ -552,10 +558,13 @@ static ssize_t bonding_store_arp_interval(struct device *d,
                 * timer will get fired off when the open function
                 * is called.
                 */
-               cancel_delayed_work_sync(&bond->mii_work);
-               queue_delayed_work(bond->wq, &bond->arp_work, 0);
+               if (!new_value) {
+                       cancel_delayed_work_sync(&bond->arp_work);
+               } else {
+                       cancel_delayed_work_sync(&bond->mii_work);
+                       queue_delayed_work(bond->wq, &bond->arp_work, 0);
+               }
        }
-
 out:
        rtnl_unlock();
        return ret;
@@ -697,7 +706,7 @@ static ssize_t bonding_store_downdelay(struct device *d,
        }
        if (new_value < 0) {
                pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
-                      bond->dev->name, new_value, 1, INT_MAX);
+                      bond->dev->name, new_value, 0, INT_MAX);
                ret = -EINVAL;
                goto out;
        } else {
@@ -752,8 +761,8 @@ static ssize_t bonding_store_updelay(struct device *d,
                goto out;
        }
        if (new_value < 0) {
-               pr_err("%s: Invalid down delay value %d not in range %d-%d; rejected.\n",
-                      bond->dev->name, new_value, 1, INT_MAX);
+               pr_err("%s: Invalid up delay value %d not in range %d-%d; rejected.\n",
+                      bond->dev->name, new_value, 0, INT_MAX);
                ret = -EINVAL;
                goto out;
        } else {
@@ -963,37 +972,37 @@ static ssize_t bonding_store_miimon(struct device *d,
        }
        if (new_value < 0) {
                pr_err("%s: Invalid miimon value %d not in range %d-%d; rejected.\n",
-                      bond->dev->name, new_value, 1, INT_MAX);
+                      bond->dev->name, new_value, 0, INT_MAX);
                ret = -EINVAL;
                goto out;
-       } else {
-               pr_info("%s: Setting MII monitoring interval to %d.\n",
-                       bond->dev->name, new_value);
-               bond->params.miimon = new_value;
-               if (bond->params.updelay)
-                       pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
-                               bond->dev->name,
-                               bond->params.updelay * bond->params.miimon);
-               if (bond->params.downdelay)
-                       pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
-                               bond->dev->name,
-                               bond->params.downdelay * bond->params.miimon);
-               if (bond->params.arp_interval) {
-                       pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
-                               bond->dev->name);
-                       bond->params.arp_interval = 0;
-                       if (bond->params.arp_validate) {
-                               bond->params.arp_validate =
-                                       BOND_ARP_VALIDATE_NONE;
-                       }
-               }
-
-               if (bond->dev->flags & IFF_UP) {
-                       /* If the interface is up, we may need to fire off
-                        * the MII timer. If the interface is down, the
-                        * timer will get fired off when the open function
-                        * is called.
-                        */
+       }
+       pr_info("%s: Setting MII monitoring interval to %d.\n",
+               bond->dev->name, new_value);
+       bond->params.miimon = new_value;
+       if (bond->params.updelay)
+               pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n",
+                       bond->dev->name,
+                       bond->params.updelay * bond->params.miimon);
+       if (bond->params.downdelay)
+               pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n",
+                       bond->dev->name,
+                       bond->params.downdelay * bond->params.miimon);
+       if (new_value && bond->params.arp_interval) {
+               pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n",
+                       bond->dev->name);
+               bond->params.arp_interval = 0;
+               if (bond->params.arp_validate)
+                       bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
+       }
+       if (bond->dev->flags & IFF_UP) {
+               /* If the interface is up, we may need to fire off
+                * the MII timer. If the interface is down, the
+                * timer will get fired off when the open function
+                * is called.
+                */
+               if (!new_value) {
+                       cancel_delayed_work_sync(&bond->mii_work);
+               } else {
                        cancel_delayed_work_sync(&bond->arp_work);
                        queue_delayed_work(bond->wq, &bond->mii_work, 0);
                }
index b39ca5b..ff2ba86 100644 (file)
@@ -46,6 +46,7 @@ config CAN_EMS_PCI
 config CAN_PEAK_PCMCIA
        tristate "PEAK PCAN-PC Card"
        depends on PCMCIA
+       depends on HAS_IOPORT
        ---help---
          This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)
          from PEAK-System (http://www.peak-system.com). To compile this
index a042cdc..3c18d7d 100644 (file)
@@ -348,7 +348,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
         */
        if ((priv->read_reg(priv, REG_CR) & REG_CR_BASICCAN_INITIAL_MASK) ==
            REG_CR_BASICCAN_INITIAL &&
-           (priv->read_reg(priv, REG_SR) == REG_SR_BASICCAN_INITIAL) &&
+           (priv->read_reg(priv, SJA1000_REG_SR) == REG_SR_BASICCAN_INITIAL) &&
            (priv->read_reg(priv, REG_IR) == REG_IR_BASICCAN_INITIAL))
                flag = 1;
 
@@ -360,7 +360,7 @@ static inline int plx_pci_check_sja1000(const struct sja1000_priv *priv)
         * See states on p. 23 of the Datasheet.
         */
        if (priv->read_reg(priv, REG_MOD) == REG_MOD_PELICAN_INITIAL &&
-           priv->read_reg(priv, REG_SR) == REG_SR_PELICAN_INITIAL &&
+           priv->read_reg(priv, SJA1000_REG_SR) == REG_SR_PELICAN_INITIAL &&
            priv->read_reg(priv, REG_IR) == REG_IR_PELICAN_INITIAL)
                return flag;
 
index daf4013..e4df307 100644 (file)
@@ -92,7 +92,7 @@ static void sja1000_write_cmdreg(struct sja1000_priv *priv, u8 val)
         */
        spin_lock_irqsave(&priv->cmdreg_lock, flags);
        priv->write_reg(priv, REG_CMR, val);
-       priv->read_reg(priv, REG_SR);
+       priv->read_reg(priv, SJA1000_REG_SR);
        spin_unlock_irqrestore(&priv->cmdreg_lock, flags);
 }
 
@@ -502,7 +502,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
 
        while ((isrc = priv->read_reg(priv, REG_IR)) && (n < SJA1000_MAX_IRQ)) {
                n++;
-               status = priv->read_reg(priv, REG_SR);
+               status = priv->read_reg(priv, SJA1000_REG_SR);
                /* check for absent controller due to hw unplug */
                if (status == 0xFF && sja1000_is_absent(priv))
                        return IRQ_NONE;
@@ -530,7 +530,7 @@ irqreturn_t sja1000_interrupt(int irq, void *dev_id)
                        /* receive interrupt */
                        while (status & SR_RBS) {
                                sja1000_rx(dev);
-                               status = priv->read_reg(priv, REG_SR);
+                               status = priv->read_reg(priv, SJA1000_REG_SR);
                                /* check for absent controller */
                                if (status == 0xFF && sja1000_is_absent(priv))
                                        return IRQ_NONE;
index afa9984..aa48e05 100644 (file)
@@ -56,7 +56,7 @@
 /* SJA1000 registers - manual section 6.4 (Pelican Mode) */
 #define REG_MOD                0x00
 #define REG_CMR                0x01
-#define REG_SR         0x02
+#define SJA1000_REG_SR         0x02
 #define REG_IR         0x03
 #define REG_IER                0x04
 #define REG_ALC                0x0B
index 829b5ad..b5fd934 100644 (file)
@@ -186,7 +186,7 @@ struct atl1e_tpd_desc {
 /* how about 0x2000 */
 #define MAX_TX_BUF_LEN      0x2000
 #define MAX_TX_BUF_SHIFT    13
-/*#define MAX_TX_BUF_LEN  0x3000 */
+#define MAX_TSO_SEG_SIZE    0x3c00
 
 /* rrs word 1 bit 0:31 */
 #define RRS_RX_CSUM_MASK       0xFFFF
@@ -438,7 +438,6 @@ struct atl1e_adapter {
        struct atl1e_hw        hw;
        struct atl1e_hw_stats  hw_stats;
 
-       bool have_msi;
        u32 wol;
        u16 link_speed;
        u16 link_duplex;
index 92f4734..ac25f05 100644 (file)
@@ -1849,34 +1849,19 @@ static void atl1e_free_irq(struct atl1e_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
 
        free_irq(adapter->pdev->irq, netdev);
-
-       if (adapter->have_msi)
-               pci_disable_msi(adapter->pdev);
 }
 
 static int atl1e_request_irq(struct atl1e_adapter *adapter)
 {
        struct pci_dev    *pdev   = adapter->pdev;
        struct net_device *netdev = adapter->netdev;
-       int flags = 0;
        int err = 0;
 
-       adapter->have_msi = true;
-       err = pci_enable_msi(pdev);
-       if (err) {
-               netdev_dbg(netdev,
-                          "Unable to allocate MSI interrupt Error: %d\n", err);
-               adapter->have_msi = false;
-       }
-
-       if (!adapter->have_msi)
-               flags |= IRQF_SHARED;
-       err = request_irq(pdev->irq, atl1e_intr, flags, netdev->name, netdev);
+       err = request_irq(pdev->irq, atl1e_intr, IRQF_SHARED, netdev->name,
+                         netdev);
        if (err) {
                netdev_dbg(adapter->netdev,
                           "Unable to allocate interrupt Error: %d\n", err);
-               if (adapter->have_msi)
-                       pci_disable_msi(pdev);
                return err;
        }
        netdev_dbg(netdev, "atl1e_request_irq OK\n");
@@ -2344,6 +2329,7 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        INIT_WORK(&adapter->reset_task, atl1e_reset_task);
        INIT_WORK(&adapter->link_chg_task, atl1e_link_chg_task);
+       netif_set_gso_max_size(netdev, MAX_TSO_SEG_SIZE);
        err = register_netdev(netdev);
        if (err) {
                netdev_err(netdev, "register netdevice failed\n");
index 5682054..91ecd6a 100644 (file)
@@ -2139,12 +2139,12 @@ static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap)
                        break;
                default:
                        BNX2X_ERR("Non valid capability ID\n");
-                       rval = -EINVAL;
+                       rval = 1;
                        break;
                }
        } else {
                DP(BNX2X_MSG_DCB, "DCB disabled\n");
-               rval = -EINVAL;
+               rval = 1;
        }
 
        DP(BNX2X_MSG_DCB, "capid %d:%x\n", capid, *cap);
@@ -2170,12 +2170,12 @@ static int bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num)
                        break;
                default:
                        BNX2X_ERR("Non valid TC-ID\n");
-                       rval = -EINVAL;
+                       rval = 1;
                        break;
                }
        } else {
                DP(BNX2X_MSG_DCB, "DCB disabled\n");
-               rval = -EINVAL;
+               rval = 1;
        }
 
        return rval;
@@ -2188,7 +2188,7 @@ static int bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num)
        return -EINVAL;
 }
 
-static u8  bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)
+static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev)
 {
        struct bnx2x *bp = netdev_priv(netdev);
        DP(BNX2X_MSG_DCB, "state = %d\n", bp->dcbx_local_feat.pfc.enabled);
@@ -2390,12 +2390,12 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
                        break;
                default:
                        BNX2X_ERR("Non valid featrue-ID\n");
-                       rval = -EINVAL;
+                       rval = 1;
                        break;
                }
        } else {
                DP(BNX2X_MSG_DCB, "DCB disabled\n");
-               rval = -EINVAL;
+               rval = 1;
        }
 
        return rval;
@@ -2431,12 +2431,12 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,
                        break;
                default:
                        BNX2X_ERR("Non valid featrue-ID\n");
-                       rval = -EINVAL;
+                       rval = 1;
                        break;
                }
        } else {
                DP(BNX2X_MSG_DCB, "dcbnl call not valid\n");
-               rval = -EINVAL;
+               rval = 1;
        }
 
        return rval;
index 67d2663..17a9727 100644 (file)
@@ -14604,8 +14604,11 @@ static void tg3_read_vpd(struct tg3 *tp)
                if (j + len > block_end)
                        goto partno;
 
-               memcpy(tp->fw_ver, &vpd_data[j], len);
-               strncat(tp->fw_ver, " bc ", vpdlen - len - 1);
+               if (len >= sizeof(tp->fw_ver))
+                       len = sizeof(tp->fw_ver) - 1;
+               memset(tp->fw_ver, 0, sizeof(tp->fw_ver));
+               snprintf(tp->fw_ver, sizeof(tp->fw_ver), "%.*s bc ", len,
+                        &vpd_data[j]);
        }
 
 partno:
index a170065..b0ebc9f 100644 (file)
 #define XGMAC_FLOW_CTRL_FCB_BPA        0x00000001      /* Flow Control Busy ... */
 
 /* XGMAC_INT_STAT reg */
+#define XGMAC_INT_STAT_PMTIM   0x00800000      /* PMT Interrupt Mask */
 #define XGMAC_INT_STAT_PMT     0x0080          /* PMT Interrupt Status */
 #define XGMAC_INT_STAT_LPI     0x0040          /* LPI Interrupt Status */
 
@@ -960,6 +961,9 @@ static int xgmac_hw_init(struct net_device *dev)
        writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_STATUS);
        writel(DMA_INTR_DEFAULT_MASK, ioaddr + XGMAC_DMA_INTR_ENA);
 
+       /* Mask power mgt interrupt */
+       writel(XGMAC_INT_STAT_PMTIM, ioaddr + XGMAC_INT_STAT);
+
        /* XGMAC requires AXI bus init. This is a 'magic number' for now */
        writel(0x0077000E, ioaddr + XGMAC_DMA_AXI_BUS);
 
@@ -1141,6 +1145,9 @@ static int xgmac_rx(struct xgmac_priv *priv, int limit)
                struct sk_buff *skb;
                int frame_len;
 
+               if (!dma_ring_cnt(priv->rx_head, priv->rx_tail, DMA_RX_RING_SZ))
+                       break;
+
                entry = priv->rx_tail;
                p = priv->dma_rx + entry;
                if (desc_get_owner(p))
@@ -1825,7 +1832,7 @@ static void xgmac_pmt(void __iomem *ioaddr, unsigned long mode)
        unsigned int pmt = 0;
 
        if (mode & WAKE_MAGIC)
-               pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT;
+               pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_MAGIC_PKT_EN;
        if (mode & WAKE_UCAST)
                pmt |= XGMAC_PMT_POWERDOWN | XGMAC_PMT_GLBL_UNICAST;
 
index 8cdf025..9eada8e 100644 (file)
@@ -257,6 +257,107 @@ static void dm9000_dumpblk_32bit(void __iomem *reg, int count)
                tmp = readl(reg);
 }
 
+/*
+ * Sleep, either by using msleep() or if we are suspending, then
+ * use mdelay() to sleep.
+ */
+static void dm9000_msleep(board_info_t *db, unsigned int ms)
+{
+       if (db->in_suspend)
+               mdelay(ms);
+       else
+               msleep(ms);
+}
+
+/* Read a word from phyxcer */
+static int
+dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
+{
+       board_info_t *db = netdev_priv(dev);
+       unsigned long flags;
+       unsigned int reg_save;
+       int ret;
+
+       mutex_lock(&db->addr_lock);
+
+       spin_lock_irqsave(&db->lock, flags);
+
+       /* Save previous register address */
+       reg_save = readb(db->io_addr);
+
+       /* Fill the phyxcer register into REG_0C */
+       iow(db, DM9000_EPAR, DM9000_PHY | reg);
+
+       /* Issue phyxcer read command */
+       iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);
+
+       writeb(reg_save, db->io_addr);
+       spin_unlock_irqrestore(&db->lock, flags);
+
+       dm9000_msleep(db, 1);           /* Wait read complete */
+
+       spin_lock_irqsave(&db->lock, flags);
+       reg_save = readb(db->io_addr);
+
+       iow(db, DM9000_EPCR, 0x0);      /* Clear phyxcer read command */
+
+       /* The read data keeps on REG_0D & REG_0E */
+       ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
+
+       /* restore the previous address */
+       writeb(reg_save, db->io_addr);
+       spin_unlock_irqrestore(&db->lock, flags);
+
+       mutex_unlock(&db->addr_lock);
+
+       dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
+       return ret;
+}
+
+/* Write a word to phyxcer */
+static void
+dm9000_phy_write(struct net_device *dev,
+                int phyaddr_unused, int reg, int value)
+{
+       board_info_t *db = netdev_priv(dev);
+       unsigned long flags;
+       unsigned long reg_save;
+
+       dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
+       mutex_lock(&db->addr_lock);
+
+       spin_lock_irqsave(&db->lock, flags);
+
+       /* Save previous register address */
+       reg_save = readb(db->io_addr);
+
+       /* Fill the phyxcer register into REG_0C */
+       iow(db, DM9000_EPAR, DM9000_PHY | reg);
+
+       /* Fill the written data into REG_0D & REG_0E */
+       iow(db, DM9000_EPDRL, value);
+       iow(db, DM9000_EPDRH, value >> 8);
+
+       /* Issue phyxcer write command */
+       iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);
+
+       writeb(reg_save, db->io_addr);
+       spin_unlock_irqrestore(&db->lock, flags);
+
+       dm9000_msleep(db, 1);           /* Wait write complete */
+
+       spin_lock_irqsave(&db->lock, flags);
+       reg_save = readb(db->io_addr);
+
+       iow(db, DM9000_EPCR, 0x0);      /* Clear phyxcer write command */
+
+       /* restore the previous address */
+       writeb(reg_save, db->io_addr);
+
+       spin_unlock_irqrestore(&db->lock, flags);
+       mutex_unlock(&db->addr_lock);
+}
+
 /* dm9000_set_io
  *
  * select the specified set of io routines to use with the
@@ -795,6 +896,9 @@ dm9000_init_dm9000(struct net_device *dev)
 
        iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */
 
+       dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */
+       dm9000_phy_write(dev, 0, MII_DM_DSPCR, DSPCR_INIT_PARAM); /* Init */
+
        ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;
 
        /* if wol is needed, then always set NCR_WAKEEN otherwise we end
@@ -1201,109 +1305,6 @@ dm9000_open(struct net_device *dev)
        return 0;
 }
 
-/*
- * Sleep, either by using msleep() or if we are suspending, then
- * use mdelay() to sleep.
- */
-static void dm9000_msleep(board_info_t *db, unsigned int ms)
-{
-       if (db->in_suspend)
-               mdelay(ms);
-       else
-               msleep(ms);
-}
-
-/*
- *   Read a word from phyxcer
- */
-static int
-dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg)
-{
-       board_info_t *db = netdev_priv(dev);
-       unsigned long flags;
-       unsigned int reg_save;
-       int ret;
-
-       mutex_lock(&db->addr_lock);
-
-       spin_lock_irqsave(&db->lock,flags);
-
-       /* Save previous register address */
-       reg_save = readb(db->io_addr);
-
-       /* Fill the phyxcer register into REG_0C */
-       iow(db, DM9000_EPAR, DM9000_PHY | reg);
-
-       iow(db, DM9000_EPCR, EPCR_ERPRR | EPCR_EPOS);   /* Issue phyxcer read command */
-
-       writeb(reg_save, db->io_addr);
-       spin_unlock_irqrestore(&db->lock,flags);
-
-       dm9000_msleep(db, 1);           /* Wait read complete */
-
-       spin_lock_irqsave(&db->lock,flags);
-       reg_save = readb(db->io_addr);
-
-       iow(db, DM9000_EPCR, 0x0);      /* Clear phyxcer read command */
-
-       /* The read data keeps on REG_0D & REG_0E */
-       ret = (ior(db, DM9000_EPDRH) << 8) | ior(db, DM9000_EPDRL);
-
-       /* restore the previous address */
-       writeb(reg_save, db->io_addr);
-       spin_unlock_irqrestore(&db->lock,flags);
-
-       mutex_unlock(&db->addr_lock);
-
-       dm9000_dbg(db, 5, "phy_read[%02x] -> %04x\n", reg, ret);
-       return ret;
-}
-
-/*
- *   Write a word to phyxcer
- */
-static void
-dm9000_phy_write(struct net_device *dev,
-                int phyaddr_unused, int reg, int value)
-{
-       board_info_t *db = netdev_priv(dev);
-       unsigned long flags;
-       unsigned long reg_save;
-
-       dm9000_dbg(db, 5, "phy_write[%02x] = %04x\n", reg, value);
-       mutex_lock(&db->addr_lock);
-
-       spin_lock_irqsave(&db->lock,flags);
-
-       /* Save previous register address */
-       reg_save = readb(db->io_addr);
-
-       /* Fill the phyxcer register into REG_0C */
-       iow(db, DM9000_EPAR, DM9000_PHY | reg);
-
-       /* Fill the written data into REG_0D & REG_0E */
-       iow(db, DM9000_EPDRL, value);
-       iow(db, DM9000_EPDRH, value >> 8);
-
-       iow(db, DM9000_EPCR, EPCR_EPOS | EPCR_ERPRW);   /* Issue phyxcer write command */
-
-       writeb(reg_save, db->io_addr);
-       spin_unlock_irqrestore(&db->lock, flags);
-
-       dm9000_msleep(db, 1);           /* Wait write complete */
-
-       spin_lock_irqsave(&db->lock,flags);
-       reg_save = readb(db->io_addr);
-
-       iow(db, DM9000_EPCR, 0x0);      /* Clear phyxcer write command */
-
-       /* restore the previous address */
-       writeb(reg_save, db->io_addr);
-
-       spin_unlock_irqrestore(&db->lock, flags);
-       mutex_unlock(&db->addr_lock);
-}
-
 static void
 dm9000_shutdown(struct net_device *dev)
 {
@@ -1502,7 +1503,12 @@ dm9000_probe(struct platform_device *pdev)
        db->flags |= DM9000_PLATF_SIMPLE_PHY;
 #endif
 
-       dm9000_reset(db);
+       /* Fixing bug on dm9000_probe, takeover dm9000_reset(db),
+        * Need 'NCR_MAC_LBK' bit to indeed stable our DM9000 fifo
+        * while probe stage.
+        */
+
+       iow(db, DM9000_NCR, NCR_MAC_LBK | NCR_RST);
 
        /* try multiple times, DM9000 sometimes gets the read wrong */
        for (i = 0; i < 8; i++) {
index 55688bd..9ce058a 100644 (file)
@@ -69,7 +69,9 @@
 #define NCR_WAKEEN          (1<<6)
 #define NCR_FCOL            (1<<4)
 #define NCR_FDX             (1<<3)
-#define NCR_LBK             (3<<1)
+
+#define NCR_RESERVED        (3<<1)
+#define NCR_MAC_LBK         (1<<1)
 #define NCR_RST                    (1<<0)
 
 #define NSR_SPEED           (1<<7)
 #define ISR_LNKCHNG            (1<<5)
 #define ISR_UNDERRUN           (1<<4)
 
+/* Davicom MII registers.
+ */
+
+#define MII_DM_DSPCR           0x1b    /* DSP Control Register */
+
+#define DSPCR_INIT_PARAM       0xE100  /* DSP init parameter */
+
 #endif /* _DM9000X_H_ */
 
index e3f3937..f292c3a 100644 (file)
@@ -345,6 +345,53 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        return NETDEV_TX_OK;
 }
 
+/* Init RX & TX buffer descriptors
+ */
+static void fec_enet_bd_init(struct net_device *dev)
+{
+       struct fec_enet_private *fep = netdev_priv(dev);
+       struct bufdesc *bdp;
+       unsigned int i;
+
+       /* Initialize the receive buffer descriptors. */
+       bdp = fep->rx_bd_base;
+       for (i = 0; i < RX_RING_SIZE; i++) {
+
+               /* Initialize the BD for every fragment in the page. */
+               if (bdp->cbd_bufaddr)
+                       bdp->cbd_sc = BD_ENET_RX_EMPTY;
+               else
+                       bdp->cbd_sc = 0;
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
+       }
+
+       /* Set the last buffer to wrap */
+       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+       bdp->cbd_sc |= BD_SC_WRAP;
+
+       fep->cur_rx = fep->rx_bd_base;
+
+       /* ...and the same for transmit */
+       bdp = fep->tx_bd_base;
+       fep->cur_tx = bdp;
+       for (i = 0; i < TX_RING_SIZE; i++) {
+
+               /* Initialize the BD for every fragment in the page. */
+               bdp->cbd_sc = 0;
+               if (bdp->cbd_bufaddr && fep->tx_skbuff[i]) {
+                       dev_kfree_skb_any(fep->tx_skbuff[i]);
+                       fep->tx_skbuff[i] = NULL;
+               }
+               bdp->cbd_bufaddr = 0;
+               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
+       }
+
+       /* Set the last buffer to wrap */
+       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
+       bdp->cbd_sc |= BD_SC_WRAP;
+       fep->dirty_tx = bdp;
+}
+
 /* This function is called to start or restart the FEC during a link
  * change.  This only happens when switching between half and full
  * duplex.
@@ -388,6 +435,8 @@ fec_restart(struct net_device *ndev, int duplex)
        /* Set maximum receive buffer size. */
        writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE);
 
+       fec_enet_bd_init(ndev);
+
        /* Set receive and transmit descriptor base. */
        writel(fep->bd_dma, fep->hwp + FEC_R_DES_START);
        if (fep->bufdesc_ex)
@@ -397,7 +446,6 @@ fec_restart(struct net_device *ndev, int duplex)
                writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc)
                        * RX_RING_SIZE, fep->hwp + FEC_X_DES_START);
 
-       fep->cur_rx = fep->rx_bd_base;
 
        for (i = 0; i <= TX_RING_MOD_MASK; i++) {
                if (fep->tx_skbuff[i]) {
@@ -1332,7 +1380,7 @@ static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 static void fec_enet_free_buffers(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       int i;
+       unsigned int i;
        struct sk_buff *skb;
        struct bufdesc  *bdp;
 
@@ -1356,7 +1404,7 @@ static void fec_enet_free_buffers(struct net_device *ndev)
 static int fec_enet_alloc_buffers(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
-       int i;
+       unsigned int i;
        struct sk_buff *skb;
        struct bufdesc  *bdp;
 
@@ -1597,8 +1645,6 @@ static int fec_enet_init(struct net_device *ndev)
 {
        struct fec_enet_private *fep = netdev_priv(ndev);
        struct bufdesc *cbd_base;
-       struct bufdesc *bdp;
-       int i;
 
        /* Allocate memory for buffer descriptors. */
        cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma,
@@ -1608,6 +1654,7 @@ static int fec_enet_init(struct net_device *ndev)
                return -ENOMEM;
        }
 
+       memset(cbd_base, 0, PAGE_SIZE);
        spin_lock_init(&fep->hw_lock);
 
        fep->netdev = ndev;
@@ -1631,35 +1678,6 @@ static int fec_enet_init(struct net_device *ndev)
        writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK);
        netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, FEC_NAPI_WEIGHT);
 
-       /* Initialize the receive buffer descriptors. */
-       bdp = fep->rx_bd_base;
-       for (i = 0; i < RX_RING_SIZE; i++) {
-
-               /* Initialize the BD for every fragment in the page. */
-               bdp->cbd_sc = 0;
-               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
-       }
-
-       /* Set the last buffer to wrap */
-       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
-       bdp->cbd_sc |= BD_SC_WRAP;
-
-       /* ...and the same for transmit */
-       bdp = fep->tx_bd_base;
-       fep->cur_tx = bdp;
-       for (i = 0; i < TX_RING_SIZE; i++) {
-
-               /* Initialize the BD for every fragment in the page. */
-               bdp->cbd_sc = 0;
-               bdp->cbd_bufaddr = 0;
-               bdp = fec_enet_get_nextdesc(bdp, fep->bufdesc_ex);
-       }
-
-       /* Set the last buffer to wrap */
-       bdp = fec_enet_get_prevdesc(bdp, fep->bufdesc_ex);
-       bdp->cbd_sc |= BD_SC_WRAP;
-       fep->dirty_tx = bdp;
-
        fec_restart(ndev, 0);
 
        return 0;
index 1f17ca0..0d8df40 100644 (file)
@@ -128,6 +128,7 @@ void fec_ptp_start_cyclecounter(struct net_device *ndev)
 
        spin_unlock_irqrestore(&fep->tmreg_lock, flags);
 }
+EXPORT_SYMBOL(fec_ptp_start_cyclecounter);
 
 /**
  * fec_ptp_adjfreq - adjust ptp cycle frequency
@@ -318,6 +319,7 @@ int fec_ptp_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
        return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
            -EFAULT : 0;
 }
+EXPORT_SYMBOL(fec_ptp_ioctl);
 
 /**
  * fec_time_keep - call timecounter_read every second to avoid timer overrun
@@ -383,3 +385,4 @@ void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev)
                pr_info("registered PHC device on %s\n", ndev->name);
        }
 }
+EXPORT_SYMBOL(fec_ptp_init);
index 43462d5..ffd2871 100644 (file)
@@ -1053,6 +1053,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
                txdr->buffer_info[i].dma =
                        dma_map_single(&pdev->dev, skb->data, skb->len,
                                       DMA_TO_DEVICE);
+               if (dma_mapping_error(&pdev->dev, txdr->buffer_info[i].dma)) {
+                       ret_val = 4;
+                       goto err_nomem;
+               }
                tx_desc->buffer_addr = cpu_to_le64(txdr->buffer_info[i].dma);
                tx_desc->lower.data = cpu_to_le32(skb->len);
                tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
@@ -1069,7 +1073,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
        rxdr->buffer_info = kcalloc(rxdr->count, sizeof(struct e1000_buffer),
                                    GFP_KERNEL);
        if (!rxdr->buffer_info) {
-               ret_val = 4;
+               ret_val = 5;
                goto err_nomem;
        }
 
@@ -1077,7 +1081,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
        rxdr->desc = dma_alloc_coherent(&pdev->dev, rxdr->size, &rxdr->dma,
                                        GFP_KERNEL);
        if (!rxdr->desc) {
-               ret_val = 5;
+               ret_val = 6;
                goto err_nomem;
        }
        memset(rxdr->desc, 0, rxdr->size);
@@ -1101,7 +1105,7 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
 
                skb = alloc_skb(E1000_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
                if (!skb) {
-                       ret_val = 6;
+                       ret_val = 7;
                        goto err_nomem;
                }
                skb_reserve(skb, NET_IP_ALIGN);
@@ -1110,6 +1114,10 @@ static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
                rxdr->buffer_info[i].dma =
                        dma_map_single(&pdev->dev, skb->data,
                                       E1000_RXBUFFER_2048, DMA_FROM_DEVICE);
+               if (dma_mapping_error(&pdev->dev, rxdr->buffer_info[i].dma)) {
+                       ret_val = 8;
+                       goto err_nomem;
+               }
                rx_desc->buffer_addr = cpu_to_le64(rxdr->buffer_info[i].dma);
                memset(skb->data, 0x00, skb->len);
        }
index 948b86f..7e615e2 100644 (file)
@@ -848,11 +848,16 @@ check_page:
                        }
                }
 
-               if (!buffer_info->dma)
+               if (!buffer_info->dma) {
                        buffer_info->dma = dma_map_page(&pdev->dev,
                                                        buffer_info->page, 0,
                                                        PAGE_SIZE,
                                                        DMA_FROM_DEVICE);
+                       if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
+                               adapter->alloc_rx_buff_failed++;
+                               break;
+                       }
+               }
 
                rx_desc = E1000_RX_DESC_EXT(*rx_ring, i);
                rx_desc->read.buffer_addr = cpu_to_le64(buffer_info->dma);
index b64542a..12b1d84 100644 (file)
@@ -1818,27 +1818,32 @@ out:
  **/
 void igb_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
 {
-       u32 dtxswc;
+       u32 reg_val, reg_offset;
 
        switch (hw->mac.type) {
        case e1000_82576:
+               reg_offset = E1000_DTXSWC;
+               break;
        case e1000_i350:
-               dtxswc = rd32(E1000_DTXSWC);
-               if (enable) {
-                       dtxswc |= (E1000_DTXSWC_MAC_SPOOF_MASK |
-                                  E1000_DTXSWC_VLAN_SPOOF_MASK);
-                       /* The PF can spoof - it has to in order to
-                        * support emulation mode NICs */
-                       dtxswc ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
-               } else {
-                       dtxswc &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
-                                   E1000_DTXSWC_VLAN_SPOOF_MASK);
-               }
-               wr32(E1000_DTXSWC, dtxswc);
+               reg_offset = E1000_TXSWC;
                break;
        default:
-               break;
+               return;
+       }
+
+       reg_val = rd32(reg_offset);
+       if (enable) {
+               reg_val |= (E1000_DTXSWC_MAC_SPOOF_MASK |
+                            E1000_DTXSWC_VLAN_SPOOF_MASK);
+               /* The PF can spoof - it has to in order to
+                * support emulation mode NICs
+                */
+               reg_val ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
+       } else {
+               reg_val &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
+                            E1000_DTXSWC_VLAN_SPOOF_MASK);
        }
+       wr32(reg_offset, reg_val);
 }
 
 /**
index 4623502..0478a1a 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/pci.h>
 
 #ifdef CONFIG_IGB_HWMON
-struct i2c_board_info i350_sensor_info = {
+static struct i2c_board_info i350_sensor_info = {
        I2C_BOARD_INFO("i350bb", (0Xf8 >> 1)),
 };
 
index 4dbd629..8496adf 100644 (file)
@@ -2542,8 +2542,8 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
        if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
                return;
 
-       igb_enable_sriov(pdev, max_vfs);
        pci_sriov_set_totalvfs(pdev, 7);
+       igb_enable_sriov(pdev, max_vfs);
 
 #endif /* CONFIG_PCI_IOV */
 }
@@ -2652,7 +2652,7 @@ static int igb_sw_init(struct igb_adapter *adapter)
                if (max_vfs > 7) {
                        dev_warn(&pdev->dev,
                                 "Maximum of 7 VFs per PF, using max\n");
-                       adapter->vfs_allocated_count = 7;
+                       max_vfs = adapter->vfs_allocated_count = 7;
                } else
                        adapter->vfs_allocated_count = max_vfs;
                if (adapter->vfs_allocated_count)
index 0987822..0a23750 100644 (file)
@@ -740,7 +740,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
        case e1000_82576:
                snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
                adapter->ptp_caps.owner = THIS_MODULE;
-               adapter->ptp_caps.max_adj = 1000000000;
+               adapter->ptp_caps.max_adj = 999999881;
                adapter->ptp_caps.n_ext_ts = 0;
                adapter->ptp_caps.pps = 0;
                adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576;
index ea48083..b5f94ab 100644 (file)
@@ -2159,6 +2159,10 @@ map_skb:
                                                  skb->data,
                                                  adapter->rx_buffer_len,
                                                  DMA_FROM_DEVICE);
+               if (dma_mapping_error(&pdev->dev, buffer_info->dma)) {
+                       adapter->alloc_rx_buff_failed++;
+                       break;
+               }
 
                rx_desc = IXGB_RX_DESC(*rx_ring, i);
                rx_desc->buff_addr = cpu_to_le64(buffer_info->dma);
@@ -2168,7 +2172,8 @@ map_skb:
                rx_desc->status = 0;
 
 
-               if (++i == rx_ring->count) i = 0;
+               if (++i == rx_ring->count)
+                       i = 0;
                buffer_info = &rx_ring->buffer_info[i];
        }
 
index db5611a..79f4a26 100644 (file)
@@ -7922,12 +7922,19 @@ static int __init ixgbe_init_module(void)
        ixgbe_dbg_init();
 #endif /* CONFIG_DEBUG_FS */
 
+       ret = pci_register_driver(&ixgbe_driver);
+       if (ret) {
+#ifdef CONFIG_DEBUG_FS
+               ixgbe_dbg_exit();
+#endif /* CONFIG_DEBUG_FS */
+               return ret;
+       }
+
 #ifdef CONFIG_IXGBE_DCA
        dca_register_notify(&dca_notifier);
 #endif
 
-       ret = pci_register_driver(&ixgbe_driver);
-       return ret;
+       return 0;
 }
 
 module_init(ixgbe_init_module);
index c3db6cd..2b6cb5c 100644 (file)
@@ -944,9 +944,17 @@ free_queue_irqs:
                free_irq(adapter->msix_entries[vector].vector,
                         adapter->q_vector[vector]);
        }
-       pci_disable_msix(adapter->pdev);
-       kfree(adapter->msix_entries);
-       adapter->msix_entries = NULL;
+       /* This failure is non-recoverable - it indicates the system is
+        * out of MSIX vector resources and the VF driver cannot run
+        * without them.  Set the number of msix vectors to zero
+        * indicating that not enough can be allocated.  The error
+        * will be returned to the user indicating device open failed.
+        * Any further attempts to force the driver to open will also
+        * fail.  The only way to recover is to unload the driver and
+        * reload it again.  If the system has recovered some MSIX
+        * vectors then it may succeed.
+        */
+       adapter->num_msix_vectors = 0;
        return err;
 }
 
@@ -2572,6 +2580,15 @@ static int ixgbevf_open(struct net_device *netdev)
        struct ixgbe_hw *hw = &adapter->hw;
        int err;
 
+       /* A previous failure to open the device because of a lack of
+        * available MSIX vector resources may have reset the number
+        * of msix vectors variable to zero.  The only way to recover
+        * is to unload/reload the driver and hope that the system has
+        * been able to recover some MSIX vector resources.
+        */
+       if (!adapter->num_msix_vectors)
+               return -ENOMEM;
+
        /* disallow open during test */
        if (test_bit(__IXGBEVF_TESTING, &adapter->state))
                return -EBUSY;
@@ -2628,7 +2645,6 @@ static int ixgbevf_open(struct net_device *netdev)
 
 err_req_irq:
        ixgbevf_down(adapter);
-       ixgbevf_free_irq(adapter);
 err_setup_rx:
        ixgbevf_free_all_rx_resources(adapter);
 err_setup_tx:
index 6a21274..bfdb068 100644 (file)
@@ -769,7 +769,7 @@ ltq_etop_probe(struct platform_device *pdev)
        return 0;
 
 err_free:
-       kfree(dev);
+       free_netdev(dev);
 err_out:
        return err;
 }
index fc07ca3..6a0e671 100644 (file)
@@ -1067,7 +1067,7 @@ static void sky2_ramset(struct sky2_hw *hw, u16 q, u32 start, u32 space)
                sky2_write32(hw, RB_ADDR(q, RB_RX_UTHP), tp);
                sky2_write32(hw, RB_ADDR(q, RB_RX_LTHP), space/2);
 
-               tp = space - 2048/8;
+               tp = space - 8192/8;
                sky2_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp);
                sky2_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4);
        } else {
index 615ac63..ec6dcd8 100644 (file)
@@ -2074,7 +2074,7 @@ enum {
        GM_IS_RX_FF_OR  = 1<<1, /* Receive FIFO Overrun */
        GM_IS_RX_COMPL  = 1<<0, /* Frame Reception Complete */
 
-#define GMAC_DEF_MSK     GM_IS_TX_FF_UR
+#define GMAC_DEF_MSK     (GM_IS_TX_FF_UR | GM_IS_RX_FF_OR)
 };
 
 /*     GMAC_LINK_CTRL  16 bit  GMAC Link Control Reg (YUKON only) */
index 995d4b6..30d78f8 100644 (file)
@@ -411,8 +411,8 @@ static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 
 static void mlx4_en_u64_to_mac(unsigned char dst_mac[ETH_ALEN + 2], u64 src_mac)
 {
-       unsigned int i;
-       for (i = ETH_ALEN - 1; i; --i) {
+       int i;
+       for (i = ETH_ALEN - 1; i >= 0; --i) {
                dst_mac[i] = src_mac & 0xff;
                src_mac >>= 8;
        }
@@ -1637,6 +1637,17 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
        /* Flush multicast filter */
        mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG);
 
+       /* Remove flow steering rules for the port*/
+       if (mdev->dev->caps.steering_mode ==
+           MLX4_STEERING_MODE_DEVICE_MANAGED) {
+               ASSERT_RTNL();
+               list_for_each_entry_safe(flow, tmp_flow,
+                                        &priv->ethtool_list, list) {
+                       mlx4_flow_detach(mdev->dev, flow->id);
+                       list_del(&flow->list);
+               }
+       }
+
        mlx4_en_destroy_drop_qp(priv);
 
        /* Free TX Rings */
@@ -1657,17 +1668,6 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
        if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAGS2_REASSIGN_MAC_EN))
                mdev->mac_removed[priv->port] = 1;
 
-       /* Remove flow steering rules for the port*/
-       if (mdev->dev->caps.steering_mode ==
-           MLX4_STEERING_MODE_DEVICE_MANAGED) {
-               ASSERT_RTNL();
-               list_for_each_entry_safe(flow, tmp_flow,
-                                        &priv->ethtool_list, list) {
-                       mlx4_flow_detach(mdev->dev, flow->id);
-                       list_del(&flow->list);
-               }
-       }
-
        /* Free RX Rings */
        for (i = 0; i < priv->rx_ring_num; i++) {
                mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
index 251ae2f..8e3123a 100644 (file)
@@ -771,7 +771,7 @@ int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave,
        struct mlx4_slave_event_eq_info *event_eq =
                priv->mfunc.master.slave_state[slave].event_eq;
        u32 in_modifier = vhcr->in_modifier;
-       u32 eqn = in_modifier & 0x1FF;
+       u32 eqn = in_modifier & 0x3FF;
        u64 in_param =  vhcr->in_param;
        int err = 0;
        int i;
index 2995687..1391b52 100644 (file)
@@ -99,6 +99,7 @@ struct res_qp {
        struct list_head        mcg_list;
        spinlock_t              mcg_spl;
        int                     local_qpn;
+       atomic_t                ref_count;
 };
 
 enum res_mtt_states {
@@ -197,6 +198,7 @@ enum res_fs_rule_states {
 
 struct res_fs_rule {
        struct res_common       com;
+       int                     qpn;
 };
 
 static void *res_tracker_lookup(struct rb_root *root, u64 res_id)
@@ -355,7 +357,7 @@ static int mpt_mask(struct mlx4_dev *dev)
        return dev->caps.num_mpts - 1;
 }
 
-static void *find_res(struct mlx4_dev *dev, int res_id,
+static void *find_res(struct mlx4_dev *dev, u64 res_id,
                      enum mlx4_resource type)
 {
        struct mlx4_priv *priv = mlx4_priv(dev);
@@ -447,6 +449,7 @@ static struct res_common *alloc_qp_tr(int id)
        ret->local_qpn = id;
        INIT_LIST_HEAD(&ret->mcg_list);
        spin_lock_init(&ret->mcg_spl);
+       atomic_set(&ret->ref_count, 0);
 
        return &ret->com;
 }
@@ -554,7 +557,7 @@ static struct res_common *alloc_xrcdn_tr(int id)
        return &ret->com;
 }
 
-static struct res_common *alloc_fs_rule_tr(u64 id)
+static struct res_common *alloc_fs_rule_tr(u64 id, int qpn)
 {
        struct res_fs_rule *ret;
 
@@ -564,7 +567,7 @@ static struct res_common *alloc_fs_rule_tr(u64 id)
 
        ret->com.res_id = id;
        ret->com.state = RES_FS_RULE_ALLOCATED;
-
+       ret->qpn = qpn;
        return &ret->com;
 }
 
@@ -602,7 +605,7 @@ static struct res_common *alloc_tr(u64 id, enum mlx4_resource type, int slave,
                ret = alloc_xrcdn_tr(id);
                break;
        case RES_FS_RULE:
-               ret = alloc_fs_rule_tr(id);
+               ret = alloc_fs_rule_tr(id, extra);
                break;
        default:
                return NULL;
@@ -671,10 +674,14 @@ undo:
 
 static int remove_qp_ok(struct res_qp *res)
 {
-       if (res->com.state == RES_QP_BUSY)
+       if (res->com.state == RES_QP_BUSY || atomic_read(&res->ref_count) ||
+           !list_empty(&res->mcg_list)) {
+               pr_err("resource tracker: fail to remove qp, state %d, ref_count %d\n",
+                      res->com.state, atomic_read(&res->ref_count));
                return -EBUSY;
-       else if (res->com.state != RES_QP_RESERVED)
+       } else if (res->com.state != RES_QP_RESERVED) {
                return -EPERM;
+       }
 
        return 0;
 }
@@ -3124,6 +3131,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        struct list_head *rlist = &tracker->slave_list[slave].res_list[RES_MAC];
        int err;
        int qpn;
+       struct res_qp *rqp;
        struct mlx4_net_trans_rule_hw_ctrl *ctrl;
        struct _rule_hw  *rule_header;
        int header_id;
@@ -3134,7 +3142,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
 
        ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
        qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
-       err = get_res(dev, slave, qpn, RES_QP, NULL);
+       err = get_res(dev, slave, qpn, RES_QP, &rqp);
        if (err) {
                pr_err("Steering rule with qpn 0x%x rejected.\n", qpn);
                return err;
@@ -3175,14 +3183,16 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
        if (err)
                goto err_put;
 
-       err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, 0);
+       err = add_res_range(dev, slave, vhcr->out_param, 1, RES_FS_RULE, qpn);
        if (err) {
                mlx4_err(dev, "Fail to add flow steering resources.\n ");
                /* detach rule*/
                mlx4_cmd(dev, vhcr->out_param, 0, 0,
                         MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
                         MLX4_CMD_NATIVE);
+               goto err_put;
        }
+       atomic_inc(&rqp->ref_count);
 err_put:
        put_res(dev, slave, qpn, RES_QP);
        return err;
@@ -3195,20 +3205,35 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave,
                                         struct mlx4_cmd_info *cmd)
 {
        int err;
+       struct res_qp *rqp;
+       struct res_fs_rule *rrule;
 
        if (dev->caps.steering_mode !=
            MLX4_STEERING_MODE_DEVICE_MANAGED)
                return -EOPNOTSUPP;
 
+       err = get_res(dev, slave, vhcr->in_param, RES_FS_RULE, &rrule);
+       if (err)
+               return err;
+       /* Release the rule form busy state before removal */
+       put_res(dev, slave, vhcr->in_param, RES_FS_RULE);
+       err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp);
+       if (err)
+               return err;
+
        err = rem_res_range(dev, slave, vhcr->in_param, 1, RES_FS_RULE, 0);
        if (err) {
                mlx4_err(dev, "Fail to remove flow steering resources.\n ");
-               return err;
+               goto out;
        }
 
        err = mlx4_cmd(dev, vhcr->in_param, 0, 0,
                       MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A,
                       MLX4_CMD_NATIVE);
+       if (!err)
+               atomic_dec(&rqp->ref_count);
+out:
+       put_res(dev, slave, rrule->qpn, RES_QP);
        return err;
 }
 
@@ -3806,6 +3831,7 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
        mutex_lock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
        /*VLAN*/
        rem_slave_macs(dev, slave);
+       rem_slave_fs_rule(dev, slave);
        rem_slave_qps(dev, slave);
        rem_slave_srqs(dev, slave);
        rem_slave_cqs(dev, slave);
@@ -3814,6 +3840,5 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave)
        rem_slave_mtts(dev, slave);
        rem_slave_counters(dev, slave);
        rem_slave_xrcdns(dev, slave);
-       rem_slave_fs_rule(dev, slave);
        mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
 }
index 33bcb63..8fb4812 100644 (file)
@@ -528,7 +528,7 @@ static void ks8851_rx_pkts(struct ks8851_net *ks)
        for (; rxfc != 0; rxfc--) {
                rxh = ks8851_rdreg32(ks, KS_RXFHSR);
                rxstat = rxh & 0xffff;
-               rxlen = rxh >> 16;
+               rxlen = (rxh >> 16) & 0xfff;
 
                netif_dbg(ks, rx_status, ks->netdev,
                          "rx: stat 0x%04x, len 0x%04x\n", rxstat, rxlen);
index c4122c8..efa29b7 100644 (file)
@@ -1472,7 +1472,8 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, ndev);
 
-       if (lpc_mii_init(pldat) != 0)
+       ret = lpc_mii_init(pldat);
+       if (ret)
                goto err_out_unregister_netdev;
 
        netdev_info(ndev, "LPC mac at 0x%08x irq %d\n",
index 39ab4d0..73ce7dd 100644 (file)
@@ -1726,9 +1726,9 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
 
                        skb->protocol = eth_type_trans(skb, netdev);
                        if (tcp_ip_status & PCH_GBE_RXD_ACC_STAT_TCPIPOK)
-                               skb->ip_summed = CHECKSUM_NONE;
-                       else
                                skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       else
+                               skb->ip_summed = CHECKSUM_NONE;
 
                        napi_gro_receive(&adapter->napi, skb);
                        (*work_done)++;
index 28fb50a..4ecbe64 100644 (file)
@@ -3818,6 +3818,30 @@ static void rtl_init_mdio_ops(struct rtl8169_private *tp)
        }
 }
 
+static void rtl_speed_down(struct rtl8169_private *tp)
+{
+       u32 adv;
+       int lpa;
+
+       rtl_writephy(tp, 0x1f, 0x0000);
+       lpa = rtl_readphy(tp, MII_LPA);
+
+       if (lpa & (LPA_10HALF | LPA_10FULL))
+               adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full;
+       else if (lpa & (LPA_100HALF | LPA_100FULL))
+               adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+                     ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+       else
+               adv = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+                     ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+                     (tp->mii.supports_gmii ?
+                      ADVERTISED_1000baseT_Half |
+                      ADVERTISED_1000baseT_Full : 0);
+
+       rtl8169_set_speed(tp->dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
+                         adv);
+}
+
 static void rtl_wol_suspend_quirk(struct rtl8169_private *tp)
 {
        void __iomem *ioaddr = tp->mmio_addr;
@@ -3848,9 +3872,7 @@ static bool rtl_wol_pll_power_down(struct rtl8169_private *tp)
        if (!(__rtl8169_get_wol(tp) & WAKE_ANY))
                return false;
 
-       rtl_writephy(tp, 0x1f, 0x0000);
-       rtl_writephy(tp, MII_BMCR, 0x0000);
-
+       rtl_speed_down(tp);
        rtl_wol_suspend_quirk(tp);
 
        return true;
index 33e9617..6ed333f 100644 (file)
@@ -1216,10 +1216,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
                if (felic_stat & ECSR_LCHNG) {
                        /* Link Changed */
                        if (mdp->cd->no_psr || mdp->no_ether_link) {
-                               if (mdp->link == PHY_DOWN)
-                                       link_stat = 0;
-                               else
-                                       link_stat = PHY_ST_LINK;
+                               goto ignore_link;
                        } else {
                                link_stat = (sh_eth_read(ndev, PSR));
                                if (mdp->ether_link_active_low)
@@ -1242,6 +1239,7 @@ static void sh_eth_error(struct net_device *ndev, int intr_status)
                }
        }
 
+ignore_link:
        if (intr_status & EESR_TWB) {
                /* Write buck end. unused write back interrupt */
                if (intr_status & EESR_TABT)    /* Transmit Abort int */
@@ -1326,12 +1324,18 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
        struct sh_eth_private *mdp = netdev_priv(ndev);
        struct sh_eth_cpu_data *cd = mdp->cd;
        irqreturn_t ret = IRQ_NONE;
-       u32 intr_status = 0;
+       unsigned long intr_status;
 
        spin_lock(&mdp->lock);
 
-       /* Get interrpt stat */
+       /* Get interrupt status */
        intr_status = sh_eth_read(ndev, EESR);
+       /* Mask it with the interrupt mask, forcing ECI interrupt to be always
+        * enabled since it's the one that  comes thru regardless of the mask,
+        * and we need to fully handle it in sh_eth_error() in order to quench
+        * it as it doesn't get cleared by just writing 1 to the ECI bit...
+        */
+       intr_status &= sh_eth_read(ndev, EESIPR) | DMAC_M_ECI;
        /* Clear interrupt */
        if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
                        EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
@@ -1373,7 +1377,7 @@ static void sh_eth_adjust_link(struct net_device *ndev)
        struct phy_device *phydev = mdp->phydev;
        int new_state = 0;
 
-       if (phydev->link != PHY_DOWN) {
+       if (phydev->link) {
                if (phydev->duplex != mdp->duplex) {
                        new_state = 1;
                        mdp->duplex = phydev->duplex;
@@ -1387,17 +1391,21 @@ static void sh_eth_adjust_link(struct net_device *ndev)
                        if (mdp->cd->set_rate)
                                mdp->cd->set_rate(ndev);
                }
-               if (mdp->link == PHY_DOWN) {
+               if (!mdp->link) {
                        sh_eth_write(ndev,
                                (sh_eth_read(ndev, ECMR) & ~ECMR_TXF), ECMR);
                        new_state = 1;
                        mdp->link = phydev->link;
+                       if (mdp->cd->no_psr || mdp->no_ether_link)
+                               sh_eth_rcv_snd_enable(ndev);
                }
        } else if (mdp->link) {
                new_state = 1;
-               mdp->link = PHY_DOWN;
+               mdp->link = 0;
                mdp->speed = 0;
                mdp->duplex = -1;
+               if (mdp->cd->no_psr || mdp->no_ether_link)
+                       sh_eth_rcv_snd_disable(ndev);
        }
 
        if (new_state && netif_msg_link(mdp))
@@ -1414,7 +1422,7 @@ static int sh_eth_phy_init(struct net_device *ndev)
        snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
                mdp->mii_bus->id , mdp->phy_id);
 
-       mdp->link = PHY_DOWN;
+       mdp->link = 0;
        mdp->speed = 0;
        mdp->duplex = -1;
 
@@ -2220,6 +2228,7 @@ static void sh_eth_tsu_init(struct sh_eth_private *mdp)
 /* MDIO bus release function */
 static int sh_mdio_release(struct net_device *ndev)
 {
+       struct sh_eth_private *mdp = netdev_priv(ndev);
        struct mii_bus *bus = dev_get_drvdata(&ndev->dev);
 
        /* unregister mdio bus */
@@ -2234,6 +2243,9 @@ static int sh_mdio_release(struct net_device *ndev)
        /* free bitbang info */
        free_mdio_bitbang(bus);
 
+       /* free bitbang memory */
+       kfree(mdp->bitbang);
+
        return 0;
 }
 
@@ -2262,6 +2274,7 @@ static int sh_mdio_init(struct net_device *ndev, int id,
        bitbang->ctrl.ops = &bb_ops;
 
        /* MII controller setting */
+       mdp->bitbang = bitbang;
        mdp->mii_bus = alloc_mdio_bitbang(&bitbang->ctrl);
        if (!mdp->mii_bus) {
                ret = -ENOMEM;
@@ -2441,6 +2454,11 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
                }
                mdp->tsu_addr = ioremap(rtsu->start,
                                        resource_size(rtsu));
+               if (mdp->tsu_addr == NULL) {
+                       ret = -ENOMEM;
+                       dev_err(&pdev->dev, "TSU ioremap failed.\n");
+                       goto out_release;
+               }
                mdp->port = devno % 2;
                ndev->features = NETIF_F_HW_VLAN_FILTER;
        }
index bae84fd..828be45 100644 (file)
@@ -705,6 +705,7 @@ struct sh_eth_private {
        const u16 *reg_offset;
        void __iomem *addr;
        void __iomem *tsu_addr;
+       struct bb_info *bitbang;
        u32 num_rx_ring;
        u32 num_tx_ring;
        dma_addr_t rx_desc_dma;
@@ -722,7 +723,7 @@ struct sh_eth_private {
        u32 phy_id;                                     /* PHY ID */
        struct mii_bus *mii_bus;        /* MDIO bus control */
        struct phy_device *phydev;      /* PHY device control */
-       enum phy_state link;
+       int link;
        phy_interface_t phy_interface;
        int msg_enable;
        int speed;
index 75c4855..80cad06 100644 (file)
@@ -436,7 +436,7 @@ void cpsw_tx_handler(void *token, int len, int status)
         * queue is stopped then start the queue as we have free desc for tx
         */
        if (unlikely(netif_queue_stopped(ndev)))
-               netif_start_queue(ndev);
+               netif_wake_queue(ndev);
        cpts_tx_timestamp(priv->cpts, skb);
        priv->stats.tx_packets++;
        priv->stats.tx_bytes += len;
@@ -1364,7 +1364,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
                struct platform_device *mdio;
 
                parp = of_get_property(slave_node, "phy_id", &lenp);
-               if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) {
+               if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
                        pr_err("Missing slave[%d] phy_id property\n", i);
                        ret = -EINVAL;
                        goto error_ret;
index ae1b77a..72300bc 100644 (file)
@@ -1053,7 +1053,7 @@ static void emac_tx_handler(void *token, int len, int status)
         * queue is stopped then start the queue as we have free desc for tx
         */
        if (unlikely(netif_queue_stopped(ndev)))
-               netif_start_queue(ndev);
+               netif_wake_queue(ndev);
        ndev->stats.tx_packets++;
        ndev->stats.tx_bytes += len;
        dev_kfree_skb_any(skb);
index 9abe517..1a15ec1 100644 (file)
@@ -914,8 +914,12 @@ static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size)
 static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct usbnet *dev = netdev_priv(netdev);
+       int ret;
+
+       if (new_mtu > MAX_SINGLE_PACKET_SIZE)
+               return -EINVAL;
 
-       int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu);
+       ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu + ETH_HLEN);
        if (ret < 0) {
                netdev_warn(dev->net, "Failed to set mac rx frame length\n");
                return ret;
@@ -1324,7 +1328,7 @@ static int smsc75xx_reset(struct usbnet *dev)
 
        netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x\n", buf);
 
-       ret = smsc75xx_set_rx_max_frame_length(dev, 1514);
+       ret = smsc75xx_set_rx_max_frame_length(dev, dev->net->mtu + ETH_HLEN);
        if (ret < 0) {
                netdev_warn(dev->net, "Failed to set max rx frame length\n");
                return ret;
@@ -2134,8 +2138,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
                        else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT))
                                dev->net->stats.rx_frame_errors++;
                } else {
-                       /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
-                       if (unlikely(size > (ETH_FRAME_LEN + 12))) {
+                       /* MAX_SINGLE_PACKET_SIZE + 4(CRC) + 2(COE) + 4(Vlan) */
+                       if (unlikely(size > (MAX_SINGLE_PACKET_SIZE + ETH_HLEN + 12))) {
                                netif_dbg(dev, rx_err, dev->net,
                                          "size err rx_cmd_a=0x%08x\n",
                                          rx_cmd_a);
index 4cc1394..f76c3ca 100644 (file)
@@ -1023,6 +1023,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                                          AR_PHY_AGC_CONTROL_FLTR_CAL   |
                                          AR_PHY_AGC_CONTROL_PKDET_CAL;
 
+       /* Use chip chainmask only for calibration */
        ar9003_hw_set_chain_masks(ah, ah->caps.rx_chainmask, ah->caps.tx_chainmask);
 
        if (rtt) {
@@ -1150,6 +1151,9 @@ skip_tx_iqcal:
                ar9003_hw_rtt_disable(ah);
        }
 
+       /* Revert chainmask to runtime parameters */
+       ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
+
        /* Initialize list pointers */
        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
index ade3afb..7fdac6c 100644 (file)
@@ -28,21 +28,21 @@ void ath_tx_complete_poll_work(struct work_struct *work)
        int i;
        bool needreset = false;
 
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i)) {
-                       txq = &sc->tx.txq[i];
-                       ath_txq_lock(sc, txq);
-                       if (txq->axq_depth) {
-                               if (txq->axq_tx_inprogress) {
-                                       needreset = true;
-                                       ath_txq_unlock(sc, txq);
-                                       break;
-                               } else {
-                                       txq->axq_tx_inprogress = true;
-                               }
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+               txq = sc->tx.txq_map[i];
+
+               ath_txq_lock(sc, txq);
+               if (txq->axq_depth) {
+                       if (txq->axq_tx_inprogress) {
+                               needreset = true;
+                               ath_txq_unlock(sc, txq);
+                               break;
+                       } else {
+                               txq->axq_tx_inprogress = true;
                        }
-                       ath_txq_unlock_complete(sc, txq);
                }
+               ath_txq_unlock_complete(sc, txq);
+       }
 
        if (needreset) {
                ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
@@ -170,7 +170,8 @@ void ath_rx_poll(unsigned long data)
 {
        struct ath_softc *sc = (struct ath_softc *)data;
 
-       ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+       if (!test_bit(SC_OP_INVALID, &sc->sc_flags))
+               ieee80211_queue_work(sc->hw, &sc->hw_check_work);
 }
 
 /*
index 38bc5a7..1221469 100644 (file)
@@ -1487,8 +1487,12 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
        const struct b43_dma_ops *ops;
        struct b43_dmaring *ring;
        struct b43_dmadesc_meta *meta;
+       static const struct b43_txstatus fake; /* filled with 0 */
+       const struct b43_txstatus *txstat;
        int slot, firstused;
        bool frame_succeed;
+       int skip;
+       static u8 err_out1, err_out2;
 
        ring = parse_cookie(dev, status->cookie, &slot);
        if (unlikely(!ring))
@@ -1501,13 +1505,36 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
        firstused = ring->current_slot - ring->used_slots + 1;
        if (firstused < 0)
                firstused = ring->nr_slots + firstused;
+
+       skip = 0;
        if (unlikely(slot != firstused)) {
                /* This possibly is a firmware bug and will result in
-                * malfunction, memory leaks and/or stall of DMA functionality. */
-               b43dbg(dev->wl, "Out of order TX status report on DMA ring %d. "
-                      "Expected %d, but got %d\n",
-                      ring->index, firstused, slot);
-               return;
+                * malfunction, memory leaks and/or stall of DMA functionality.
+                */
+               if (slot == next_slot(ring, next_slot(ring, firstused))) {
+                       /* If a single header/data pair was missed, skip over
+                        * the first two slots in an attempt to recover.
+                        */
+                       slot = firstused;
+                       skip = 2;
+                       if (!err_out1) {
+                               /* Report the error once. */
+                               b43dbg(dev->wl,
+                                      "Skip on DMA ring %d slot %d.\n",
+                                      ring->index, slot);
+                               err_out1 = 1;
+                       }
+               } else {
+                       /* More than a single header/data pair were missed.
+                        * Report this error once.
+                        */
+                       if (!err_out2)
+                               b43dbg(dev->wl,
+                                      "Out of order TX status report on DMA ring %d. Expected %d, but got %d\n",
+                                      ring->index, firstused, slot);
+                       err_out2 = 1;
+                       return;
+               }
        }
 
        ops = ring->ops;
@@ -1522,11 +1549,13 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                               slot, firstused, ring->index);
                        break;
                }
+
                if (meta->skb) {
                        struct b43_private_tx_info *priv_info =
-                               b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
+                            b43_get_priv_tx_info(IEEE80211_SKB_CB(meta->skb));
 
-                       unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
+                       unmap_descbuffer(ring, meta->dmaaddr,
+                                        meta->skb->len, 1);
                        kfree(priv_info->bouncebuffer);
                        priv_info->bouncebuffer = NULL;
                } else {
@@ -1538,8 +1567,9 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                        struct ieee80211_tx_info *info;
 
                        if (unlikely(!meta->skb)) {
-                               /* This is a scatter-gather fragment of a frame, so
-                                * the skb pointer must not be NULL. */
+                               /* This is a scatter-gather fragment of a frame,
+                                * so the skb pointer must not be NULL.
+                                */
                                b43dbg(dev->wl, "TX status unexpected NULL skb "
                                       "at slot %d (first=%d) on ring %d\n",
                                       slot, firstused, ring->index);
@@ -1550,9 +1580,18 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 
                        /*
                         * Call back to inform the ieee80211 subsystem about
-                        * the status of the transmission.
+                        * the status of the transmission. When skipping over
+                        * a missed TX status report, use a status structure
+                        * filled with zeros to indicate that the frame was not
+                        * sent (frame_count 0) and not acknowledged
                         */
-                       frame_succeed = b43_fill_txstatus_report(dev, info, status);
+                       if (unlikely(skip))
+                               txstat = &fake;
+                       else
+                               txstat = status;
+
+                       frame_succeed = b43_fill_txstatus_report(dev, info,
+                                                                txstat);
 #ifdef CONFIG_B43_DEBUG
                        if (frame_succeed)
                                ring->nr_succeed_tx_packets++;
@@ -1580,12 +1619,14 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                /* Everything unmapped and free'd. So it's not used anymore. */
                ring->used_slots--;
 
-               if (meta->is_last_fragment) {
+               if (meta->is_last_fragment && !skip) {
                        /* This is the last scatter-gather
                         * fragment of the frame. We are done. */
                        break;
                }
                slot = next_slot(ring, slot);
+               if (skip > 0)
+                       --skip;
        }
        if (ring->stopped) {
                B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
index 3c35382..e8486c1 100644 (file)
@@ -1564,7 +1564,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
        u16 clip_off[2] = { 0xFFFF, 0xFFFF };
 
        u8 vcm_final = 0;
-       s8 offset[4];
+       s32 offset[4];
        s32 results[8][4] = { };
        s32 results_min[4] = { };
        s32 poll_results[4] = { };
@@ -1615,7 +1615,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
                }
                for (i = 0; i < 4; i += 2) {
                        s32 curr;
-                       s32 mind = 40;
+                       s32 mind = 0x100000;
                        s32 minpoll = 249;
                        u8 minvcm = 0;
                        if (2 * core != i)
@@ -1732,7 +1732,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
        u8 regs_save_radio[2];
        u16 regs_save_phy[2];
 
-       s8 offset[4];
+       s32 offset[4];
        u8 core;
        u8 rail;
 
@@ -1799,7 +1799,7 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
        }
 
        for (i = 0; i < 4; i++) {
-               s32 mind = 40;
+               s32 mind = 0x100000;
                u8 minvcm = 0;
                s32 minpoll = 249;
                s32 curr;
index 21a8242..18d3764 100644 (file)
@@ -1137,9 +1137,8 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
        gain0_15 = ((biq1 & 0xf) << 12) |
                   ((tia & 0xf) << 8) |
                   ((lna2 & 0x3) << 6) |
-                  ((lna2 & 0x3) << 4) |
-                  ((lna1 & 0x3) << 2) |
-                  ((lna1 & 0x3) << 0);
+                  ((lna2 &
+                    0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0);
 
        mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0);
        mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0);
@@ -1157,8 +1156,6 @@ wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi,
        }
 
        mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0);
-       mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11);
-       mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3);
 
 }
 
@@ -1331,43 +1328,6 @@ static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples)
        return (iq_est.i_pwr + iq_est.q_pwr) / nsamples;
 }
 
-static bool wlc_lcnphy_rx_iq_cal_gain(struct brcms_phy *pi, u16 biq1_gain,
-                                     u16 tia_gain, u16 lna2_gain)
-{
-       u32 i_thresh_l, q_thresh_l;
-       u32 i_thresh_h, q_thresh_h;
-       struct lcnphy_iq_est iq_est_h, iq_est_l;
-
-       wlc_lcnphy_set_rx_gain_by_distribution(pi, 0, 0, 0, biq1_gain, tia_gain,
-                                              lna2_gain, 0);
-
-       wlc_lcnphy_rx_gain_override_enable(pi, true);
-       wlc_lcnphy_start_tx_tone(pi, 2000, (40 >> 1), 0);
-       udelay(500);
-       write_radio_reg(pi, RADIO_2064_REG112, 0);
-       if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_l))
-               return false;
-
-       wlc_lcnphy_start_tx_tone(pi, 2000, 40, 0);
-       udelay(500);
-       write_radio_reg(pi, RADIO_2064_REG112, 0);
-       if (!wlc_lcnphy_rx_iq_est(pi, 1024, 32, &iq_est_h))
-               return false;
-
-       i_thresh_l = (iq_est_l.i_pwr << 1);
-       i_thresh_h = (iq_est_l.i_pwr << 2) + iq_est_l.i_pwr;
-
-       q_thresh_l = (iq_est_l.q_pwr << 1);
-       q_thresh_h = (iq_est_l.q_pwr << 2) + iq_est_l.q_pwr;
-       if ((iq_est_h.i_pwr > i_thresh_l) &&
-           (iq_est_h.i_pwr < i_thresh_h) &&
-           (iq_est_h.q_pwr > q_thresh_l) &&
-           (iq_est_h.q_pwr < q_thresh_h))
-               return true;
-
-       return false;
-}
-
 static bool
 wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
                     const struct lcnphy_rx_iqcomp *iqcomp,
@@ -1382,8 +1342,8 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
            RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old,
            rfoverride3_old, rfoverride3val_old, rfoverride4_old,
            rfoverride4val_old, afectrlovr_old, afectrlovrval_old;
-       int tia_gain, lna2_gain, biq1_gain;
-       bool set_gain;
+       int tia_gain;
+       u32 received_power, rx_pwr_threshold;
        u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl;
        u16 values_to_save[11];
        s16 *ptr;
@@ -1408,134 +1368,126 @@ wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi,
                goto cal_done;
        }
 
-       WARN_ON(module != 1);
-       tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
-       wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
-
-       for (i = 0; i < 11; i++)
-               values_to_save[i] =
-                       read_radio_reg(pi, rxiq_cal_rf_reg[i]);
-       Core1TxControl_old = read_phy_reg(pi, 0x631);
-
-       or_phy_reg(pi, 0x631, 0x0015);
-
-       RFOverride0_old = read_phy_reg(pi, 0x44c);
-       RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
-       rfoverride2_old = read_phy_reg(pi, 0x4b0);
-       rfoverride2val_old = read_phy_reg(pi, 0x4b1);
-       rfoverride3_old = read_phy_reg(pi, 0x4f9);
-       rfoverride3val_old = read_phy_reg(pi, 0x4fa);
-       rfoverride4_old = read_phy_reg(pi, 0x938);
-       rfoverride4val_old = read_phy_reg(pi, 0x939);
-       afectrlovr_old = read_phy_reg(pi, 0x43b);
-       afectrlovrval_old = read_phy_reg(pi, 0x43c);
-       old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
-       old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
-
-       tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
-       if (tx_gain_override_old) {
-               wlc_lcnphy_get_tx_gain(pi, &old_gains);
-               tx_gain_index_old = pi_lcn->lcnphy_current_index;
-       }
-
-       wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
+       if (module == 1) {
 
-       mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
-       mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
+               tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi);
+               wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF);
 
-       mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
-       mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
+               for (i = 0; i < 11; i++)
+                       values_to_save[i] =
+                               read_radio_reg(pi, rxiq_cal_rf_reg[i]);
+               Core1TxControl_old = read_phy_reg(pi, 0x631);
+
+               or_phy_reg(pi, 0x631, 0x0015);
+
+               RFOverride0_old = read_phy_reg(pi, 0x44c);
+               RFOverrideVal0_old = read_phy_reg(pi, 0x44d);
+               rfoverride2_old = read_phy_reg(pi, 0x4b0);
+               rfoverride2val_old = read_phy_reg(pi, 0x4b1);
+               rfoverride3_old = read_phy_reg(pi, 0x4f9);
+               rfoverride3val_old = read_phy_reg(pi, 0x4fa);
+               rfoverride4_old = read_phy_reg(pi, 0x938);
+               rfoverride4val_old = read_phy_reg(pi, 0x939);
+               afectrlovr_old = read_phy_reg(pi, 0x43b);
+               afectrlovrval_old = read_phy_reg(pi, 0x43c);
+               old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da);
+               old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db);
+
+               tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi);
+               if (tx_gain_override_old) {
+                       wlc_lcnphy_get_tx_gain(pi, &old_gains);
+                       tx_gain_index_old = pi_lcn->lcnphy_current_index;
+               }
 
-       write_radio_reg(pi, RADIO_2064_REG116, 0x06);
-       write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
-       write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
-       write_radio_reg(pi, RADIO_2064_REG098, 0x03);
-       write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
-       mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
-       write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
-       write_radio_reg(pi, RADIO_2064_REG114, 0x01);
-       write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
-       write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
-
-       mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
-       mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
-       mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
-       mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
-       mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
-       mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
-       mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
-       mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
-       mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
-       mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
+               wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx);
 
-       mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
-       mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+               mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0);
+               mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0);
 
-       write_phy_reg(pi, 0x6da, 0xffff);
-       or_phy_reg(pi, 0x6db, 0x3);
+               mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1);
+               mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1);
 
-       wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
-       set_gain = false;
-
-       lna2_gain = 3;
-       while ((lna2_gain >= 0) && !set_gain) {
-               tia_gain = 4;
-
-               while ((tia_gain >= 0) && !set_gain) {
-                       biq1_gain = 6;
-
-                       while ((biq1_gain >= 0) && !set_gain) {
-                               set_gain = wlc_lcnphy_rx_iq_cal_gain(pi,
-                                                                    (u16)
-                                                                    biq1_gain,
-                                                                    (u16)
-                                                                    tia_gain,
-                                                                    (u16)
-                                                                    lna2_gain);
-                               biq1_gain -= 1;
-                       }
+               write_radio_reg(pi, RADIO_2064_REG116, 0x06);
+               write_radio_reg(pi, RADIO_2064_REG12C, 0x07);
+               write_radio_reg(pi, RADIO_2064_REG06A, 0xd3);
+               write_radio_reg(pi, RADIO_2064_REG098, 0x03);
+               write_radio_reg(pi, RADIO_2064_REG00B, 0x7);
+               mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4);
+               write_radio_reg(pi, RADIO_2064_REG01D, 0x01);
+               write_radio_reg(pi, RADIO_2064_REG114, 0x01);
+               write_radio_reg(pi, RADIO_2064_REG02E, 0x10);
+               write_radio_reg(pi, RADIO_2064_REG12A, 0x08);
+
+               mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0);
+               mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0);
+               mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1);
+               mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1);
+               mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2);
+               mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2);
+               mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3);
+               mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3);
+               mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5);
+               mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5);
+
+               mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0);
+               mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0);
+
+               wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0);
+               write_phy_reg(pi, 0x6da, 0xffff);
+               or_phy_reg(pi, 0x6db, 0x3);
+               wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch);
+               wlc_lcnphy_rx_gain_override_enable(pi, true);
+
+               tia_gain = 8;
+               rx_pwr_threshold = 950;
+               while (tia_gain > 0) {
                        tia_gain -= 1;
+                       wlc_lcnphy_set_rx_gain_by_distribution(pi,
+                                                              0, 0, 2, 2,
+                                                              (u16)
+                                                              tia_gain, 1, 0);
+                       udelay(500);
+
+                       received_power =
+                               wlc_lcnphy_measure_digital_power(pi, 2000);
+                       if (received_power < rx_pwr_threshold)
+                               break;
                }
-               lna2_gain -= 1;
-       }
+               result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff);
 
-       if (set_gain)
-               result = wlc_lcnphy_calc_rx_iq_comp(pi, 1024);
-       else
-               result = false;
+               wlc_lcnphy_stop_tx_tone(pi);
 
-       wlc_lcnphy_stop_tx_tone(pi);
+               write_phy_reg(pi, 0x631, Core1TxControl_old);
 
-       write_phy_reg(pi, 0x631, Core1TxControl_old);
-
-       write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
-       write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
-       write_phy_reg(pi, 0x4b0, rfoverride2_old);
-       write_phy_reg(pi, 0x4b1, rfoverride2val_old);
-       write_phy_reg(pi, 0x4f9, rfoverride3_old);
-       write_phy_reg(pi, 0x4fa, rfoverride3val_old);
-       write_phy_reg(pi, 0x938, rfoverride4_old);
-       write_phy_reg(pi, 0x939, rfoverride4val_old);
-       write_phy_reg(pi, 0x43b, afectrlovr_old);
-       write_phy_reg(pi, 0x43c, afectrlovrval_old);
-       write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
-       write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
+               write_phy_reg(pi, 0x44c, RFOverrideVal0_old);
+               write_phy_reg(pi, 0x44d, RFOverrideVal0_old);
+               write_phy_reg(pi, 0x4b0, rfoverride2_old);
+               write_phy_reg(pi, 0x4b1, rfoverride2val_old);
+               write_phy_reg(pi, 0x4f9, rfoverride3_old);
+               write_phy_reg(pi, 0x4fa, rfoverride3val_old);
+               write_phy_reg(pi, 0x938, rfoverride4_old);
+               write_phy_reg(pi, 0x939, rfoverride4val_old);
+               write_phy_reg(pi, 0x43b, afectrlovr_old);
+               write_phy_reg(pi, 0x43c, afectrlovrval_old);
+               write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl);
+               write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl);
 
-       wlc_lcnphy_clear_trsw_override(pi);
+               wlc_lcnphy_clear_trsw_override(pi);
 
-       mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
+               mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2);
 
-       for (i = 0; i < 11; i++)
-               write_radio_reg(pi, rxiq_cal_rf_reg[i],
-                               values_to_save[i]);
+               for (i = 0; i < 11; i++)
+                       write_radio_reg(pi, rxiq_cal_rf_reg[i],
+                                       values_to_save[i]);
 
-       if (tx_gain_override_old)
-               wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
-       else
-               wlc_lcnphy_disable_tx_gain_override(pi);
+               if (tx_gain_override_old)
+                       wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old);
+               else
+                       wlc_lcnphy_disable_tx_gain_override(pi);
 
-       wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
-       wlc_lcnphy_rx_gain_override_enable(pi, false);
+               wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl);
+               wlc_lcnphy_rx_gain_override_enable(pi, false);
+       }
 
 cal_done:
        kfree(ptr);
@@ -1829,17 +1781,6 @@ wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel)
                write_radio_reg(pi, RADIO_2064_REG038, 3);
                write_radio_reg(pi, RADIO_2064_REG091, 7);
        }
-
-       if (!(pi->sh->boardflags & BFL_FEM)) {
-               u8 reg038[14] = {0xd, 0xe, 0xd, 0xd, 0xd, 0xc,
-                       0xa, 0xb, 0xb, 0x3, 0x3, 0x2, 0x0, 0x0};
-
-               write_radio_reg(pi, RADIO_2064_REG02A, 0xf);
-               write_radio_reg(pi, RADIO_2064_REG091, 0x3);
-               write_radio_reg(pi, RADIO_2064_REG038, 0x3);
-
-               write_radio_reg(pi, RADIO_2064_REG038, reg038[channel - 1]);
-       }
 }
 
 static int
@@ -2034,16 +1975,6 @@ wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos)
                } else {
                        mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1);
                        mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
-                       mod_radio_reg(pi, RADIO_2064_REG028, 0x1, 0x0);
-                       mod_radio_reg(pi, RADIO_2064_REG11A, 0x4, 1<<2);
-                       mod_radio_reg(pi, RADIO_2064_REG036, 0x10, 0x0);
-                       mod_radio_reg(pi, RADIO_2064_REG11A, 0x10, 1<<4);
-                       mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
-                       mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x77);
-                       mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0xe<<1);
-                       mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1<<7);
-                       mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 1<<1);
-                       mod_radio_reg(pi, RADIO_2064_REG029, 0xf0, 0<<4);
                }
        } else {
                mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2);
@@ -2130,14 +2061,12 @@ static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi)
                    (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12));
 
        mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5));
-       mod_radio_reg(pi, RADIO_2064_REG07C, (1 << 0), (1 << 0));
 }
 
 static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
 {
        struct phytbl_info tab;
        u32 rfseq, ind;
-       u8 tssi_sel;
 
        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
        tab.tbl_width = 32;
@@ -2159,13 +2088,7 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
 
        mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4);
 
-       if (pi->sh->boardflags & BFL_FEM) {
-               tssi_sel = 0x1;
-               wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
-       } else {
-               tssi_sel = 0xe;
-               wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_POST_PA);
-       }
+       wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT);
        mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14);
 
        mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15);
@@ -2201,10 +2124,9 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
        mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0);
 
        if (LCNREV_IS(pi->pubpi.phy_rev, 2)) {
-               mod_radio_reg(pi, RADIO_2064_REG028, 0xf, tssi_sel);
+               mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe);
                mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4);
        } else {
-               mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, tssi_sel << 1);
                mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1);
                mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3);
        }
@@ -2251,10 +2173,6 @@ static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi)
 
        mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8);
 
-       mod_radio_reg(pi, RADIO_2064_REG035, 0xff, 0x0);
-       mod_radio_reg(pi, RADIO_2064_REG036, 0x3, 0x0);
-       mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8);
-
        wlc_lcnphy_pwrctrl_rssiparams(pi);
 }
 
@@ -2873,8 +2791,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
                read_radio_reg(pi, RADIO_2064_REG007) & 1;
        u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10;
        u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4;
-       u8 SAVE_bbmult = wlc_lcnphy_get_bbmult(pi);
-
        idleTssi = read_phy_reg(pi, 0x4ab);
        suspend = (0 == (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) &
                         MCTL_EN_MAC));
@@ -2892,12 +2808,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
        mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4);
        mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2);
        wlc_lcnphy_tssi_setup(pi);
-
-       mod_phy_reg(pi, 0x4d7, (0x1 << 0), (1 << 0));
-       mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1 << 6));
-
-       wlc_lcnphy_set_bbmult(pi, 0x0);
-
        wlc_phy_do_dummy_tx(pi, true, OFF);
        idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0))
                    >> 0);
@@ -2919,7 +2829,6 @@ static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi)
 
        mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12);
 
-       wlc_lcnphy_set_bbmult(pi, SAVE_bbmult);
        wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old);
        wlc_lcnphy_set_tx_gain(pi, &old_gains);
        wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl);
@@ -3133,11 +3042,6 @@ static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi)
                        wlc_lcnphy_write_table(pi, &tab);
                        tab.tbl_offset++;
                }
-               mod_phy_reg(pi, 0x4d0, (0x1 << 0), (0) << 0);
-               mod_phy_reg(pi, 0x4d3, (0xff << 0), (0) << 0);
-               mod_phy_reg(pi, 0x4d3, (0xff << 8), (0) << 8);
-               mod_phy_reg(pi, 0x4d0, (0x1 << 4), (0) << 4);
-               mod_phy_reg(pi, 0x4d0, (0x1 << 2), (0) << 2);
 
                mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7);
 
@@ -3939,6 +3843,7 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
        target_gains.pad_gain = 21;
        target_gains.dac_gain = 0;
        wlc_lcnphy_set_tx_gain(pi, &target_gains);
+       wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
 
        if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) {
 
@@ -3949,7 +3854,6 @@ static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi)
                                        lcnphy_recal ? LCNPHY_CAL_RECAL :
                                        LCNPHY_CAL_FULL), false);
        } else {
-               wlc_lcnphy_set_tx_pwr_by_index(pi, 16);
                wlc_lcnphy_tx_iqlo_soft_cal_full(pi);
        }
 
@@ -4374,22 +4278,17 @@ wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi,
        if (CHSPEC_IS5G(pi->radio_chanspec))
                pa_gain = 0x70;
        else
-               pa_gain = 0x60;
+               pa_gain = 0x70;
 
        if (pi->sh->boardflags & BFL_FEM)
                pa_gain = 0x10;
-
        tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL;
        tab.tbl_width = 32;
        tab.tbl_len = 1;
        tab.tbl_ptr = &val;
 
        for (j = 0; j < 128; j++) {
-               if (pi->sh->boardflags & BFL_FEM)
-                       gm_gain = gain_table[j].gm;
-               else
-                       gm_gain = 15;
-
+               gm_gain = gain_table[j].gm;
                val = (((u32) pa_gain << 24) |
                       (gain_table[j].pad << 16) |
                       (gain_table[j].pga << 8) | gm_gain);
@@ -4600,10 +4499,7 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)
 
        write_phy_reg(pi, 0x4ea, 0x4688);
 
-       if (pi->sh->boardflags & BFL_FEM)
-               mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
-       else
-               mod_phy_reg(pi, 0x4eb, (0x7 << 0), 3 << 0);
+       mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0);
 
        mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6);
 
@@ -4614,13 +4510,6 @@ static void wlc_radio_2064_init(struct brcms_phy *pi)
        wlc_lcnphy_rcal(pi);
 
        wlc_lcnphy_rc_cal(pi);
-
-       if (!(pi->sh->boardflags & BFL_FEM)) {
-               write_radio_reg(pi, RADIO_2064_REG032, 0x6f);
-               write_radio_reg(pi, RADIO_2064_REG033, 0x19);
-               write_radio_reg(pi, RADIO_2064_REG039, 0xe);
-       }
-
 }
 
 static void wlc_lcnphy_radio_init(struct brcms_phy *pi)
@@ -4650,20 +4539,22 @@ static void wlc_lcnphy_tbl_init(struct brcms_phy *pi)
                wlc_lcnphy_write_table(pi, &tab);
        }
 
-       if (!(pi->sh->boardflags & BFL_FEM)) {
-               tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
-               tab.tbl_width = 16;
-               tab.tbl_ptr = &val;
-               tab.tbl_len = 1;
+       tab.tbl_id = LCNPHY_TBL_ID_RFSEQ;
+       tab.tbl_width = 16;
+       tab.tbl_ptr = &val;
+       tab.tbl_len = 1;
 
-               val = 150;
-               tab.tbl_offset = 0;
-               wlc_lcnphy_write_table(pi, &tab);
+       val = 114;
+       tab.tbl_offset = 0;
+       wlc_lcnphy_write_table(pi, &tab);
 
-               val = 220;
-               tab.tbl_offset = 1;
-               wlc_lcnphy_write_table(pi, &tab);
-       }
+       val = 130;
+       tab.tbl_offset = 1;
+       wlc_lcnphy_write_table(pi, &tab);
+
+       val = 6;
+       tab.tbl_offset = 8;
+       wlc_lcnphy_write_table(pi, &tab);
 
        if (CHSPEC_IS2G(pi->radio_chanspec)) {
                if (pi->sh->boardflags & BFL_FEM)
@@ -5055,7 +4946,6 @@ void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec)
                wlc_lcnphy_load_tx_iir_filter(pi, true, 3);
 
        mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3);
-       wlc_lcnphy_tssi_setup(pi);
 }
 
 void wlc_phy_detach_lcnphy(struct brcms_phy *pi)
@@ -5094,7 +4984,8 @@ bool wlc_phy_attach_lcnphy(struct brcms_phy *pi)
        if (!wlc_phy_txpwr_srom_read_lcnphy(pi))
                return false;
 
-       if (LCNREV_IS(pi->pubpi.phy_rev, 1)) {
+       if ((pi->sh->boardflags & BFL_FEM) &&
+           (LCNREV_IS(pi->pubpi.phy_rev, 1))) {
                if (pi_lcn->lcnphy_tempsense_option == 3) {
                        pi->hwpwrctrl = true;
                        pi->hwpwrctrl_capable = true;
index b7e95ac..622c01c 100644 (file)
@@ -1992,70 +1992,70 @@ static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = {
 };
 
 static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = {
-       0x0009,
        0x000a,
-       0x0005,
-       0x0006,
        0x0009,
-       0x000a,
-       0x0005,
        0x0006,
-       0x0009,
-       0x000a,
        0x0005,
-       0x0006,
-       0x0009,
        0x000a,
-       0x0005,
-       0x0006,
        0x0009,
-       0x000a,
-       0x0005,
        0x0006,
-       0x0009,
-       0x000a,
        0x0005,
-       0x0006,
-       0x0009,
        0x000a,
-       0x0005,
-       0x0006,
        0x0009,
-       0x000a,
-       0x0005,
        0x0006,
-       0x0009,
-       0x000a,
        0x0005,
-       0x0006,
-       0x0009,
        0x000a,
-       0x0005,
-       0x0006,
        0x0009,
-       0x000a,
-       0x0005,
        0x0006,
-       0x0009,
-       0x000a,
        0x0005,
-       0x0006,
+       0x000a,
        0x0009,
+       0x0006,
+       0x0005,
        0x000a,
+       0x0009,
+       0x0006,
        0x0005,
+       0x000a,
+       0x0009,
        0x0006,
+       0x0005,
+       0x000a,
        0x0009,
+       0x0006,
+       0x0005,
        0x000a,
+       0x0009,
+       0x0006,
        0x0005,
+       0x000a,
+       0x0009,
        0x0006,
+       0x0005,
+       0x000a,
        0x0009,
+       0x0006,
+       0x0005,
        0x000a,
+       0x0009,
+       0x0006,
        0x0005,
+       0x000a,
+       0x0009,
        0x0006,
+       0x0005,
+       0x000a,
        0x0009,
+       0x0006,
+       0x0005,
        0x000a,
+       0x0009,
+       0x0006,
        0x0005,
+       0x000a,
+       0x0009,
        0x0006,
+       0x0005,
 };
 
 static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = {
index 3630a41..c353b5f 100644 (file)
@@ -475,6 +475,7 @@ il3945_tx_skb(struct il_priv *il,
        dma_addr_t txcmd_phys;
        int txq_id = skb_get_queue_mapping(skb);
        u16 len, idx, hdr_len;
+       u16 firstlen, secondlen;
        u8 id;
        u8 unicast;
        u8 sta_id;
@@ -589,21 +590,22 @@ il3945_tx_skb(struct il_priv *il,
        len =
            sizeof(struct il3945_tx_cmd) + sizeof(struct il_cmd_header) +
            hdr_len;
-       len = (len + 3) & ~3;
+       firstlen = (len + 3) & ~3;
 
        /* Physical address of this Tx command's header (not MAC header!),
         * within command buffer array. */
        txcmd_phys =
-           pci_map_single(il->pci_dev, &out_cmd->hdr, len, PCI_DMA_TODEVICE);
+           pci_map_single(il->pci_dev, &out_cmd->hdr, firstlen,
+                          PCI_DMA_TODEVICE);
        if (unlikely(pci_dma_mapping_error(il->pci_dev, txcmd_phys)))
                goto drop_unlock;
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
         * if any (802.11 null frames have no payload). */
-       len = skb->len - hdr_len;
-       if (len) {
+       secondlen = skb->len - hdr_len;
+       if (secondlen > 0) {
                phys_addr =
-                   pci_map_single(il->pci_dev, skb->data + hdr_len, len,
+                   pci_map_single(il->pci_dev, skb->data + hdr_len, secondlen,
                                   PCI_DMA_TODEVICE);
                if (unlikely(pci_dma_mapping_error(il->pci_dev, phys_addr)))
                        goto drop_unlock;
@@ -611,12 +613,12 @@ il3945_tx_skb(struct il_priv *il,
 
        /* Add buffer containing Tx command and MAC(!) header to TFD's
         * first entry */
-       il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, len, 1, 0);
+       il->ops->txq_attach_buf_to_tfd(il, txq, txcmd_phys, firstlen, 1, 0);
        dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       dma_unmap_len_set(out_meta, len, len);
-       if (len)
-               il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, len, 0,
-                                              U32_PAD(len));
+       dma_unmap_len_set(out_meta, len, firstlen);
+       if (secondlen > 0)
+               il->ops->txq_attach_buf_to_tfd(il, txq, phys_addr, secondlen, 0,
+                                              U32_PAD(secondlen));
 
        if (!ieee80211_has_morefrags(hdr->frame_control)) {
                txq->need_update = 1;
index e8324b5..6c7493c 100644 (file)
@@ -2152,7 +2152,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,
        int rate_idx;
        int i;
        u32 rate;
-       u8 use_green = il4965_rs_use_green(il, sta);
+       u8 use_green;
        u8 active_tbl = 0;
        u8 valid_tx_ant;
        struct il_station_priv *sta_priv;
@@ -2160,6 +2160,7 @@ il4965_rs_initialize_lq(struct il_priv *il, struct ieee80211_conf *conf,
        if (!sta || !lq_sta)
                return;
 
+       use_green = il4965_rs_use_green(il, sta);
        sta_priv = (void *)sta->drv_priv;
 
        i = lq_sta->last_txrate_idx;
index 86ea5f4..44ca0e5 100644 (file)
@@ -1261,6 +1261,15 @@ int iwl_dvm_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                return -EIO;
        }
 
+       /*
+        * This can happen upon FW ASSERT: we clear the STATUS_FW_ERROR flag
+        * in iwl_down but cancel the workers only later.
+        */
+       if (!priv->ucode_loaded) {
+               IWL_ERR(priv, "Fw not loaded - dropping CMD: %x\n", cmd->id);
+               return -EIO;
+       }
+
        /*
         * Synchronous commands from this op-mode must hold
         * the mutex, this ensures we don't try to send two
index 23be948..a82b6b3 100644 (file)
@@ -1419,6 +1419,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->mutex);
 
+       if (changes & BSS_CHANGED_IDLE && bss_conf->idle) {
+               /*
+                * If we go idle, then clearly no "passive-no-rx"
+                * workaround is needed any more, this is a reset.
+                */
+               iwlagn_lift_passive_no_rx(priv);
+       }
+
        if (unlikely(!iwl_is_ready(priv))) {
                IWL_DEBUG_MAC80211(priv, "leave - not ready\n");
                mutex_unlock(&priv->mutex);
@@ -1450,16 +1458,6 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        priv->timestamp = bss_conf->sync_tsf;
                        ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
                } else {
-                       /*
-                        * If we disassociate while there are pending
-                        * frames, just wake up the queues and let the
-                        * frames "escape" ... This shouldn't really
-                        * be happening to start with, but we should
-                        * not get stuck in this case either since it
-                        * can happen if userspace gets confused.
-                        */
-                       iwlagn_lift_passive_no_rx(priv);
-
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
                        if (ctx->ctxid == IWL_RXON_CTX_BSS)
index 6aec2df..d1a670d 100644 (file)
@@ -1192,7 +1192,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                        memset(&info->status, 0, sizeof(info->status));
 
                        if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
-                           iwl_is_associated_ctx(ctx) && ctx->vif &&
+                           ctx->vif &&
                            ctx->vif->type == NL80211_IFTYPE_STATION) {
                                /* block and stop all queues */
                                priv->passive_no_rx = true;
index 736fe9b..1a4ac92 100644 (file)
@@ -367,6 +367,8 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
                return -EIO;
        }
 
+       priv->ucode_loaded = true;
+
        if (ucode_type != IWL_UCODE_WOWLAN) {
                /* delay a bit to give rfkill time to run */
                msleep(5);
@@ -380,8 +382,6 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
                return ret;
        }
 
-       priv->ucode_loaded = true;
-
        return 0;
 }
 
index 17bedc5..12c4f31 100644 (file)
@@ -475,6 +475,10 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
 
        /* If platform's RF_KILL switch is NOT set to KILL */
        hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans_pcie->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans_pcie->status);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
        if (hw_rfkill && !run_in_rfkill)
                return -ERFKILL;
@@ -641,6 +645,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
 
 static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        bool hw_rfkill;
        int err;
 
@@ -656,6 +661,10 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
        iwl_enable_rfkill_int(trans);
 
        hw_rfkill = iwl_is_rfkill_set(trans);
+       if (hw_rfkill)
+               set_bit(STATUS_RFKILL, &trans_pcie->status);
+       else
+               clear_bit(STATUS_RFKILL, &trans_pcie->status);
        iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 
        return 0;
@@ -694,6 +703,10 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
                 * op_mode.
                 */
                hw_rfkill = iwl_is_rfkill_set(trans);
+               if (hw_rfkill)
+                       set_bit(STATUS_RFKILL, &trans_pcie->status);
+               else
+                       clear_bit(STATUS_RFKILL, &trans_pcie->status);
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
        }
 }
index 8595c16..cb5c679 100644 (file)
@@ -1264,7 +1264,7 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
        for (i = 0; i < IWL_MAX_CMD_TBS_PER_TFD; i++) {
                int copy = 0;
 
-               if (!cmd->len)
+               if (!cmd->len[i])
                        continue;
 
                /* need at least IWL_HCMD_SCRATCHBUF_SIZE copied */
index a44023a..8aaf56a 100644 (file)
@@ -1892,7 +1892,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
                }
        }
 
-       for (i = 0; i < request->n_channels; i++) {
+       for (i = 0; i < min_t(u32, request->n_channels,
+                             MWIFIEX_USER_SCAN_CHAN_MAX); i++) {
                chan = request->channels[i];
                priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
                priv->user_scan_cfg->chan_list[i].radio_type = chan->band;
index 20a6c55..b5c8b96 100644 (file)
@@ -157,6 +157,20 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
                return -1;
        }
 
+       cmd_code = le16_to_cpu(host_cmd->command);
+       cmd_size = le16_to_cpu(host_cmd->size);
+
+       if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET &&
+           cmd_code != HostCmd_CMD_FUNC_SHUTDOWN &&
+           cmd_code != HostCmd_CMD_FUNC_INIT) {
+               dev_err(adapter->dev,
+                       "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
+                       cmd_code);
+               mwifiex_complete_cmd(adapter, cmd_node);
+               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+               return -1;
+       }
+
        /* Set command sequence number */
        adapter->seq_num++;
        host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
@@ -168,9 +182,6 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
        adapter->curr_cmd = cmd_node;
        spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
 
-       cmd_code = le16_to_cpu(host_cmd->command);
-       cmd_size = le16_to_cpu(host_cmd->size);
-
        /* Adjust skb length */
        if (cmd_node->cmd_skb->len > cmd_size)
                /*
@@ -484,8 +495,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
 
        ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
                                     data_buf);
-       if (!ret)
-               ret = mwifiex_wait_queue_complete(adapter);
 
        return ret;
 }
@@ -588,9 +597,10 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
        if (cmd_no == HostCmd_CMD_802_11_SCAN) {
                mwifiex_queue_scan_cmd(priv, cmd_node);
        } else {
-               adapter->cmd_queued = cmd_node;
                mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
                queue_work(adapter->workqueue, &adapter->main_work);
+               if (cmd_node->wait_q_enabled)
+                       ret = mwifiex_wait_queue_complete(adapter, cmd_node);
        }
 
        return ret;
index e38aa9b..0ff4c37 100644 (file)
@@ -709,6 +709,14 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
                return ret;
        }
 
+       /* cancel current command */
+       if (adapter->curr_cmd) {
+               dev_warn(adapter->dev, "curr_cmd is still in processing\n");
+               del_timer(&adapter->cmd_timer);
+               mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+               adapter->curr_cmd = NULL;
+       }
+
        /* shut down mwifiex */
        dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
 
index 553adfb..7035ade 100644 (file)
@@ -723,7 +723,6 @@ struct mwifiex_adapter {
        u16 cmd_wait_q_required;
        struct mwifiex_wait_queue cmd_wait_q;
        u8 scan_wait_q_woken;
-       struct cmd_ctrl_node *cmd_queued;
        spinlock_t queue_lock;          /* lock for tx queues */
        struct completion fw_load;
        u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
@@ -1018,7 +1017,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
                        struct mwifiex_multicast_list *mcast_list);
 int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
                            struct net_device *dev);
-int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
+                               struct cmd_ctrl_node *cmd_queued);
 int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                      struct cfg80211_ssid *req_ssid);
 int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
index 5c395e2..feb2046 100644 (file)
@@ -1508,6 +1508,7 @@ static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
                }
                memcpy(adapter->upld_buf, skb->data,
                       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
+               skb_push(skb, INTF_HEADER_LEN);
                if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
                                           PCI_DMA_FROMDEVICE))
                        return -1;
index bb60c27..d215b4d 100644 (file)
@@ -1388,10 +1388,13 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
                        list_del(&cmd_node->list);
                        spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
                                               flags);
-                       adapter->cmd_queued = cmd_node;
                        mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
                                                        true);
                        queue_work(adapter->workqueue, &adapter->main_work);
+
+                       /* Perform internal scan synchronously */
+                       if (!priv->scan_request)
+                               mwifiex_wait_queue_complete(adapter, cmd_node);
                } else {
                        spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
                                               flags);
@@ -1946,9 +1949,6 @@ int mwifiex_request_scan(struct mwifiex_private *priv,
                /* Normal scan */
                ret = mwifiex_scan_networks(priv, NULL);
 
-       if (!ret)
-               ret = mwifiex_wait_queue_complete(priv->adapter);
-
        up(&priv->async_sem);
 
        return ret;
index 9f33c92..13100f8 100644 (file)
@@ -54,16 +54,10 @@ int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
  * This function waits on a cmd wait queue. It also cancels the pending
  * request after waking up, in case of errors.
  */
-int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter,
+                               struct cmd_ctrl_node *cmd_queued)
 {
        int status;
-       struct cmd_ctrl_node *cmd_queued;
-
-       if (!adapter->cmd_queued)
-               return 0;
-
-       cmd_queued = adapter->cmd_queued;
-       adapter->cmd_queued = NULL;
 
        dev_dbg(adapter->dev, "cmd pending\n");
        atomic_inc(&adapter->cmd_pending);
index 156b527..5847d6d 100644 (file)
@@ -851,6 +851,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,
        if (unlikely(!_urb)) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
                         "Can't allocate urb. Drop skb!\n");
+               kfree_skb(skb);
                return;
        }
        _rtl_submit_tx_urb(hw, _urb);
index eef38cf..ca33ae1 100644 (file)
@@ -22,7 +22,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/gpio.h>
-#include <linux/mei_bus.h>
+#include <linux/mei_cl_bus.h>
 
 #include <linux/nfc.h>
 #include <net/nfc/hci.h>
@@ -32,9 +32,6 @@
 
 #define MICROREAD_DRIVER_NAME "microread"
 
-#define MICROREAD_UUID UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, 0x94, \
-                              0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
-
 struct mei_nfc_hdr {
        u8 cmd;
        u8 status;
@@ -48,7 +45,7 @@ struct mei_nfc_hdr {
 #define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
 
 struct microread_mei_phy {
-       struct mei_device *mei_device;
+       struct mei_cl_device *device;
        struct nfc_hci_dev *hdev;
 
        int powered;
@@ -105,14 +102,14 @@ static int microread_mei_write(void *phy_id, struct sk_buff *skb)
 
        MEI_DUMP_SKB_OUT("mei frame sent", skb);
 
-       r = mei_send(phy->device, skb->data, skb->len);
+       r = mei_cl_send(phy->device, skb->data, skb->len);
        if (r > 0)
                r = 0;
 
        return r;
 }
 
-static void microread_event_cb(struct mei_device *device, u32 events,
+static void microread_event_cb(struct mei_cl_device *device, u32 events,
                               void *context)
 {
        struct microread_mei_phy *phy = context;
@@ -120,7 +117,7 @@ static void microread_event_cb(struct mei_device *device, u32 events,
        if (phy->hard_fault != 0)
                return;
 
-       if (events & BIT(MEI_EVENT_RX)) {
+       if (events & BIT(MEI_CL_EVENT_RX)) {
                struct sk_buff *skb;
                int reply_size;
 
@@ -128,7 +125,7 @@ static void microread_event_cb(struct mei_device *device, u32 events,
                if (!skb)
                        return;
 
-               reply_size = mei_recv(device, skb->data, MEI_NFC_MAX_READ);
+               reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
                if (reply_size < MEI_NFC_HEADER_SIZE) {
                        kfree(skb);
                        return;
@@ -149,8 +146,8 @@ static struct nfc_phy_ops mei_phy_ops = {
        .disable = microread_mei_disable,
 };
 
-static int microread_mei_probe(struct mei_device *device,
-                              const struct mei_id *id)
+static int microread_mei_probe(struct mei_cl_device *device,
+                              const struct mei_cl_device_id *id)
 {
        struct microread_mei_phy *phy;
        int r;
@@ -164,9 +161,9 @@ static int microread_mei_probe(struct mei_device *device,
        }
 
        phy->device = device;
-       mei_set_clientdata(device, phy);
+       mei_cl_set_drvdata(device, phy);
 
-       r = mei_register_event_cb(device, microread_event_cb, phy);
+       r = mei_cl_register_event_cb(device, microread_event_cb, phy);
        if (r) {
                pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
                goto err_out;
@@ -186,9 +183,9 @@ err_out:
        return r;
 }
 
-static int microread_mei_remove(struct mei_device *device)
+static int microread_mei_remove(struct mei_cl_device *device)
 {
-       struct microread_mei_phy *phy = mei_get_clientdata(device);
+       struct microread_mei_phy *phy = mei_cl_get_drvdata(device);
 
        pr_info("Removing microread\n");
 
@@ -202,16 +199,15 @@ static int microread_mei_remove(struct mei_device *device)
        return 0;
 }
 
-static struct mei_id microread_mei_tbl[] = {
-       { MICROREAD_DRIVER_NAME, MICROREAD_UUID },
+static struct mei_cl_device_id microread_mei_tbl[] = {
+       { MICROREAD_DRIVER_NAME },
 
        /* required last entry */
        { }
 };
-
 MODULE_DEVICE_TABLE(mei, microread_mei_tbl);
 
-static struct mei_driver microread_driver = {
+static struct mei_cl_driver microread_driver = {
        .id_table = microread_mei_tbl,
        .name = MICROREAD_DRIVER_NAME,
 
@@ -225,7 +221,7 @@ static int microread_mei_init(void)
 
        pr_debug(DRIVER_DESC ": %s\n", __func__);
 
-       r = mei_driver_register(&microread_driver);
+       r = mei_cl_driver_register(&microread_driver);
        if (r) {
                pr_err(MICROREAD_DRIVER_NAME ": driver registration failed\n");
                return r;
@@ -236,7 +232,7 @@ static int microread_mei_init(void)
 
 static void microread_mei_exit(void)
 {
-       mei_driver_unregister(&microread_driver);
+       mei_cl_driver_unregister(&microread_driver);
 }
 
 module_init(microread_mei_init);
index dee5ddd..5147c21 100644 (file)
@@ -53,14 +53,15 @@ static void pci_acpi_wake_dev(acpi_handle handle, u32 event, void *context)
                return;
        }
 
-       if (!pci_dev->pm_cap || !pci_dev->pme_support
-            || pci_check_pme_status(pci_dev)) {
-               if (pci_dev->pme_poll)
-                       pci_dev->pme_poll = false;
+       /* Clear PME Status if set. */
+       if (pci_dev->pme_support)
+               pci_check_pme_status(pci_dev);
 
-               pci_wakeup_event(pci_dev);
-               pm_runtime_resume(&pci_dev->dev);
-       }
+       if (pci_dev->pme_poll)
+               pci_dev->pme_poll = false;
+
+       pci_wakeup_event(pci_dev);
+       pm_runtime_resume(&pci_dev->dev);
 
        if (pci_dev->subordinate)
                pci_pme_wakeup_bus(pci_dev->subordinate);
index 1fa1e48..79277fb 100644 (file)
@@ -390,9 +390,10 @@ static void pci_device_shutdown(struct device *dev)
 
        /*
         * Turn off Bus Master bit on the device to tell it to not
-        * continue to do DMA
+        * continue to do DMA. Don't touch devices in D3cold or unknown states.
         */
-       pci_clear_master(pci_dev);
+       if (pci_dev->current_state <= PCI_D3hot)
+               pci_clear_master(pci_dev);
 }
 
 #ifdef CONFIG_PM
index 08c243a..ed4d094 100644 (file)
@@ -184,14 +184,6 @@ static const struct dev_pm_ops pcie_portdrv_pm_ops = {
 #define PCIE_PORTDRV_PM_OPS    NULL
 #endif /* !PM */
 
-/*
- * PCIe port runtime suspend is broken for some chipsets, so use a
- * black list to disable runtime PM for these chipsets.
- */
-static const struct pci_device_id port_runtime_pm_black_list[] = {
-       { /* end: all zeroes */ }
-};
-
 /*
  * pcie_portdrv_probe - Probe PCI-Express port devices
  * @dev: PCI-Express port device being probed
@@ -225,16 +217,11 @@ static int pcie_portdrv_probe(struct pci_dev *dev,
         * it by default.
         */
        dev->d3cold_allowed = false;
-       if (!pci_match_id(port_runtime_pm_black_list, dev))
-               pm_runtime_put_noidle(&dev->dev);
-
        return 0;
 }
 
 static void pcie_portdrv_remove(struct pci_dev *dev)
 {
-       if (!pci_match_id(port_runtime_pm_black_list, dev))
-               pm_runtime_get_noresume(&dev->dev);
        pcie_port_device_remove(dev);
        pci_disable_device(dev);
 }
index b41ac77..c5d0a08 100644 (file)
@@ -100,27 +100,6 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
        return min((size_t)(image - rom), size);
 }
 
-static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size)
-{
-       struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
-       loff_t start;
-
-       /* assign the ROM an address if it doesn't have one */
-       if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE))
-               return 0;
-       start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
-       *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
-
-       if (*size == 0)
-               return 0;
-
-       /* Enable ROM space decodes */
-       if (pci_enable_rom(pdev))
-               return 0;
-
-       return start;
-}
-
 /**
  * pci_map_rom - map a PCI ROM to kernel space
  * @pdev: pointer to pci device struct
@@ -135,7 +114,7 @@ static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size)
 void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
 {
        struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
-       loff_t start = 0;
+       loff_t start;
        void __iomem *rom;
 
        /*
@@ -154,21 +133,21 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
                        return (void __iomem *)(unsigned long)
                                pci_resource_start(pdev, PCI_ROM_RESOURCE);
                } else {
-                       start = pci_find_rom(pdev, size);
-               }
-       }
+                       /* assign the ROM an address if it doesn't have one */
+                       if (res->parent == NULL &&
+                           pci_assign_resource(pdev,PCI_ROM_RESOURCE))
+                               return NULL;
+                       start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
+                       *size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
+                       if (*size == 0)
+                               return NULL;
 
-       /*
-        * Some devices may provide ROMs via a source other than the BAR
-        */
-       if (!start && pdev->rom && pdev->romlen) {
-               *size = pdev->romlen;
-               return phys_to_virt(pdev->rom);
+                       /* Enable ROM space decodes */
+                       if (pci_enable_rom(pdev))
+                               return NULL;
+               }
        }
 
-       if (!start)
-               return NULL;
-
        rom = ioremap(start, *size);
        if (!rom) {
                /* restore enable if ioremap fails */
@@ -202,8 +181,7 @@ void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom)
        if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY))
                return;
 
-       if (!pdev->rom || !pdev->romlen)
-               iounmap(rom);
+       iounmap(rom);
 
        /* Disable again before continuing, leave enabled if pci=rom */
        if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW)))
@@ -227,7 +205,24 @@ void pci_cleanup_rom(struct pci_dev *pdev)
        }
 }
 
+/**
+ * pci_platform_rom - provides a pointer to any ROM image provided by the
+ * platform
+ * @pdev: pointer to pci device struct
+ * @size: pointer to receive size of pci window over ROM
+ */
+void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size)
+{
+       if (pdev->rom && pdev->romlen) {
+               *size = pdev->romlen;
+               return phys_to_virt((phys_addr_t)pdev->rom);
+       }
+
+       return NULL;
+}
+
 EXPORT_SYMBOL(pci_map_rom);
 EXPORT_SYMBOL(pci_unmap_rom);
 EXPORT_SYMBOL_GPL(pci_enable_rom);
 EXPORT_SYMBOL_GPL(pci_disable_rom);
+EXPORT_SYMBOL(pci_platform_rom);
index c689c04..2d2f0a4 100644 (file)
@@ -620,7 +620,7 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
 
                /* special soc specific control */
                if (ctrl->mpp_get || ctrl->mpp_set) {
-                       if (!ctrl->name || !ctrl->mpp_set || !ctrl->mpp_set) {
+                       if (!ctrl->name || !ctrl->mpp_get || !ctrl->mpp_set) {
                                dev_err(&pdev->dev, "wrong soc control info\n");
                                return -EINVAL;
                        }
index ac8d382..d611ecf 100644 (file)
@@ -622,7 +622,7 @@ static const struct file_operations pinconf_dbg_pinname_fops = {
 static int pinconf_dbg_state_print(struct seq_file *s, void *d)
 {
        if (strlen(dbg_state_name))
-               seq_printf(s, "%s\n", dbg_pinname);
+               seq_printf(s, "%s\n", dbg_state_name);
        else
                seq_printf(s, "No pin state set\n");
        return 0;
index e3ed8cb..bfda73d 100644 (file)
@@ -90,7 +90,7 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot,
  * pin config.
  */
 
-#ifdef CONFIG_GENERIC_PINCONF
+#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS)
 
 void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
                              struct seq_file *s, unsigned pin);
index caecdd3..c542a97 100644 (file)
@@ -422,7 +422,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
        }
 
        /* check if pin use AlternateFunction register */
-       if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED))
+       if ((af.alt_bit1 == UNUSED) && (af.alt_bit2 == UNUSED))
                return mode;
        /*
         * if pin GPIOSEL bit is set and pin supports alternate function,
index 1a00658..bd83c8b 100644 (file)
@@ -194,6 +194,11 @@ static const char *pin_free(struct pinctrl_dev *pctldev, int pin,
        }
 
        if (!gpio_range) {
+               /*
+                * A pin should not be freed more times than allocated.
+                */
+               if (WARN_ON(!desc->mux_usecount))
+                       return NULL;
                desc->mux_usecount--;
                if (desc->mux_usecount)
                        return NULL;
index 0a9f27e..434ebc3 100644 (file)
@@ -44,7 +44,6 @@ static DECLARE_COMPLETION(at91_rtc_updated);
 static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
 static void __iomem *at91_rtc_regs;
 static int irq;
-static u32 at91_rtc_imr;
 
 /*
  * Decode time/date into rtc_time structure
@@ -109,11 +108,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
        cr = at91_rtc_read(AT91_RTC_CR);
        at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
 
-       at91_rtc_imr |= AT91_RTC_ACKUPD;
        at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
        wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
-       at91_rtc_imr &= ~AT91_RTC_ACKUPD;
 
        at91_rtc_write(AT91_RTC_TIMR,
                          bin2bcd(tm->tm_sec) << 0
@@ -145,7 +142,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
        tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
        tm->tm_year = at91_alarm_year - 1900;
 
-       alrm->enabled = (at91_rtc_imr & AT91_RTC_ALARM)
+       alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
                        ? 1 : 0;
 
        dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
@@ -171,7 +168,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        tm.tm_sec = alrm->time.tm_sec;
 
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
-       at91_rtc_imr &= ~AT91_RTC_ALARM;
        at91_rtc_write(AT91_RTC_TIMALR,
                  bin2bcd(tm.tm_sec) << 0
                | bin2bcd(tm.tm_min) << 8
@@ -184,7 +180,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        if (alrm->enabled) {
                at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
-               at91_rtc_imr |= AT91_RTC_ALARM;
                at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
        }
 
@@ -201,12 +196,9 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
 
        if (enabled) {
                at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
-               at91_rtc_imr |= AT91_RTC_ALARM;
                at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
-       } else {
+       } else
                at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
-               at91_rtc_imr &= ~AT91_RTC_ALARM;
-       }
 
        return 0;
 }
@@ -215,10 +207,12 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
  */
 static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
 {
+       unsigned long imr = at91_rtc_read(AT91_RTC_IMR);
+
        seq_printf(seq, "update_IRQ\t: %s\n",
-                       (at91_rtc_imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+                       (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
        seq_printf(seq, "periodic_IRQ\t: %s\n",
-                       (at91_rtc_imr & AT91_RTC_SECEV) ? "yes" : "no");
+                       (imr & AT91_RTC_SECEV) ? "yes" : "no");
 
        return 0;
 }
@@ -233,7 +227,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
        unsigned int rtsr;
        unsigned long events = 0;
 
-       rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_imr;
+       rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR);
        if (rtsr) {             /* this interrupt is shared!  Is it ours? */
                if (rtsr & AT91_RTC_ALARM)
                        events |= (RTC_AF | RTC_IRQF);
@@ -297,7 +291,6 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
                                        AT91_RTC_SECEV | AT91_RTC_TIMEV |
                                        AT91_RTC_CALEV);
-       at91_rtc_imr = 0;
 
        ret = request_irq(irq, at91_rtc_interrupt,
                                IRQF_SHARED,
@@ -336,7 +329,6 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
        at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
                                        AT91_RTC_SECEV | AT91_RTC_TIMEV |
                                        AT91_RTC_CALEV);
-       at91_rtc_imr = 0;
        free_irq(irq, pdev);
 
        rtc_device_unregister(rtc);
@@ -349,35 +341,31 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
 
 /* AT91RM9200 RTC Power management control */
 
-static u32 at91_rtc_bkpimr;
-
+static u32 at91_rtc_imr;
 
 static int at91_rtc_suspend(struct device *dev)
 {
        /* this IRQ is shared with DBGU and other hardware which isn't
         * necessarily doing PM like we are...
         */
-       at91_rtc_bkpimr = at91_rtc_imr & (AT91_RTC_ALARM|AT91_RTC_SECEV);
-       if (at91_rtc_bkpimr) {
-               if (device_may_wakeup(dev)) {
+       at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR)
+                       & (AT91_RTC_ALARM|AT91_RTC_SECEV);
+       if (at91_rtc_imr) {
+               if (device_may_wakeup(dev))
                        enable_irq_wake(irq);
-               } else {
-                       at91_rtc_write(AT91_RTC_IDR, at91_rtc_bkpimr);
-                       at91_rtc_imr &= ~at91_rtc_bkpimr;
-               }
-}
+               else
+                       at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr);
+       }
        return 0;
 }
 
 static int at91_rtc_resume(struct device *dev)
 {
-       if (at91_rtc_bkpimr) {
-               if (device_may_wakeup(dev)) {
+       if (at91_rtc_imr) {
+               if (device_may_wakeup(dev))
                        disable_irq_wake(irq);
-               } else {
-                       at91_rtc_imr |= at91_rtc_bkpimr;
-                       at91_rtc_write(AT91_RTC_IER, at91_rtc_bkpimr);
-               }
+               else
+                       at91_rtc_write(AT91_RTC_IER, at91_rtc_imr);
        }
        return 0;
 }
index 5f940b6..da1945e 100644 (file)
@@ -64,6 +64,7 @@
 #define        AT91_RTC_SCCR           0x1c                    /* Status Clear Command Register */
 #define        AT91_RTC_IER            0x20                    /* Interrupt Enable Register */
 #define        AT91_RTC_IDR            0x24                    /* Interrupt Disable Register */
+#define        AT91_RTC_IMR            0x28                    /* Interrupt Mask Register */
 
 #define        AT91_RTC_VER            0x2c                    /* Valid Entry Register */
 #define                AT91_RTC_NVTIM          (1 <<  0)               /* Non valid Time */
index 5ac9c93..e9b9c83 100644 (file)
@@ -307,7 +307,7 @@ static void scm_blk_handle_error(struct scm_request *scmrq)
        case EQC_WR_PROHIBIT:
                spin_lock_irqsave(&bdev->lock, flags);
                if (bdev->state != SCM_WR_PROHIBIT)
-                       pr_info("%lu: Write access to the SCM increment is suspended\n",
+                       pr_info("%lx: Write access to the SCM increment is suspended\n",
                                (unsigned long) bdev->scmdev->address);
                bdev->state = SCM_WR_PROHIBIT;
                spin_unlock_irqrestore(&bdev->lock, flags);
@@ -445,7 +445,7 @@ void scm_blk_set_available(struct scm_blk_dev *bdev)
 
        spin_lock_irqsave(&bdev->lock, flags);
        if (bdev->state == SCM_WR_PROHIBIT)
-               pr_info("%lu: Write access to the SCM increment is restored\n",
+               pr_info("%lx: Write access to the SCM increment is restored\n",
                        (unsigned long) bdev->scmdev->address);
        bdev->state = SCM_OPER;
        spin_unlock_irqrestore(&bdev->lock, flags);
@@ -463,12 +463,15 @@ static int __init scm_blk_init(void)
                goto out;
 
        scm_major = ret;
-       if (scm_alloc_rqs(nr_requests))
+       ret = scm_alloc_rqs(nr_requests);
+       if (ret)
                goto out_unreg;
 
        scm_debug = debug_register("scm_log", 16, 1, 16);
-       if (!scm_debug)
+       if (!scm_debug) {
+               ret = -ENOMEM;
                goto out_free;
+       }
 
        debug_register_view(scm_debug, &debug_hex_ascii_view);
        debug_set_level(scm_debug, 2);
index 5f6180d..c98cf52 100644 (file)
@@ -19,7 +19,7 @@ static void scm_notify(struct scm_device *scmdev, enum scm_event event)
 
        switch (event) {
        case SCM_CHANGE:
-               pr_info("%lu: The capabilities of the SCM increment changed\n",
+               pr_info("%lx: The capabilities of the SCM increment changed\n",
                        (unsigned long) scmdev->address);
                SCM_LOG(2, "State changed");
                SCM_LOG_STATE(2, scmdev);
index b907dba..cee69da 100644 (file)
@@ -915,7 +915,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
        int i, rc;
 
        /* Check if the tty3270 is already there. */
-       view = raw3270_find_view(&tty3270_fn, tty->index);
+       view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR);
        if (!IS_ERR(view)) {
                tp = container_of(view, struct tty3270, view);
                tty->driver_data = tp;
@@ -927,15 +927,16 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
                tp->inattr = TF_INPUT;
                return tty_port_install(&tp->port, driver, tty);
        }
-       if (tty3270_max_index < tty->index)
-               tty3270_max_index = tty->index;
+       if (tty3270_max_index < tty->index + 1)
+               tty3270_max_index = tty->index + 1;
 
        /* Allocate tty3270 structure on first open. */
        tp = tty3270_alloc_view();
        if (IS_ERR(tp))
                return PTR_ERR(tp);
 
-       rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index);
+       rc = raw3270_add_view(&tp->view, &tty3270_fn,
+                             tty->index + RAW3270_FIRSTMINOR);
        if (rc) {
                tty3270_free_view(tp);
                return rc;
@@ -1846,12 +1847,12 @@ static const struct tty_operations tty3270_ops = {
 
 void tty3270_create_cb(int minor)
 {
-       tty_register_device(tty3270_driver, minor, NULL);
+       tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
 }
 
 void tty3270_destroy_cb(int minor)
 {
-       tty_unregister_device(tty3270_driver, minor);
+       tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
 }
 
 struct raw3270_notifier tty3270_notifier =
@@ -1884,7 +1885,8 @@ static int __init tty3270_init(void)
        driver->driver_name = "tty3270";
        driver->name = "3270/tty";
        driver->major = IBM_TTY3270_MAJOR;
-       driver->minor_start = 0;
+       driver->minor_start = RAW3270_FIRSTMINOR;
+       driver->name_base = RAW3270_FIRSTMINOR;
        driver->type = TTY_DRIVER_TYPE_SYSTEM;
        driver->subtype = SYSTEM_TYPE_TTY;
        driver->init_termios = tty_std_termios;
index 2daf4b0..90bc7bd 100644 (file)
@@ -940,6 +940,7 @@ static int bnx2fc_libfc_config(struct fc_lport *lport)
        fc_exch_init(lport);
        fc_rport_init(lport);
        fc_disc_init(lport);
+       fc_disc_config(lport, lport);
        return 0;
 }
 
@@ -2133,6 +2134,7 @@ static int _bnx2fc_create(struct net_device *netdev,
        }
 
        ctlr = bnx2fc_to_ctlr(interface);
+       cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
        interface->vlan_id = vlan_id;
 
        interface->timer_work_queue =
@@ -2143,7 +2145,7 @@ static int _bnx2fc_create(struct net_device *netdev,
                goto ifput_err;
        }
 
-       lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0);
+       lport = bnx2fc_if_create(interface, &cdev->dev, 0);
        if (!lport) {
                printk(KERN_ERR PFX "Failed to create interface (%s)\n",
                        netdev->name);
@@ -2159,8 +2161,6 @@ static int _bnx2fc_create(struct net_device *netdev,
        /* Make this master N_port */
        ctlr->lp = lport;
 
-       cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
-
        if (link_state == BNX2FC_CREATE_LINK_UP)
                cdev->enabled = FCOE_CTLR_ENABLED;
        else
index b5d92fc..9bfdc9a 100644 (file)
@@ -490,7 +490,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
 {
        struct net_device *netdev = fcoe->netdev;
        struct fcoe_ctlr *fip = fcoe_to_ctlr(fcoe);
-       struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
 
        rtnl_lock();
        if (!fcoe->removed)
@@ -501,7 +500,6 @@ static void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
        /* tear-down the FCoE controller */
        fcoe_ctlr_destroy(fip);
        scsi_host_put(fip->lp->host);
-       fcoe_ctlr_device_delete(ctlr_dev);
        dev_put(netdev);
        module_put(THIS_MODULE);
 }
@@ -2194,6 +2192,8 @@ out_nodev:
  */
 static void fcoe_destroy_work(struct work_struct *work)
 {
+       struct fcoe_ctlr_device *cdev;
+       struct fcoe_ctlr *ctlr;
        struct fcoe_port *port;
        struct fcoe_interface *fcoe;
        struct Scsi_Host *shost;
@@ -2224,10 +2224,15 @@ static void fcoe_destroy_work(struct work_struct *work)
        mutex_lock(&fcoe_config_mutex);
 
        fcoe = port->priv;
+       ctlr = fcoe_to_ctlr(fcoe);
+       cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
+
        fcoe_if_destroy(port->lport);
        fcoe_interface_cleanup(fcoe);
 
        mutex_unlock(&fcoe_config_mutex);
+
+       fcoe_ctlr_device_delete(cdev);
 }
 
 /**
@@ -2335,7 +2340,9 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
                rc = -EIO;
                rtnl_unlock();
                fcoe_interface_cleanup(fcoe);
-               goto out_nortnl;
+               mutex_unlock(&fcoe_config_mutex);
+               fcoe_ctlr_device_delete(ctlr_dev);
+               goto out;
        }
 
        /* Make this the "master" N_Port */
@@ -2375,8 +2382,8 @@ static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
 
 out_nodev:
        rtnl_unlock();
-out_nortnl:
        mutex_unlock(&fcoe_config_mutex);
+out:
        return rc;
 }
 
index 08c3bc3..a762472 100644 (file)
@@ -2814,6 +2814,47 @@ unlock:
                fc_lport_set_local_id(fip->lp, new_port_id);
 }
 
+/**
+ * fcoe_ctlr_mode_set() - Set or reset the ctlr's mode
+ * @lport: The local port to be (re)configured
+ * @fip:   The FCoE controller whose mode is changing
+ * @fip_mode: The new fip mode
+ *
+ * Note that the we shouldn't be changing the libfc discovery settings
+ * (fc_disc_config) while an lport is going through the libfc state
+ * machine. The mode can only be changed when a fcoe_ctlr device is
+ * disabled, so that should ensure that this routine is only called
+ * when nothing is happening.
+ */
+void fcoe_ctlr_mode_set(struct fc_lport *lport, struct fcoe_ctlr *fip,
+                       enum fip_state fip_mode)
+{
+       void *priv;
+
+       WARN_ON(lport->state != LPORT_ST_RESET &&
+               lport->state != LPORT_ST_DISABLED);
+
+       if (fip_mode == FIP_MODE_VN2VN) {
+               lport->rport_priv_size = sizeof(struct fcoe_rport);
+               lport->point_to_multipoint = 1;
+               lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
+               lport->tt.disc_start = fcoe_ctlr_disc_start;
+               lport->tt.disc_stop = fcoe_ctlr_disc_stop;
+               lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
+               priv = fip;
+       } else {
+               lport->rport_priv_size = 0;
+               lport->point_to_multipoint = 0;
+               lport->tt.disc_recv_req = NULL;
+               lport->tt.disc_start = NULL;
+               lport->tt.disc_stop = NULL;
+               lport->tt.disc_stop_final = NULL;
+               priv = lport;
+       }
+
+       fc_disc_config(lport, priv);
+}
+
 /**
  * fcoe_libfc_config() - Sets up libfc related properties for local port
  * @lport:    The local port to configure libfc for
@@ -2833,21 +2874,9 @@ int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip,
        fc_exch_init(lport);
        fc_elsct_init(lport);
        fc_lport_init(lport);
-       if (fip->mode == FIP_MODE_VN2VN)
-               lport->rport_priv_size = sizeof(struct fcoe_rport);
        fc_rport_init(lport);
-       if (fip->mode == FIP_MODE_VN2VN) {
-               lport->point_to_multipoint = 1;
-               lport->tt.disc_recv_req = fcoe_ctlr_disc_recv;
-               lport->tt.disc_start = fcoe_ctlr_disc_start;
-               lport->tt.disc_stop = fcoe_ctlr_disc_stop;
-               lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final;
-               mutex_init(&lport->disc.disc_mutex);
-               INIT_LIST_HEAD(&lport->disc.rports);
-               lport->disc.priv = fip;
-       } else {
-               fc_disc_init(lport);
-       }
+       fc_disc_init(lport);
+       fcoe_ctlr_mode_set(lport, fip, fip->mode);
        return 0;
 }
 EXPORT_SYMBOL_GPL(fcoe_libfc_config);
@@ -2875,6 +2904,7 @@ EXPORT_SYMBOL(fcoe_fcf_get_selected);
 void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
 {
        struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
+       struct fc_lport *lport = ctlr->lp;
 
        mutex_lock(&ctlr->ctlr_mutex);
        switch (ctlr_dev->mode) {
@@ -2888,5 +2918,7 @@ void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
        }
 
        mutex_unlock(&ctlr->ctlr_mutex);
+
+       fcoe_ctlr_mode_set(lport, ctlr, ctlr->mode);
 }
 EXPORT_SYMBOL(fcoe_ctlr_set_fip_mode);
index 8e561e6..880a906 100644 (file)
@@ -712,12 +712,13 @@ static void fc_disc_stop_final(struct fc_lport *lport)
 }
 
 /**
- * fc_disc_init() - Initialize the discovery layer for a local port
- * @lport: The local port that needs the discovery layer to be initialized
+ * fc_disc_config() - Configure the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be configured
+ * @priv: Private data structre for users of the discovery layer
  */
-int fc_disc_init(struct fc_lport *lport)
+void fc_disc_config(struct fc_lport *lport, void *priv)
 {
-       struct fc_disc *disc;
+       struct fc_disc *disc = &lport->disc;
 
        if (!lport->tt.disc_start)
                lport->tt.disc_start = fc_disc_start;
@@ -732,12 +733,21 @@ int fc_disc_init(struct fc_lport *lport)
                lport->tt.disc_recv_req = fc_disc_recv_req;
 
        disc = &lport->disc;
+
+       disc->priv = priv;
+}
+EXPORT_SYMBOL(fc_disc_config);
+
+/**
+ * fc_disc_init() - Initialize the discovery layer for a local port
+ * @lport: The local port that needs the discovery layer to be initialized
+ */
+void fc_disc_init(struct fc_lport *lport)
+{
+       struct fc_disc *disc = &lport->disc;
+
        INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout);
        mutex_init(&disc->disc_mutex);
        INIT_LIST_HEAD(&disc->rports);
-
-       disc->priv = lport;
-
-       return 0;
 }
 EXPORT_SYMBOL(fc_disc_init);
index f80eee7..2be0de9 100644 (file)
@@ -55,6 +55,7 @@ comment "SPI Master Controller Drivers"
 
 config SPI_ALTERA
        tristate "Altera SPI Controller"
+       depends on GENERIC_HARDIRQS
        select SPI_BITBANG
        help
          This is the driver for the Altera SPI Controller.
@@ -310,7 +311,7 @@ config SPI_PXA2XX_DMA
 
 config SPI_PXA2XX
        tristate "PXA2xx SSP SPI master"
-       depends on ARCH_PXA || PCI || ACPI
+       depends on (ARCH_PXA || PCI || ACPI) && GENERIC_HARDIRQS
        select PXA_SSP if ARCH_PXA
        help
          This enables using a PXA2xx or Sodaville SSP port as a SPI master
index 9578af7..d7df435 100644 (file)
@@ -152,7 +152,6 @@ static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
 static int bcm63xx_spi_setup(struct spi_device *spi)
 {
        struct bcm63xx_spi *bs;
-       int ret;
 
        bs = spi_master_get_devdata(spi->master);
 
@@ -490,7 +489,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
        default:
                dev_err(dev, "unsupported MSG_CTL width: %d\n",
                         bs->msg_ctl_width);
-               goto out_clk_disable;
+               goto out_err;
        }
 
        /* Initialize hardware */
index 89480b2..3e490ee 100644 (file)
@@ -164,7 +164,7 @@ static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
 
                for (i = count; i > 0; i--) {
                        data = tx_buf ? *tx_buf++ : 0;
-                       if (len == EOFBYTE)
+                       if (len == EOFBYTE && t->cs_change)
                                setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
                        out_8(&fifo->txdata_8, data);
                        len--;
index 90b27a3..8104138 100644 (file)
@@ -1168,7 +1168,6 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
 
        master->dev.parent = &pdev->dev;
        master->dev.of_node = pdev->dev.of_node;
-       ACPI_HANDLE_SET(&master->dev, ACPI_HANDLE(&pdev->dev));
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
 
index e862ab8..4188b2f 100644 (file)
@@ -994,25 +994,30 @@ static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
 {
        struct s3c64xx_spi_driver_data *sdd = data;
        struct spi_master *spi = sdd->master;
-       unsigned int val;
+       unsigned int val, clr = 0;
 
-       val = readl(sdd->regs + S3C64XX_SPI_PENDING_CLR);
+       val = readl(sdd->regs + S3C64XX_SPI_STATUS);
 
-       val &= S3C64XX_SPI_PND_RX_OVERRUN_CLR |
-               S3C64XX_SPI_PND_RX_UNDERRUN_CLR |
-               S3C64XX_SPI_PND_TX_OVERRUN_CLR |
-               S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
-
-       writel(val, sdd->regs + S3C64XX_SPI_PENDING_CLR);
-
-       if (val & S3C64XX_SPI_PND_RX_OVERRUN_CLR)
+       if (val & S3C64XX_SPI_ST_RX_OVERRUN_ERR) {
+               clr = S3C64XX_SPI_PND_RX_OVERRUN_CLR;
                dev_err(&spi->dev, "RX overrun\n");
-       if (val & S3C64XX_SPI_PND_RX_UNDERRUN_CLR)
+       }
+       if (val & S3C64XX_SPI_ST_RX_UNDERRUN_ERR) {
+               clr |= S3C64XX_SPI_PND_RX_UNDERRUN_CLR;
                dev_err(&spi->dev, "RX underrun\n");
-       if (val & S3C64XX_SPI_PND_TX_OVERRUN_CLR)
+       }
+       if (val & S3C64XX_SPI_ST_TX_OVERRUN_ERR) {
+               clr |= S3C64XX_SPI_PND_TX_OVERRUN_CLR;
                dev_err(&spi->dev, "TX overrun\n");
-       if (val & S3C64XX_SPI_PND_TX_UNDERRUN_CLR)
+       }
+       if (val & S3C64XX_SPI_ST_TX_UNDERRUN_ERR) {
+               clr |= S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
                dev_err(&spi->dev, "TX underrun\n");
+       }
+
+       /* Clear the pending irq by setting and then clearing it */
+       writel(clr, sdd->regs + S3C64XX_SPI_PENDING_CLR);
+       writel(0, sdd->regs + S3C64XX_SPI_PENDING_CLR);
 
        return IRQ_HANDLED;
 }
@@ -1036,9 +1041,13 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
        writel(0, regs + S3C64XX_SPI_MODE_CFG);
        writel(0, regs + S3C64XX_SPI_PACKET_CNT);
 
-       /* Clear any irq pending bits */
-       writel(readl(regs + S3C64XX_SPI_PENDING_CLR),
-                               regs + S3C64XX_SPI_PENDING_CLR);
+       /* Clear any irq pending bits, should set and clear the bits */
+       val = S3C64XX_SPI_PND_RX_OVERRUN_CLR |
+               S3C64XX_SPI_PND_RX_UNDERRUN_CLR |
+               S3C64XX_SPI_PND_TX_OVERRUN_CLR |
+               S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
+       writel(val, regs + S3C64XX_SPI_PENDING_CLR);
+       writel(0, regs + S3C64XX_SPI_PENDING_CLR);
 
        writel(0, regs + S3C64XX_SPI_SWAP_CFG);
 
index b8698b3..a829563 100644 (file)
@@ -858,21 +858,6 @@ static int tegra_slink_setup(struct spi_device *spi)
        return 0;
 }
 
-static int tegra_slink_prepare_transfer(struct spi_master *master)
-{
-       struct tegra_slink_data *tspi = spi_master_get_devdata(master);
-
-       return pm_runtime_get_sync(tspi->dev);
-}
-
-static int tegra_slink_unprepare_transfer(struct spi_master *master)
-{
-       struct tegra_slink_data *tspi = spi_master_get_devdata(master);
-
-       pm_runtime_put(tspi->dev);
-       return 0;
-}
-
 static int tegra_slink_transfer_one_message(struct spi_master *master,
                        struct spi_message *msg)
 {
@@ -885,6 +870,12 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
 
        msg->status = 0;
        msg->actual_length = 0;
+       ret = pm_runtime_get_sync(tspi->dev);
+       if (ret < 0) {
+               dev_err(tspi->dev, "runtime get failed: %d\n", ret);
+               goto done;
+       }
+
        single_xfer = list_is_singular(&msg->transfers);
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
                INIT_COMPLETION(tspi->xfer_completion);
@@ -921,6 +912,8 @@ static int tegra_slink_transfer_one_message(struct spi_master *master,
 exit:
        tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND);
        tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2);
+       pm_runtime_put(tspi->dev);
+done:
        msg->status = ret;
        spi_finalize_current_message(master);
        return ret;
@@ -1148,9 +1141,7 @@ static int tegra_slink_probe(struct platform_device *pdev)
        /* the spi->mode bits understood by this driver: */
        master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
        master->setup = tegra_slink_setup;
-       master->prepare_transfer_hardware = tegra_slink_prepare_transfer;
        master->transfer_one_message = tegra_slink_transfer_one_message;
-       master->unprepare_transfer_hardware = tegra_slink_unprepare_transfer;
        master->num_chipselect = MAX_CHIP_SELECT;
        master->bus_num = -1;
 
index f996c60..004b10f 100644 (file)
@@ -543,17 +543,16 @@ static void spi_pump_messages(struct kthread_work *work)
        /* Lock queue and check for queue work */
        spin_lock_irqsave(&master->queue_lock, flags);
        if (list_empty(&master->queue) || !master->running) {
-               if (master->busy && master->unprepare_transfer_hardware) {
-                       ret = master->unprepare_transfer_hardware(master);
-                       if (ret) {
-                               spin_unlock_irqrestore(&master->queue_lock, flags);
-                               dev_err(&master->dev,
-                                       "failed to unprepare transfer hardware\n");
-                               return;
-                       }
+               if (!master->busy) {
+                       spin_unlock_irqrestore(&master->queue_lock, flags);
+                       return;
                }
                master->busy = false;
                spin_unlock_irqrestore(&master->queue_lock, flags);
+               if (master->unprepare_transfer_hardware &&
+                   master->unprepare_transfer_hardware(master))
+                       dev_err(&master->dev,
+                               "failed to unprepare transfer hardware\n");
                return;
        }
 
@@ -984,7 +983,7 @@ static void acpi_register_spi_devices(struct spi_master *master)
        acpi_status status;
        acpi_handle handle;
 
-       handle = ACPI_HANDLE(&master->dev);
+       handle = ACPI_HANDLE(master->dev.parent);
        if (!handle)
                return;
 
index 81a1fe6..71a73ec 100644 (file)
@@ -1483,7 +1483,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
        case TRIG_NONE:
                /*  continous acquisition */
                devpriv->ai_continous = 1;
-               devpriv->ai_sample_count = 0;
+               devpriv->ai_sample_count = 1;
                break;
        }
 
index 7358270..5c37145 100644 (file)
@@ -15,7 +15,7 @@ config RAMSTER
        depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE=y
        depends on NET
        # must ensure struct page is 8-byte aligned
-       select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT
+       select HAVE_ALIGNED_STRUCT_PAGE if !64BIT
        default n
        help
          RAMster allows RAM on other machines in a cluster to be utilized
index 2030b60..3243ea7 100644 (file)
@@ -1139,8 +1139,10 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb)
                return ret;
 
        ret = target_check_reservation(cmd);
-       if (ret)
+       if (ret) {
+               cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT;
                return ret;
+       }
 
        ret = dev->transport->parse_cdb(cmd);
        if (ret)
similarity index 99%
rename from drivers/tty/serial/8250/8250.c
rename to drivers/tty/serial/8250/8250_core.c
index cf6a538..35f9c96 100644 (file)
@@ -3418,6 +3418,7 @@ MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
 #endif
 MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
 
+#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
 #ifndef MODULE
 /* This module was renamed to 8250_core in 3.7.  Keep the old "8250" name
  * working as well for the module options so we don't break people.  We
@@ -3432,7 +3433,7 @@ MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
 static void __used s8250_options(void)
 {
 #undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250."
+#define MODULE_PARAM_PREFIX "8250_core."
 
        module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
        module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
@@ -3444,5 +3445,6 @@ static void __used s8250_options(void)
 #endif
 }
 #else
-MODULE_ALIAS("8250");
+MODULE_ALIAS("8250_core");
+#endif
 #endif
index aa76825..26e3a97 100644 (file)
@@ -1554,6 +1554,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
 #define PCI_VENDOR_ID_WCH              0x4348
+#define PCI_DEVICE_ID_WCH_CH352_2S     0x3253
 #define PCI_DEVICE_ID_WCH_CH353_4S     0x3453
 #define PCI_DEVICE_ID_WCH_CH353_2S1PF  0x5046
 #define PCI_DEVICE_ID_WCH_CH353_2S1P   0x7053
@@ -2172,6 +2173,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_wch_ch353_setup,
        },
+       /* WCH CH352 2S card (16550 clone) */
+       {
+               .vendor         = PCI_VENDOR_ID_WCH,
+               .device         = PCI_DEVICE_ID_WCH_CH352_2S,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_wch_ch353_setup,
+       },
        /*
         * ASIX devices with FIFO bug
         */
@@ -4870,6 +4879,10 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_b0_bt_2_115200 },
 
+       {       PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH352_2S,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0, pbn_b0_bt_2_115200 },
+
        /*
         * Commtech, Inc. Fastcom adapters
         */
index 2ef9537..80fe91e 100644 (file)
@@ -33,6 +33,23 @@ config SERIAL_8250
          Most people will say Y or M here, so that they can use serial mice,
          modems and similar devices connecting to the standard serial ports.
 
+config SERIAL_8250_DEPRECATED_OPTIONS
+       bool "Support 8250_core.* kernel options (DEPRECATED)"
+       depends on SERIAL_8250
+       default y
+       ---help---
+         In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to
+         accept kernel parameters in both forms like 8250_core.nr_uarts=4 and
+         8250.nr_uarts=4. We now renamed the module back to 8250, but if
+         anybody noticed in 3.7 and changed their userspace we still have to
+         keep the 8350_core.* options around until they revert the changes
+         they already did.
+
+         If 8250 is built as a module, this adds 8250_core alias instead. 
+
+         If you did not notice yet and/or you have userspace from pre-3.7, it
+         is safe (and recommended) to say N here.
+
 config SERIAL_8250_PNP
        bool "8250/16550 PNP device support" if EXPERT
        depends on SERIAL_8250 && PNP
index a23838a..36d68d0 100644 (file)
@@ -2,10 +2,10 @@
 # Makefile for the 8250 serial device drivers.
 #
 
-obj-$(CONFIG_SERIAL_8250)              += 8250_core.o
-8250_core-y                            := 8250.o
-8250_core-$(CONFIG_SERIAL_8250_PNP)    += 8250_pnp.o
-8250_core-$(CONFIG_SERIAL_8250_DMA)    += 8250_dma.o
+obj-$(CONFIG_SERIAL_8250)              += 8250.o
+8250-y                                 := 8250_core.o
+8250-$(CONFIG_SERIAL_8250_PNP)         += 8250_pnp.o
+8250-$(CONFIG_SERIAL_8250_DMA)         += 8250_dma.o
 obj-$(CONFIG_SERIAL_8250_GSC)          += 8250_gsc.o
 obj-$(CONFIG_SERIAL_8250_PCI)          += 8250_pci.o
 obj-$(CONFIG_SERIAL_8250_HP300)                += 8250_hp300.o
index d4a7c24..3467462 100644 (file)
@@ -158,7 +158,7 @@ struct atmel_uart_port {
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
-static unsigned long atmel_ports_in_use;
+static DECLARE_BITMAP(atmel_ports_in_use, ATMEL_MAX_UART);
 
 #ifdef SUPPORT_SYSRQ
 static struct console atmel_console;
@@ -1769,15 +1769,14 @@ static int atmel_serial_probe(struct platform_device *pdev)
        if (ret < 0)
                /* port id not found in platform data nor device-tree aliases:
                 * auto-enumerate it */
-               ret = find_first_zero_bit(&atmel_ports_in_use,
-                               sizeof(atmel_ports_in_use));
+               ret = find_first_zero_bit(atmel_ports_in_use, ATMEL_MAX_UART);
 
-       if (ret > ATMEL_MAX_UART) {
+       if (ret >= ATMEL_MAX_UART) {
                ret = -ENODEV;
                goto err;
        }
 
-       if (test_and_set_bit(ret, &atmel_ports_in_use)) {
+       if (test_and_set_bit(ret, atmel_ports_in_use)) {
                /* port already in use */
                ret = -EBUSY;
                goto err;
@@ -1857,7 +1856,7 @@ static int atmel_serial_remove(struct platform_device *pdev)
 
        /* "port" is allocated statically, so we shouldn't free it */
 
-       clear_bit(port->line, &atmel_ports_in_use);
+       clear_bit(port->line, atmel_ports_in_use);
 
        clk_put(atmel_port->clk);
 
index ba451c7..f36bbba 100644 (file)
@@ -578,6 +578,8 @@ static int xuartps_startup(struct uart_port *port)
        /* Receive Timeout register is enabled with value of 10 */
        xuartps_writel(10, XUARTPS_RXTOUT_OFFSET);
 
+       /* Clear out any pending interrupts before enabling them */
+       xuartps_writel(xuartps_readl(XUARTPS_ISR_OFFSET), XUARTPS_ISR_OFFSET);
 
        /* Set the Interrupt Registers with desired interrupts */
        xuartps_writel(XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_PARITY |
index e4ca345..d7799de 100644 (file)
@@ -93,7 +93,7 @@ vcs_poll_data_free(struct vcs_poll_data *poll)
 static struct vcs_poll_data *
 vcs_poll_data_get(struct file *file)
 {
-       struct vcs_poll_data *poll = file->private_data;
+       struct vcs_poll_data *poll = file->private_data, *kill = NULL;
 
        if (poll)
                return poll;
@@ -122,10 +122,12 @@ vcs_poll_data_get(struct file *file)
                file->private_data = poll;
        } else {
                /* someone else raced ahead of us */
-               vcs_poll_data_free(poll);
+               kill = poll;
                poll = file->private_data;
        }
        spin_unlock(&file->f_lock);
+       if (kill)
+               vcs_poll_data_free(kill);
 
        return poll;
 }
index 99b34a3..f9ec44c 100644 (file)
@@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
 
+int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+       if (!hcd->driver->find_raw_port_number)
+               return port1;
+
+       return hcd->driver->find_raw_port_number(hcd, port1);
+}
+
 static int usb_hcd_request_irqs(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags)
 {
index 797f9d5..65d4e55 100644 (file)
@@ -67,7 +67,6 @@ static void usb_port_device_release(struct device *dev)
 {
        struct usb_port *port_dev = to_usb_port(dev);
 
-       dev_pm_qos_hide_flags(dev);
        kfree(port_dev);
 }
 
index b6f4bad..255c144 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/acpi.h>
 #include <linux/pci.h>
+#include <linux/usb/hcd.h>
 #include <acpi/acpi_bus.h>
 
 #include "usb.h"
@@ -188,8 +189,13 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)
                 * connected to.
                 */
                if (!udev->parent) {
-                       *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
+                       struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+                       int raw_port_num;
+
+                       raw_port_num = usb_hcd_find_raw_port_number(hcd,
                                port_num);
+                       *handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev),
+                               raw_port_num);
                        if (!*handle)
                                return -ENODEV;
                } else {
index 5a0c541..c7525b1 100644 (file)
@@ -145,6 +145,7 @@ config USB_LPC32XX
        tristate "LPC32XX USB Peripheral Controller"
        depends on ARCH_LPC32XX
        select USB_ISP1301
+       select USB_OTG_UTILS
        help
           This option selects the USB device controller in the LPC32xx SoC.
 
index b476daf..010f686 100644 (file)
@@ -1214,6 +1214,7 @@ itd_urb_transaction (
 
                memset (itd, 0, sizeof *itd);
                itd->itd_dma = itd_dma;
+               itd->frame = 9999;              /* an invalid value */
                list_add (&itd->itd_list, &sched->td_list);
        }
        spin_unlock_irqrestore (&ehci->lock, flags);
@@ -1915,6 +1916,7 @@ sitd_urb_transaction (
 
                memset (sitd, 0, sizeof *sitd);
                sitd->sitd_dma = sitd_dma;
+               sitd->frame = 9999;             /* an invalid value */
                list_add (&sitd->sitd_list, &iso_sched->td_list);
        }
 
index 35616ff..6dc238c 100644 (file)
@@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
  * is attached to (or the roothub port its ancestor hub is attached to).  All we
  * know is the index of that port under either the USB 2.0 or the USB 3.0
  * roothub, but that doesn't give us the real index into the HW port status
- * registers.  Scan through the xHCI roothub port array, looking for the Nth
- * entry of the correct port speed.  Return the port number of that entry.
+ * registers. Call xhci_find_raw_port_number() to get real index.
  */
 static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,
                struct usb_device *udev)
 {
        struct usb_device *top_dev;
-       unsigned int num_similar_speed_ports;
-       unsigned int faked_port_num;
-       int i;
+       struct usb_hcd *hcd;
+
+       if (udev->speed == USB_SPEED_SUPER)
+               hcd = xhci->shared_hcd;
+       else
+               hcd = xhci->main_hcd;
 
        for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
                        top_dev = top_dev->parent)
                /* Found device below root hub */;
-       faked_port_num = top_dev->portnum;
-       for (i = 0, num_similar_speed_ports = 0;
-                       i < HCS_MAX_PORTS(xhci->hcs_params1); i++) {
-               u8 port_speed = xhci->port_array[i];
-
-               /*
-                * Skip ports that don't have known speeds, or have duplicate
-                * Extended Capabilities port speed entries.
-                */
-               if (port_speed == 0 || port_speed == DUPLICATE_ENTRY)
-                       continue;
 
-               /*
-                * USB 3.0 ports are always under a USB 3.0 hub.  USB 2.0 and
-                * 1.1 ports are under the USB 2.0 hub.  If the port speed
-                * matches the device speed, it's a similar speed port.
-                */
-               if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER))
-                       num_similar_speed_ports++;
-               if (num_similar_speed_ports == faked_port_num)
-                       /* Roothub ports are numbered from 1 to N */
-                       return i+1;
-       }
-       return 0;
+       return  xhci_find_raw_port_number(hcd, top_dev->portnum);
 }
 
 /* Setup an xHCI virtual device for a Set Address command */
index af259e0..1a30c38 100644 (file)
@@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
        .set_usb2_hw_lpm =      xhci_set_usb2_hardware_lpm,
        .enable_usb3_lpm_timeout =      xhci_enable_usb3_lpm_timeout,
        .disable_usb3_lpm_timeout =     xhci_disable_usb3_lpm_timeout,
+       .find_raw_port_number = xhci_find_raw_port_number,
 };
 
 /*-------------------------------------------------------------------------*/
index 8828754..1969c00 100644 (file)
@@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci,
        max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
        if ((port_id <= 0) || (port_id > max_ports)) {
                xhci_warn(xhci, "Invalid port id %d\n", port_id);
-               bogus_port_status = true;
-               goto cleanup;
+               inc_deq(xhci, xhci->event_ring);
+               return;
        }
 
        /* Figure out which usb_hcd this port is attached to:
         * is it a USB 3.0 port or a USB 2.0/1.1 port?
         */
        major_revision = xhci->port_array[port_id - 1];
+
+       /* Find the right roothub. */
+       hcd = xhci_to_hcd(xhci);
+       if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
+               hcd = xhci->shared_hcd;
+
        if (major_revision == 0) {
                xhci_warn(xhci, "Event for port %u not in "
                                "Extended Capabilities, ignoring.\n",
@@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci,
         * into the index into the ports on the correct split roothub, and the
         * correct bus_state structure.
         */
-       /* Find the right roothub. */
-       hcd = xhci_to_hcd(xhci);
-       if ((major_revision == 0x03) != (hcd->speed == HCD_USB3))
-               hcd = xhci->shared_hcd;
        bus_state = &xhci->bus_state[hcd_index(hcd)];
        if (hcd->speed == HCD_USB3)
                port_array = xhci->usb3_ports;
@@ -2027,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                if (event_trb != ep_ring->dequeue &&
                                event_trb != td->last_trb)
                        td->urb->actual_length =
-                               td->urb->transfer_buffer_length
-                               TRB_LEN(le32_to_cpu(event->transfer_len));
+                               td->urb->transfer_buffer_length -
+                               EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
                else
                        td->urb->actual_length = 0;
 
@@ -2060,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                /* Maybe the event was for the data stage? */
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
-                               TRB_LEN(le32_to_cpu(event->transfer_len));
+                               EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
                        xhci_dbg(xhci, "Waiting for status "
                                        "stage event\n");
                        return 0;
@@ -2096,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
        /* handle completion code */
        switch (trb_comp_code) {
        case COMP_SUCCESS:
-               if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
+               if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {
                        frame->status = 0;
                        break;
                }
@@ -2141,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
                }
                len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
-                       TRB_LEN(le32_to_cpu(event->transfer_len));
+                       EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
 
                if (trb_comp_code != COMP_STOP_INVAL) {
                        frame->actual_length = len;
@@ -2199,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
        case COMP_SUCCESS:
                /* Double check that the HW transferred everything. */
                if (event_trb != td->last_trb ||
-                               TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
+                   EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
                        xhci_warn(xhci, "WARN Successful completion "
                                        "on short TX\n");
                        if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
@@ -2227,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                                "%d bytes untransferred\n",
                                td->urb->ep->desc.bEndpointAddress,
                                td->urb->transfer_buffer_length,
-                               TRB_LEN(le32_to_cpu(event->transfer_len)));
+                               EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
        /* Fast path - was this the last TRB in the TD for this URB? */
        if (event_trb == td->last_trb) {
-               if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
+               if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {
                        td->urb->actual_length =
                                td->urb->transfer_buffer_length -
-                               TRB_LEN(le32_to_cpu(event->transfer_len));
+                               EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
                        if (td->urb->transfer_buffer_length <
                                        td->urb->actual_length) {
                                xhci_warn(xhci, "HC gave bad length "
                                                "of %d bytes left\n",
-                                         TRB_LEN(le32_to_cpu(event->transfer_len)));
+                                         EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));
                                td->urb->actual_length = 0;
                                if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
                                        *status = -EREMOTEIO;
@@ -2280,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
                if (trb_comp_code != COMP_STOP_INVAL)
                        td->urb->actual_length +=
                                TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
-                               TRB_LEN(le32_to_cpu(event->transfer_len));
+                               EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));
        }
 
        return finish_td(xhci, td, event_trb, event, ep, status, false);
@@ -2368,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
         * transfer type
         */
        case COMP_SUCCESS:
-               if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
+               if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)
                        break;
                if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
                        trb_comp_code = COMP_SHORT_TX;
@@ -2461,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                 * TD list.
                 */
                if (list_empty(&ep_ring->td_list)) {
-                       xhci_warn(xhci, "WARN Event TRB for slot %d ep %d "
-                                       "with no TDs queued?\n",
-                                 TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
-                                 ep_index);
-                       xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
-                                (le32_to_cpu(event->flags) &
-                                 TRB_TYPE_BITMASK)>>10);
-                       xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
+                       /*
+                        * A stopped endpoint may generate an extra completion
+                        * event if the device was suspended.  Don't print
+                        * warnings.
+                        */
+                       if (!(trb_comp_code == COMP_STOP ||
+                                               trb_comp_code == COMP_STOP_INVAL)) {
+                               xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n",
+                                               TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
+                                               ep_index);
+                               xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
+                                               (le32_to_cpu(event->flags) &
+                                                TRB_TYPE_BITMASK)>>10);
+                               xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
+                       }
                        if (ep->skip) {
                                ep->skip = false;
                                xhci_dbg(xhci, "td_list is empty while skip "
index 849470b..53b8f89 100644 (file)
@@ -3779,6 +3779,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
        return 0;
 }
 
+/*
+ * Transfer the port index into real index in the HW port status
+ * registers. Caculate offset between the port's PORTSC register
+ * and port status base. Divide the number of per port register
+ * to get the real index. The raw port number bases 1.
+ */
+int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       __le32 __iomem *base_addr = &xhci->op_regs->port_status_base;
+       __le32 __iomem *addr;
+       int raw_port;
+
+       if (hcd->speed != HCD_USB3)
+               addr = xhci->usb2_ports[port1 - 1];
+       else
+               addr = xhci->usb3_ports[port1 - 1];
+
+       raw_port = (addr - base_addr)/NUM_PORT_REGS + 1;
+       return raw_port;
+}
+
 #ifdef CONFIG_USB_SUSPEND
 
 /* BESL to HIRD Encoding array for USB2 LPM */
index 2c510e4..6358271 100644 (file)
@@ -972,6 +972,10 @@ struct xhci_transfer_event {
        __le32  flags;
 };
 
+/* Transfer event TRB length bit mask */
+/* bits 0:23 */
+#define        EVENT_TRB_LEN(p)                ((p) & 0xffffff)
+
 /** Transfer Event bit fields **/
 #define        TRB_TO_EP_ID(p) (((p) >> 16) & 0x1f)
 
@@ -1829,6 +1833,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
                char *buf, u16 wLength);
 int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
+int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 #ifdef CONFIG_PM
 int xhci_bus_suspend(struct usb_hcd *hcd);
index 65217a5..9054938 100644 (file)
@@ -38,6 +38,7 @@ config USB_ISP1301
        tristate "NXP ISP1301 USB transceiver support"
        depends on USB || USB_GADGET
        depends on I2C
+       select USB_OTG_UTILS
        help
          Say Y here to add support for the NXP ISP1301 USB transceiver driver.
          This chip is typically used as USB transceiver for USB host, gadget
index d4809d5..9886180 100644 (file)
@@ -640,6 +640,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
        { USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },
        { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
+       { USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
index 9d359e1..e79861e 100644 (file)
 #define CONTEC_VID             0x06CE  /* Vendor ID */
 #define CONTEC_COM1USBH_PID    0x8311  /* COM-1(USB)H */
 
+/*
+ * Mitsubishi Electric Corp. (http://www.meau.com)
+ * Submitted by Konstantin Holoborodko
+ */
+#define MITSUBISHI_VID         0x06D3
+#define MITSUBISHI_FXUSB_PID   0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */
+
 /*
  * Definitions for B&B Electronics products.
  */
index 2e70efa..5d9b178 100644 (file)
@@ -903,6 +903,7 @@ static int usb_serial_probe(struct usb_interface *interface,
                port->port.ops = &serial_port_ops;
                port->serial = serial;
                spin_lock_init(&port->lock);
+               init_waitqueue_head(&port->delta_msr_wait);
                /* Keep this for private driver use for the moment but
                   should probably go away */
                INIT_WORK(&port->work, usb_serial_port_work);
index 43fb11e..2968b49 100644 (file)
@@ -60,6 +60,15 @@ enum {
        VHOST_SCSI_VQ_IO = 2,
 };
 
+/*
+ * VIRTIO_RING_F_EVENT_IDX seems broken. Not sure the bug is in
+ * kernel but disabling it helps.
+ * TODO: debug and remove the workaround.
+ */
+enum {
+       VHOST_SCSI_FEATURES = VHOST_FEATURES & (~VIRTIO_RING_F_EVENT_IDX)
+};
+
 #define VHOST_SCSI_MAX_TARGET  256
 #define VHOST_SCSI_MAX_VQ      128
 
@@ -946,7 +955,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
 
 static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
 {
-       if (features & ~VHOST_FEATURES)
+       if (features & ~VHOST_SCSI_FEATURES)
                return -EOPNOTSUPP;
 
        mutex_lock(&vs->dev.mutex);
@@ -992,7 +1001,7 @@ static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
                        return -EFAULT;
                return 0;
        case VHOST_GET_FEATURES:
-               features = VHOST_FEATURES;
+               features = VHOST_SCSI_FEATURES;
                if (copy_to_user(featurep, &features, sizeof features))
                        return -EFAULT;
                return 0;
index 94ad0f7..7f67099 100644 (file)
@@ -1400,7 +1400,7 @@ int fb_videomode_from_videomode(const struct videomode *vm,
        fbmode->vmode = 0;
        if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
                fbmode->sync |= FB_SYNC_HOR_HIGH_ACT;
-       if (vm->dmt_flags & VESA_DMT_HSYNC_HIGH)
+       if (vm->dmt_flags & VESA_DMT_VSYNC_HIGH)
                fbmode->sync |= FB_SYNC_VERT_HIGH_ACT;
        if (vm->data_flags & DISPLAY_FLAGS_INTERLACED)
                fbmode->vmode |= FB_VMODE_INTERLACED;
index 755556c..45169cb 100644 (file)
@@ -169,6 +169,7 @@ struct mxsfb_info {
        unsigned dotclk_delay;
        const struct mxsfb_devdata *devdata;
        int mapped;
+       u32 sync;
 };
 
 #define mxsfb_is_v3(host) (host->devdata->ipversion == 3)
@@ -456,9 +457,9 @@ static int mxsfb_set_par(struct fb_info *fb_info)
                vdctrl0 |= VDCTRL0_HSYNC_ACT_HIGH;
        if (fb_info->var.sync & FB_SYNC_VERT_HIGH_ACT)
                vdctrl0 |= VDCTRL0_VSYNC_ACT_HIGH;
-       if (fb_info->var.sync & FB_SYNC_DATA_ENABLE_HIGH_ACT)
+       if (host->sync & MXSFB_SYNC_DATA_ENABLE_HIGH_ACT)
                vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
-       if (fb_info->var.sync & FB_SYNC_DOTCLK_FAILING_ACT)
+       if (host->sync & MXSFB_SYNC_DOTCLK_FAILING_ACT)
                vdctrl0 |= VDCTRL0_DOTCLK_ACT_FAILING;
 
        writel(vdctrl0, host->base + LCDC_VDCTRL0);
@@ -861,6 +862,8 @@ static int mxsfb_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&fb_info->modelist);
 
+       host->sync = pdata->sync;
+
        ret = mxsfb_init_fbinfo(host);
        if (ret != 0)
                goto error_init_fb;
index e31f5b3..d40612c 100644 (file)
@@ -32,6 +32,8 @@
 
 #include <linux/omap-dma.h>
 
+#include <mach/hardware.h>
+
 #include "omapfb.h"
 #include "lcdc.h"
 
index 6b66439..048c983 100644 (file)
@@ -63,6 +63,9 @@ struct tpo_td043_device {
        u32 power_on_resume:1;
 };
 
+/* used to pass spi_device from SPI to DSS portion of the driver */
+static struct tpo_td043_device *g_tpo_td043;
+
 static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data)
 {
        struct spi_message      m;
@@ -403,7 +406,7 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev)
 
 static int tpo_td043_probe(struct omap_dss_device *dssdev)
 {
-       struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev);
+       struct tpo_td043_device *tpo_td043 = g_tpo_td043;
        int nreset_gpio = dssdev->reset_gpio;
        int ret = 0;
 
@@ -440,6 +443,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev)
        if (ret)
                dev_warn(&dssdev->dev, "failed to create sysfs files\n");
 
+       dev_set_drvdata(&dssdev->dev, tpo_td043);
+
        return 0;
 
 fail_gpio_req:
@@ -505,6 +510,9 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
                return -ENODEV;
        }
 
+       if (g_tpo_td043 != NULL)
+               return -EBUSY;
+
        spi->bits_per_word = 16;
        spi->mode = SPI_MODE_0;
 
@@ -521,7 +529,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi)
        tpo_td043->spi = spi;
        tpo_td043->nreset_gpio = dssdev->reset_gpio;
        dev_set_drvdata(&spi->dev, tpo_td043);
-       dev_set_drvdata(&dssdev->dev, tpo_td043);
+       g_tpo_td043 = tpo_td043;
 
        omap_dss_register_driver(&tpo_td043_driver);
 
@@ -534,6 +542,7 @@ static int tpo_td043_spi_remove(struct spi_device *spi)
 
        omap_dss_unregister_driver(&tpo_td043_driver);
        kfree(tpo_td043);
+       g_tpo_td043 = NULL;
 
        return 0;
 }
index d7d66ef..7f791ae 100644 (file)
@@ -202,12 +202,10 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
 
 static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
        /* OMAP_DSS_CHANNEL_LCD */
-       OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
-       OMAP_DSS_OUTPUT_DSI1,
+       OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
 
        /* OMAP_DSS_CHANNEL_DIGIT */
-       OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI |
-       OMAP_DSS_OUTPUT_DPI,
+       OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
 
        /* OMAP_DSS_CHANNEL_LCD2 */
        OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
index 63203ac..0264704 100644 (file)
@@ -858,6 +858,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
        tmp = ((mode->xres & 7) << 24) | ((display_h_total & 7) << 16)
            | ((mode->hsync_len & 7) << 8) | (hsync_pos & 7);
        lcdc_write_chan(ch, LDHAJR, tmp);
+       lcdc_write_chan_mirror(ch, LDHAJR, tmp);
 }
 
 static void sh_mobile_lcdc_overlay_setup(struct sh_mobile_lcdc_overlay *ovl)
index b75db01..d428445 100644 (file)
@@ -1973,7 +1973,8 @@ static int uvesafb_init(void)
                        err = -ENOMEM;
 
                if (err) {
-                       platform_device_put(uvesafb_device);
+                       if (uvesafb_device)
+                               platform_device_put(uvesafb_device);
                        platform_driver_unregister(&uvesafb_driver);
                        cn_del_callback(&uvesafb_cn_id);
                        return err;
index 5a32232..67af155 100644 (file)
@@ -182,7 +182,7 @@ config XEN_PRIVCMD
 
 config XEN_STUB
        bool "Xen stub drivers"
-       depends on XEN && X86_64
+       depends on XEN && X86_64 && BROKEN
        default n
        help
          Allow kernel to install stub drivers, to reserve space for Xen drivers,
index d17aa41..aa85881 100644 (file)
@@ -403,11 +403,23 @@ static void unmask_evtchn(int port)
 
        if (unlikely((cpu != cpu_from_evtchn(port))))
                do_hypercall = 1;
-       else
+       else {
+               /*
+                * Need to clear the mask before checking pending to
+                * avoid a race with an event becoming pending.
+                *
+                * EVTCHNOP_unmask will only trigger an upcall if the
+                * mask bit was set, so if a hypercall is needed
+                * remask the event.
+                */
+               sync_clear_bit(port, BM(&s->evtchn_mask[0]));
                evtchn_pending = sync_test_bit(port, BM(&s->evtchn_pending[0]));
 
-       if (unlikely(evtchn_pending && xen_hvm_domain()))
-               do_hypercall = 1;
+               if (unlikely(evtchn_pending && xen_hvm_domain())) {
+                       sync_set_bit(port, BM(&s->evtchn_mask[0]));
+                       do_hypercall = 1;
+               }
+       }
 
        /* Slow path (hypercall) if this is a non-local port or if this is
         * an hvm domain and an event is pending (hvm domains don't have
@@ -418,8 +430,6 @@ static void unmask_evtchn(int port)
        } else {
                struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu);
 
-               sync_clear_bit(port, BM(&s->evtchn_mask[0]));
-
                /*
                 * The following is basically the equivalent of
                 * 'hw_resend_irq'. Just like a real IO-APIC we 'lose
index 0ef7c4d..b04fb64 100644 (file)
@@ -44,7 +44,7 @@ int xen_event_channel_op_compat(int cmd, void *arg)
 }
 EXPORT_SYMBOL_GPL(xen_event_channel_op_compat);
 
-int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
+int xen_physdev_op_compat(int cmd, void *arg)
 {
        struct physdev_op op;
        int rc;
@@ -78,3 +78,4 @@ int HYPERVISOR_physdev_op_compat(int cmd, void *arg)
 
        return rc;
 }
+EXPORT_SYMBOL_GPL(xen_physdev_op_compat);
index f3278a6..90e34ac 100644 (file)
@@ -505,6 +505,9 @@ static int __init xen_acpi_processor_init(void)
 
                pr = per_cpu(processors, i);
                perf = per_cpu_ptr(acpi_perf_data, i);
+               if (!pr)
+                       continue;
+
                pr->performance = perf;
                rc = acpi_processor_get_performance_info(pr);
                if (rc)
index 9204126..a2278ba 100644 (file)
@@ -17,6 +17,7 @@
 #include <xen/events.h>
 #include <asm/xen/pci.h>
 #include <asm/xen/hypervisor.h>
+#include <xen/interface/physdev.h>
 #include "pciback.h"
 #include "conf_space.h"
 #include "conf_space_quirks.h"
@@ -85,37 +86,52 @@ static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
 static void pcistub_device_release(struct kref *kref)
 {
        struct pcistub_device *psdev;
+       struct pci_dev *dev;
        struct xen_pcibk_dev_data *dev_data;
 
        psdev = container_of(kref, struct pcistub_device, kref);
-       dev_data = pci_get_drvdata(psdev->dev);
+       dev = psdev->dev;
+       dev_data = pci_get_drvdata(dev);
 
-       dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
+       dev_dbg(&dev->dev, "pcistub_device_release\n");
 
-       xen_unregister_device_domain_owner(psdev->dev);
+       xen_unregister_device_domain_owner(dev);
 
        /* Call the reset function which does not take lock as this
         * is called from "unbind" which takes a device_lock mutex.
         */
-       __pci_reset_function_locked(psdev->dev);
-       if (pci_load_and_free_saved_state(psdev->dev,
-                                         &dev_data->pci_saved_state)) {
-               dev_dbg(&psdev->dev->dev, "Could not reload PCI state\n");
-       } else
-               pci_restore_state(psdev->dev);
+       __pci_reset_function_locked(dev);
+       if (pci_load_and_free_saved_state(dev, &dev_data->pci_saved_state))
+               dev_dbg(&dev->dev, "Could not reload PCI state\n");
+       else
+               pci_restore_state(dev);
+
+       if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
+               struct physdev_pci_device ppdev = {
+                       .seg = pci_domain_nr(dev->bus),
+                       .bus = dev->bus->number,
+                       .devfn = dev->devfn
+               };
+               int err = HYPERVISOR_physdev_op(PHYSDEVOP_release_msix,
+                                               &ppdev);
+
+               if (err)
+                       dev_warn(&dev->dev, "MSI-X release failed (%d)\n",
+                                err);
+       }
 
        /* Disable the device */
-       xen_pcibk_reset_device(psdev->dev);
+       xen_pcibk_reset_device(dev);
 
        kfree(dev_data);
-       pci_set_drvdata(psdev->dev, NULL);
+       pci_set_drvdata(dev, NULL);
 
        /* Clean-up the device */
-       xen_pcibk_config_free_dyn_fields(psdev->dev);
-       xen_pcibk_config_free_dev(psdev->dev);
+       xen_pcibk_config_free_dyn_fields(dev);
+       xen_pcibk_config_free_dev(dev);
 
-       psdev->dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
-       pci_dev_put(psdev->dev);
+       dev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED;
+       pci_dev_put(dev);
 
        kfree(psdev);
 }
@@ -355,6 +371,19 @@ static int pcistub_init_device(struct pci_dev *dev)
        if (err)
                goto config_release;
 
+       if (pci_find_capability(dev, PCI_CAP_ID_MSIX)) {
+               struct physdev_pci_device ppdev = {
+                       .seg = pci_domain_nr(dev->bus),
+                       .bus = dev->bus->number,
+                       .devfn = dev->devfn
+               };
+
+               err = HYPERVISOR_physdev_op(PHYSDEVOP_prepare_msix, &ppdev);
+               if (err)
+                       dev_err(&dev->dev, "MSI-X preparation failed (%d)\n",
+                               err);
+       }
+
        /* We need the device active to save the state. */
        dev_dbg(&dev->dev, "save state of device\n");
        pci_save_state(dev);
index aea605c..aae187a 100644 (file)
@@ -551,6 +551,7 @@ struct block_device *bdgrab(struct block_device *bdev)
        ihold(bdev->bd_inode);
        return bdev;
 }
+EXPORT_SYMBOL(bdgrab);
 
 long nr_blockdev_pages(void)
 {
index ecd25a1..ca9d8f1 100644 (file)
@@ -651,6 +651,8 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
        if (tree_mod_dont_log(fs_info, NULL))
                return 0;
 
+       __tree_mod_log_free_eb(fs_info, old_root);
+
        ret = tree_mod_alloc(fs_info, flags, &tm);
        if (ret < 0)
                goto out;
@@ -736,7 +738,7 @@ tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq)
 static noinline void
 tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
                     struct extent_buffer *src, unsigned long dst_offset,
-                    unsigned long src_offset, int nr_items)
+                    unsigned long src_offset, int nr_items, int log_removal)
 {
        int ret;
        int i;
@@ -750,10 +752,12 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
        }
 
        for (i = 0; i < nr_items; i++) {
-               ret = tree_mod_log_insert_key_locked(fs_info, src,
-                                                    i + src_offset,
-                                                    MOD_LOG_KEY_REMOVE);
-               BUG_ON(ret < 0);
+               if (log_removal) {
+                       ret = tree_mod_log_insert_key_locked(fs_info, src,
+                                                       i + src_offset,
+                                                       MOD_LOG_KEY_REMOVE);
+                       BUG_ON(ret < 0);
+               }
                ret = tree_mod_log_insert_key_locked(fs_info, dst,
                                                     i + dst_offset,
                                                     MOD_LOG_KEY_ADD);
@@ -927,7 +931,6 @@ static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans,
                        ret = btrfs_dec_ref(trans, root, buf, 1, 1);
                        BUG_ON(ret); /* -ENOMEM */
                }
-               tree_mod_log_free_eb(root->fs_info, buf);
                clean_tree_block(trans, root, buf);
                *last_ref = 1;
        }
@@ -1046,6 +1049,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                btrfs_set_node_ptr_generation(parent, parent_slot,
                                              trans->transid);
                btrfs_mark_buffer_dirty(parent);
+               tree_mod_log_free_eb(root->fs_info, buf);
                btrfs_free_tree_block(trans, root, buf, parent_start,
                                      last_ref);
        }
@@ -1750,7 +1754,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
                        goto enospc;
                }
 
-               tree_mod_log_free_eb(root->fs_info, root->node);
                tree_mod_log_set_root_pointer(root, child);
                rcu_assign_pointer(root->node, child);
 
@@ -2995,7 +2998,7 @@ static int push_node_left(struct btrfs_trans_handle *trans,
                push_items = min(src_nritems - 8, push_items);
 
        tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
-                            push_items);
+                            push_items, 1);
        copy_extent_buffer(dst, src,
                           btrfs_node_key_ptr_offset(dst_nritems),
                           btrfs_node_key_ptr_offset(0),
@@ -3066,7 +3069,7 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
                                      sizeof(struct btrfs_key_ptr));
 
        tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
-                            src_nritems - push_items, push_items);
+                            src_nritems - push_items, push_items, 1);
        copy_extent_buffer(dst, src,
                           btrfs_node_key_ptr_offset(0),
                           btrfs_node_key_ptr_offset(src_nritems - push_items),
@@ -3218,12 +3221,18 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
        int mid;
        int ret;
        u32 c_nritems;
+       int tree_mod_log_removal = 1;
 
        c = path->nodes[level];
        WARN_ON(btrfs_header_generation(c) != trans->transid);
        if (c == root->node) {
                /* trying to split the root, lets make a new one */
                ret = insert_new_root(trans, root, path, level + 1);
+               /*
+                * removal of root nodes has been logged by
+                * tree_mod_log_set_root_pointer due to locking
+                */
+               tree_mod_log_removal = 0;
                if (ret)
                        return ret;
        } else {
@@ -3261,7 +3270,8 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
                            (unsigned long)btrfs_header_chunk_tree_uuid(split),
                            BTRFS_UUID_SIZE);
 
-       tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid);
+       tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid,
+                            tree_mod_log_removal);
        copy_extent_buffer(split, c,
                           btrfs_node_key_ptr_offset(0),
                           btrfs_node_key_ptr_offset(mid),
index 7d84651..6d19a0a 100644 (file)
@@ -1291,6 +1291,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
                                      0, objectid, NULL, 0, 0, 0);
        if (IS_ERR(leaf)) {
                ret = PTR_ERR(leaf);
+               leaf = NULL;
                goto fail;
        }
 
@@ -1334,11 +1335,16 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
 
        btrfs_tree_unlock(leaf);
 
+       return root;
+
 fail:
-       if (ret)
-               return ERR_PTR(ret);
+       if (leaf) {
+               btrfs_tree_unlock(leaf);
+               free_extent_buffer(leaf);
+       }
+       kfree(root);
 
-       return root;
+       return ERR_PTR(ret);
 }
 
 static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
@@ -3253,7 +3259,7 @@ void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
        if (btrfs_root_refs(&root->root_item) == 0)
                synchronize_srcu(&fs_info->subvol_srcu);
 
-       if (fs_info->fs_state & BTRFS_SUPER_FLAG_ERROR) {
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
                btrfs_free_log(NULL, root);
                btrfs_free_log_root_tree(NULL, fs_info);
        }
index 9ac2eca..3d55123 100644 (file)
@@ -257,7 +257,8 @@ static int exclude_super_stripes(struct btrfs_root *root,
                cache->bytes_super += stripe_len;
                ret = add_excluded_extent(root, cache->key.objectid,
                                          stripe_len);
-               BUG_ON(ret); /* -ENOMEM */
+               if (ret)
+                       return ret;
        }
 
        for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
@@ -265,13 +266,17 @@ static int exclude_super_stripes(struct btrfs_root *root,
                ret = btrfs_rmap_block(&root->fs_info->mapping_tree,
                                       cache->key.objectid, bytenr,
                                       0, &logical, &nr, &stripe_len);
-               BUG_ON(ret); /* -ENOMEM */
+               if (ret)
+                       return ret;
 
                while (nr--) {
                        cache->bytes_super += stripe_len;
                        ret = add_excluded_extent(root, logical[nr],
                                                  stripe_len);
-                       BUG_ON(ret); /* -ENOMEM */
+                       if (ret) {
+                               kfree(logical);
+                               return ret;
+                       }
                }
 
                kfree(logical);
@@ -4438,7 +4443,7 @@ static void update_global_block_rsv(struct btrfs_fs_info *fs_info)
        spin_lock(&sinfo->lock);
        spin_lock(&block_rsv->lock);
 
-       block_rsv->size = num_bytes;
+       block_rsv->size = min_t(u64, num_bytes, 512 * 1024 * 1024);
 
        num_bytes = sinfo->bytes_used + sinfo->bytes_pinned +
                    sinfo->bytes_reserved + sinfo->bytes_readonly +
@@ -4793,14 +4798,49 @@ out_fail:
         * If the inodes csum_bytes is the same as the original
         * csum_bytes then we know we haven't raced with any free()ers
         * so we can just reduce our inodes csum bytes and carry on.
-        * Otherwise we have to do the normal free thing to account for
-        * the case that the free side didn't free up its reserve
-        * because of this outstanding reservation.
         */
-       if (BTRFS_I(inode)->csum_bytes == csum_bytes)
+       if (BTRFS_I(inode)->csum_bytes == csum_bytes) {
                calc_csum_metadata_size(inode, num_bytes, 0);
-       else
-               to_free = calc_csum_metadata_size(inode, num_bytes, 0);
+       } else {
+               u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes;
+               u64 bytes;
+
+               /*
+                * This is tricky, but first we need to figure out how much we
+                * free'd from any free-ers that occured during this
+                * reservation, so we reset ->csum_bytes to the csum_bytes
+                * before we dropped our lock, and then call the free for the
+                * number of bytes that were freed while we were trying our
+                * reservation.
+                */
+               bytes = csum_bytes - BTRFS_I(inode)->csum_bytes;
+               BTRFS_I(inode)->csum_bytes = csum_bytes;
+               to_free = calc_csum_metadata_size(inode, bytes, 0);
+
+
+               /*
+                * Now we need to see how much we would have freed had we not
+                * been making this reservation and our ->csum_bytes were not
+                * artificially inflated.
+                */
+               BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes;
+               bytes = csum_bytes - orig_csum_bytes;
+               bytes = calc_csum_metadata_size(inode, bytes, 0);
+
+               /*
+                * Now reset ->csum_bytes to what it should be.  If bytes is
+                * more than to_free then we would have free'd more space had we
+                * not had an artificially high ->csum_bytes, so we need to free
+                * the remainder.  If bytes is the same or less then we don't
+                * need to do anything, the other free-ers did the correct
+                * thing.
+                */
+               BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes;
+               if (bytes > to_free)
+                       to_free = bytes - to_free;
+               else
+                       to_free = 0;
+       }
        spin_unlock(&BTRFS_I(inode)->lock);
        if (dropped)
                to_free += btrfs_calc_trans_metadata_size(root, dropped);
@@ -7947,7 +7987,17 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                 * info has super bytes accounted for, otherwise we'll think
                 * we have more space than we actually do.
                 */
-               exclude_super_stripes(root, cache);
+               ret = exclude_super_stripes(root, cache);
+               if (ret) {
+                       /*
+                        * We may have excluded something, so call this just in
+                        * case.
+                        */
+                       free_excluded_extents(root, cache);
+                       kfree(cache->free_space_ctl);
+                       kfree(cache);
+                       goto error;
+               }
 
                /*
                 * check for two cases, either we are full, and therefore
@@ -8089,7 +8139,17 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        cache->last_byte_to_unpin = (u64)-1;
        cache->cached = BTRFS_CACHE_FINISHED;
-       exclude_super_stripes(root, cache);
+       ret = exclude_super_stripes(root, cache);
+       if (ret) {
+               /*
+                * We may have excluded something, so call this just in
+                * case.
+                */
+               free_excluded_extents(root, cache);
+               kfree(cache->free_space_ctl);
+               kfree(cache);
+               return ret;
+       }
 
        add_new_free_space(cache, root->fs_info, chunk_offset,
                           chunk_offset + size);
index f173c5a..cdee391 100644 (file)
@@ -1257,6 +1257,39 @@ int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end)
                                GFP_NOFS);
 }
 
+int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end)
+{
+       unsigned long index = start >> PAGE_CACHE_SHIFT;
+       unsigned long end_index = end >> PAGE_CACHE_SHIFT;
+       struct page *page;
+
+       while (index <= end_index) {
+               page = find_get_page(inode->i_mapping, index);
+               BUG_ON(!page); /* Pages should be in the extent_io_tree */
+               clear_page_dirty_for_io(page);
+               page_cache_release(page);
+               index++;
+       }
+       return 0;
+}
+
+int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end)
+{
+       unsigned long index = start >> PAGE_CACHE_SHIFT;
+       unsigned long end_index = end >> PAGE_CACHE_SHIFT;
+       struct page *page;
+
+       while (index <= end_index) {
+               page = find_get_page(inode->i_mapping, index);
+               BUG_ON(!page); /* Pages should be in the extent_io_tree */
+               account_page_redirty(page);
+               __set_page_dirty_nobuffers(page);
+               page_cache_release(page);
+               index++;
+       }
+       return 0;
+}
+
 /*
  * helper function to set both pages and extents in the tree writeback
  */
index 6068a19..258c921 100644 (file)
@@ -325,6 +325,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
                      unsigned long *map_len);
 int extent_range_uptodate(struct extent_io_tree *tree,
                          u64 start, u64 end);
+int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
+int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
 int extent_clear_unlock_delalloc(struct inode *inode,
                                struct extent_io_tree *tree,
                                u64 start, u64 end, struct page *locked_page,
index ec16020..c4628a2 100644 (file)
@@ -118,9 +118,11 @@ struct btrfs_csum_item *btrfs_lookup_csum(struct btrfs_trans_handle *trans,
                csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]);
                csums_in_item /= csum_size;
 
-               if (csum_offset >= csums_in_item) {
+               if (csum_offset == csums_in_item) {
                        ret = -EFBIG;
                        goto fail;
+               } else if (csum_offset > csums_in_item) {
+                       goto fail;
                }
        }
        item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item);
@@ -728,7 +730,6 @@ int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans,
                return -ENOMEM;
 
        sector_sum = sums->sums;
-       trans->adding_csums = 1;
 again:
        next_offset = (u64)-1;
        found_next = 0;
@@ -899,7 +900,6 @@ next_sector:
                goto again;
        }
 out:
-       trans->adding_csums = 0;
        btrfs_free_path(path);
        return ret;
 
index 5b4ea5f..ade03e6 100644 (file)
@@ -2142,6 +2142,7 @@ static long btrfs_fallocate(struct file *file, int mode,
 {
        struct inode *inode = file_inode(file);
        struct extent_state *cached_state = NULL;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 cur_offset;
        u64 last_byte;
        u64 alloc_start;
@@ -2169,6 +2170,11 @@ static long btrfs_fallocate(struct file *file, int mode,
        ret = btrfs_check_data_free_space(inode, alloc_end - alloc_start);
        if (ret)
                return ret;
+       if (root->fs_info->quota_enabled) {
+               ret = btrfs_qgroup_reserve(root, alloc_end - alloc_start);
+               if (ret)
+                       goto out_reserve_fail;
+       }
 
        /*
         * wait for ordered IO before we have any locks.  We'll loop again
@@ -2272,6 +2278,9 @@ static long btrfs_fallocate(struct file *file, int mode,
                             &cached_state, GFP_NOFS);
 out:
        mutex_unlock(&inode->i_mutex);
+       if (root->fs_info->quota_enabled)
+               btrfs_qgroup_free(root, alloc_end - alloc_start);
+out_reserve_fail:
        /* Let go of our reservation. */
        btrfs_free_reserved_data_space(inode, alloc_end - alloc_start);
        return ret;
index ca1b767..09c58a3 100644 (file)
@@ -353,6 +353,7 @@ static noinline int compress_file_range(struct inode *inode,
        int i;
        int will_compress;
        int compress_type = root->fs_info->compress_type;
+       int redirty = 0;
 
        /* if this is a small write inside eof, kick off a defrag */
        if ((end - start + 1) < 16 * 1024 &&
@@ -415,6 +416,17 @@ again:
                if (BTRFS_I(inode)->force_compress)
                        compress_type = BTRFS_I(inode)->force_compress;
 
+               /*
+                * we need to call clear_page_dirty_for_io on each
+                * page in the range.  Otherwise applications with the file
+                * mmap'd can wander in and change the page contents while
+                * we are compressing them.
+                *
+                * If the compression fails for any reason, we set the pages
+                * dirty again later on.
+                */
+               extent_range_clear_dirty_for_io(inode, start, end);
+               redirty = 1;
                ret = btrfs_compress_pages(compress_type,
                                           inode->i_mapping, start,
                                           total_compressed, pages,
@@ -554,6 +566,8 @@ cleanup_and_bail_uncompressed:
                        __set_page_dirty_nobuffers(locked_page);
                        /* unlocked later on in the async handlers */
                }
+               if (redirty)
+                       extent_range_redirty_for_io(inode, start, end);
                add_async_extent(async_cow, start, end - start + 1,
                                 0, NULL, 0, BTRFS_COMPRESS_NONE);
                *num_added += 1;
@@ -1743,8 +1757,10 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
        struct btrfs_ordered_sum *sum;
 
        list_for_each_entry(sum, list, list) {
+               trans->adding_csums = 1;
                btrfs_csum_file_blocks(trans,
                       BTRFS_I(inode)->root->fs_info->csum_root, sum);
+               trans->adding_csums = 0;
        }
        return 0;
 }
@@ -3679,11 +3695,9 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
         * 1 for the dir item
         * 1 for the dir index
         * 1 for the inode ref
-        * 1 for the inode ref in the tree log
-        * 2 for the dir entries in the log
         * 1 for the inode
         */
-       trans = btrfs_start_transaction(root, 8);
+       trans = btrfs_start_transaction(root, 5);
        if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
                return trans;
 
@@ -8127,7 +8141,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         * inodes.  So 5 * 2 is 10, plus 1 for the new link, so 11 total items
         * should cover the worst case number of items we'll modify.
         */
-       trans = btrfs_start_transaction(root, 20);
+       trans = btrfs_start_transaction(root, 11);
        if (IS_ERR(trans)) {
                 ret = PTR_ERR(trans);
                 goto out_notrans;
index dc08d77..005c45d 100644 (file)
@@ -557,6 +557,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
        INIT_LIST_HEAD(&splice);
        INIT_LIST_HEAD(&works);
 
+       mutex_lock(&root->fs_info->ordered_operations_mutex);
        spin_lock(&root->fs_info->ordered_extent_lock);
        list_splice_init(&root->fs_info->ordered_extents, &splice);
        while (!list_empty(&splice)) {
@@ -600,6 +601,7 @@ void btrfs_wait_ordered_extents(struct btrfs_root *root, int delay_iput)
 
                cond_resched();
        }
+       mutex_unlock(&root->fs_info->ordered_operations_mutex);
 }
 
 /*
index 5471e47..b44124d 100644 (file)
@@ -1153,7 +1153,7 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
        ret = btrfs_find_all_roots(trans, fs_info, node->bytenr,
                                   sgn > 0 ? node->seq - 1 : node->seq, &roots);
        if (ret < 0)
-               goto out;
+               return ret;
 
        spin_lock(&fs_info->qgroup_lock);
        quota_root = fs_info->quota_root;
@@ -1275,7 +1275,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
        ret = 0;
 unlock:
        spin_unlock(&fs_info->qgroup_lock);
-out:
        ulist_free(roots);
        ulist_free(tmp);
 
index 53c3501..85e072b 100644 (file)
@@ -542,7 +542,6 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
        eb = path->nodes[0];
        ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
        item_size = btrfs_item_size_nr(eb, path->slots[0]);
-       btrfs_release_path(path);
 
        if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
                do {
@@ -558,7 +557,9 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
                                ret < 0 ? -1 : ref_level,
                                ret < 0 ? -1 : ref_root);
                } while (ret != 1);
+               btrfs_release_path(path);
        } else {
+               btrfs_release_path(path);
                swarn.path = path;
                swarn.dev = dev;
                iterate_extent_inodes(fs_info, found_key.objectid,
index f7a8b86..c85e7c6 100644 (file)
@@ -3945,12 +3945,10 @@ static int is_extent_unchanged(struct send_ctx *sctx,
                    found_key.type != key.type) {
                        key.offset += right_len;
                        break;
-               } else {
-                       if (found_key.offset != key.offset + right_len) {
-                               /* Should really not happen */
-                               ret = -EIO;
-                               goto out;
-                       }
+               }
+               if (found_key.offset != key.offset + right_len) {
+                       ret = 0;
+                       goto out;
                }
                key = found_key;
        }
index 5989a92..2854c82 100644 (file)
@@ -4935,7 +4935,18 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
        em = lookup_extent_mapping(em_tree, chunk_start, 1);
        read_unlock(&em_tree->lock);
 
-       BUG_ON(!em || em->start != chunk_start);
+       if (!em) {
+               printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n",
+                      chunk_start);
+               return -EIO;
+       }
+
+       if (em->start != chunk_start) {
+               printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n",
+                      em->start, chunk_start);
+               free_extent_map(em);
+               return -EIO;
+       }
        map = (struct map_lookup *)em->bdev;
 
        length = em->len;
index fbfae00..e8bc342 100644 (file)
@@ -2542,7 +2542,6 @@ static int prepend_path(const struct path *path,
        bool slash = false;
        int error = 0;
 
-       br_read_lock(&vfsmount_lock);
        while (dentry != root->dentry || vfsmnt != root->mnt) {
                struct dentry * parent;
 
@@ -2572,8 +2571,6 @@ static int prepend_path(const struct path *path,
        if (!error && !slash)
                error = prepend(buffer, buflen, "/", 1);
 
-out:
-       br_read_unlock(&vfsmount_lock);
        return error;
 
 global_root:
@@ -2590,7 +2587,7 @@ global_root:
                error = prepend(buffer, buflen, "/", 1);
        if (!error)
                error = is_mounted(vfsmnt) ? 1 : 2;
-       goto out;
+       return error;
 }
 
 /**
@@ -2617,9 +2614,11 @@ char *__d_path(const struct path *path,
        int error;
 
        prepend(&res, &buflen, "\0", 1);
+       br_read_lock(&vfsmount_lock);
        write_seqlock(&rename_lock);
        error = prepend_path(path, root, &res, &buflen);
        write_sequnlock(&rename_lock);
+       br_read_unlock(&vfsmount_lock);
 
        if (error < 0)
                return ERR_PTR(error);
@@ -2636,9 +2635,11 @@ char *d_absolute_path(const struct path *path,
        int error;
 
        prepend(&res, &buflen, "\0", 1);
+       br_read_lock(&vfsmount_lock);
        write_seqlock(&rename_lock);
        error = prepend_path(path, &root, &res, &buflen);
        write_sequnlock(&rename_lock);
+       br_read_unlock(&vfsmount_lock);
 
        if (error > 1)
                error = -EINVAL;
@@ -2702,11 +2703,13 @@ char *d_path(const struct path *path, char *buf, int buflen)
                return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
 
        get_fs_root(current->fs, &root);
+       br_read_lock(&vfsmount_lock);
        write_seqlock(&rename_lock);
        error = path_with_deleted(path, &root, &res, &buflen);
+       write_sequnlock(&rename_lock);
+       br_read_unlock(&vfsmount_lock);
        if (error < 0)
                res = ERR_PTR(error);
-       write_sequnlock(&rename_lock);
        path_put(&root);
        return res;
 }
@@ -2830,6 +2833,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
        get_fs_root_and_pwd(current->fs, &root, &pwd);
 
        error = -ENOENT;
+       br_read_lock(&vfsmount_lock);
        write_seqlock(&rename_lock);
        if (!d_unlinked(pwd.dentry)) {
                unsigned long len;
@@ -2839,6 +2843,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
                prepend(&cwd, &buflen, "\0", 1);
                error = prepend_path(&pwd, &root, &cwd, &buflen);
                write_sequnlock(&rename_lock);
+               br_read_unlock(&vfsmount_lock);
 
                if (error < 0)
                        goto out;
@@ -2859,6 +2864,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
                }
        } else {
                write_sequnlock(&rename_lock);
+               br_read_unlock(&vfsmount_lock);
        }
 
 out:
index 56efcaa..9c6d06d 100644 (file)
@@ -2999,20 +2999,23 @@ static int ext4_split_extent_at(handle_t *handle,
                        if (split_flag & EXT4_EXT_DATA_VALID1) {
                                err = ext4_ext_zeroout(inode, ex2);
                                zero_ex.ee_block = ex2->ee_block;
-                               zero_ex.ee_len = ext4_ext_get_actual_len(ex2);
+                               zero_ex.ee_len = cpu_to_le16(
+                                               ext4_ext_get_actual_len(ex2));
                                ext4_ext_store_pblock(&zero_ex,
                                                      ext4_ext_pblock(ex2));
                        } else {
                                err = ext4_ext_zeroout(inode, ex);
                                zero_ex.ee_block = ex->ee_block;
-                               zero_ex.ee_len = ext4_ext_get_actual_len(ex);
+                               zero_ex.ee_len = cpu_to_le16(
+                                               ext4_ext_get_actual_len(ex));
                                ext4_ext_store_pblock(&zero_ex,
                                                      ext4_ext_pblock(ex));
                        }
                } else {
                        err = ext4_ext_zeroout(inode, &orig_ex);
                        zero_ex.ee_block = orig_ex.ee_block;
-                       zero_ex.ee_len = ext4_ext_get_actual_len(&orig_ex);
+                       zero_ex.ee_len = cpu_to_le16(
+                                               ext4_ext_get_actual_len(&orig_ex));
                        ext4_ext_store_pblock(&zero_ex,
                                              ext4_ext_pblock(&orig_ex));
                }
@@ -3272,7 +3275,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                if (err)
                        goto out;
                zero_ex.ee_block = ex->ee_block;
-               zero_ex.ee_len = ext4_ext_get_actual_len(ex);
+               zero_ex.ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex));
                ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex));
 
                err = ext4_ext_get_access(handle, inode, path + depth);
index b505a14..a041831 100644 (file)
@@ -1539,9 +1539,9 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
                blk = *i_data;
                if (level > 0) {
                        ext4_lblk_t first2;
-                       bh = sb_bread(inode->i_sb, blk);
+                       bh = sb_bread(inode->i_sb, le32_to_cpu(blk));
                        if (!bh) {
-                               EXT4_ERROR_INODE_BLOCK(inode, blk,
+                               EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk),
                                                       "Read failure");
                                return -EIO;
                        }
index 019f45e..d79c2da 100644 (file)
@@ -923,8 +923,11 @@ static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
                cmd = F_SETLK;
                fl->fl_type = F_UNLCK;
        }
-       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+       if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+               if (fl->fl_type == F_UNLCK)
+                       posix_lock_file_wait(file, fl);
                return -EIO;
+       }
        if (IS_GETLK(cmd))
                return dlm_posix_get(ls->ls_dlm, ip->i_no_addr, file, fl);
        else if (fl->fl_type == F_UNLCK)
index 156e42e..5c29216 100644 (file)
@@ -588,6 +588,7 @@ struct lm_lockstruct {
        struct dlm_lksb ls_control_lksb; /* control_lock */
        char ls_control_lvb[GDLM_LVB_SIZE]; /* control_lock lvb */
        struct completion ls_sync_wait; /* {control,mounted}_{lock,unlock} */
+       char *ls_lvb_bits;
 
        spinlock_t ls_recover_spin; /* protects following fields */
        unsigned long ls_recover_flags; /* DFL_ */
index 9802de0..c8423d6 100644 (file)
@@ -483,12 +483,8 @@ static void control_lvb_write(struct lm_lockstruct *ls, uint32_t lvb_gen,
 
 static int all_jid_bits_clear(char *lvb)
 {
-       int i;
-       for (i = JID_BITMAP_OFFSET; i < GDLM_LVB_SIZE; i++) {
-               if (lvb[i])
-                       return 0;
-       }
-       return 1;
+       return !memchr_inv(lvb + JID_BITMAP_OFFSET, 0,
+                       GDLM_LVB_SIZE - JID_BITMAP_OFFSET);
 }
 
 static void sync_wait_cb(void *arg)
@@ -580,7 +576,6 @@ static void gfs2_control_func(struct work_struct *work)
 {
        struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_control_work.work);
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       char lvb_bits[GDLM_LVB_SIZE];
        uint32_t block_gen, start_gen, lvb_gen, flags;
        int recover_set = 0;
        int write_lvb = 0;
@@ -634,7 +629,7 @@ static void gfs2_control_func(struct work_struct *work)
                return;
        }
 
-       control_lvb_read(ls, &lvb_gen, lvb_bits);
+       control_lvb_read(ls, &lvb_gen, ls->ls_lvb_bits);
 
        spin_lock(&ls->ls_recover_spin);
        if (block_gen != ls->ls_recover_block ||
@@ -664,10 +659,10 @@ static void gfs2_control_func(struct work_struct *work)
 
                        ls->ls_recover_result[i] = 0;
 
-                       if (!test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET))
+                       if (!test_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET))
                                continue;
 
-                       __clear_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+                       __clear_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET);
                        write_lvb = 1;
                }
        }
@@ -691,7 +686,7 @@ static void gfs2_control_func(struct work_struct *work)
                                continue;
                        if (ls->ls_recover_submit[i] < start_gen) {
                                ls->ls_recover_submit[i] = 0;
-                               __set_bit_le(i, lvb_bits + JID_BITMAP_OFFSET);
+                               __set_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET);
                        }
                }
                /* even if there are no bits to set, we need to write the
@@ -705,7 +700,7 @@ static void gfs2_control_func(struct work_struct *work)
        spin_unlock(&ls->ls_recover_spin);
 
        if (write_lvb) {
-               control_lvb_write(ls, start_gen, lvb_bits);
+               control_lvb_write(ls, start_gen, ls->ls_lvb_bits);
                flags = DLM_LKF_CONVERT | DLM_LKF_VALBLK;
        } else {
                flags = DLM_LKF_CONVERT;
@@ -725,7 +720,7 @@ static void gfs2_control_func(struct work_struct *work)
         */
 
        for (i = 0; i < recover_size; i++) {
-               if (test_bit_le(i, lvb_bits + JID_BITMAP_OFFSET)) {
+               if (test_bit_le(i, ls->ls_lvb_bits + JID_BITMAP_OFFSET)) {
                        fs_info(sdp, "recover generation %u jid %d\n",
                                start_gen, i);
                        gfs2_recover_set(sdp, i);
@@ -758,7 +753,6 @@ static void gfs2_control_func(struct work_struct *work)
 static int control_mount(struct gfs2_sbd *sdp)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       char lvb_bits[GDLM_LVB_SIZE];
        uint32_t start_gen, block_gen, mount_gen, lvb_gen;
        int mounted_mode;
        int retries = 0;
@@ -857,7 +851,7 @@ locks_done:
         * lvb_gen will be non-zero.
         */
 
-       control_lvb_read(ls, &lvb_gen, lvb_bits);
+       control_lvb_read(ls, &lvb_gen, ls->ls_lvb_bits);
 
        if (lvb_gen == 0xFFFFFFFF) {
                /* special value to force mount attempts to fail */
@@ -887,7 +881,7 @@ locks_done:
         * and all lvb bits to be clear (no pending journal recoveries.)
         */
 
-       if (!all_jid_bits_clear(lvb_bits)) {
+       if (!all_jid_bits_clear(ls->ls_lvb_bits)) {
                /* journals need recovery, wait until all are clear */
                fs_info(sdp, "control_mount wait for journal recovery\n");
                goto restart;
@@ -949,7 +943,6 @@ static int dlm_recovery_wait(void *word)
 static int control_first_done(struct gfs2_sbd *sdp)
 {
        struct lm_lockstruct *ls = &sdp->sd_lockstruct;
-       char lvb_bits[GDLM_LVB_SIZE];
        uint32_t start_gen, block_gen;
        int error;
 
@@ -991,8 +984,8 @@ restart:
        memset(ls->ls_recover_result, 0, ls->ls_recover_size*sizeof(uint32_t));
        spin_unlock(&ls->ls_recover_spin);
 
-       memset(lvb_bits, 0, sizeof(lvb_bits));
-       control_lvb_write(ls, start_gen, lvb_bits);
+       memset(ls->ls_lvb_bits, 0, GDLM_LVB_SIZE);
+       control_lvb_write(ls, start_gen, ls->ls_lvb_bits);
 
        error = mounted_lock(sdp, DLM_LOCK_PR, DLM_LKF_CONVERT);
        if (error)
@@ -1022,6 +1015,12 @@ static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots,
        uint32_t old_size, new_size;
        int i, max_jid;
 
+       if (!ls->ls_lvb_bits) {
+               ls->ls_lvb_bits = kzalloc(GDLM_LVB_SIZE, GFP_NOFS);
+               if (!ls->ls_lvb_bits)
+                       return -ENOMEM;
+       }
+
        max_jid = 0;
        for (i = 0; i < num_slots; i++) {
                if (max_jid < slots[i].slot - 1)
@@ -1057,6 +1056,7 @@ static int set_recover_size(struct gfs2_sbd *sdp, struct dlm_slot *slots,
 
 static void free_recover_size(struct lm_lockstruct *ls)
 {
+       kfree(ls->ls_lvb_bits);
        kfree(ls->ls_recover_submit);
        kfree(ls->ls_recover_result);
        ls->ls_recover_submit = NULL;
@@ -1205,6 +1205,7 @@ static int gdlm_mount(struct gfs2_sbd *sdp, const char *table)
        ls->ls_recover_size = 0;
        ls->ls_recover_submit = NULL;
        ls->ls_recover_result = NULL;
+       ls->ls_lvb_bits = NULL;
 
        error = set_recover_size(sdp, NULL, 0);
        if (error)
index d1f51fd..5a51265 100644 (file)
@@ -576,7 +576,7 @@ int gfs2_rs_alloc(struct gfs2_inode *ip)
        RB_CLEAR_NODE(&ip->i_res->rs_node);
 out:
        up_write(&ip->i_rw_mutex);
-       return 0;
+       return error;
 }
 
 static void dump_rs(struct seq_file *seq, const struct gfs2_blkreserv *rs)
@@ -1181,12 +1181,9 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                             const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed)
 {
        struct super_block *sb = sdp->sd_vfs;
-       struct block_device *bdev = sb->s_bdev;
-       const unsigned int sects_per_blk = sdp->sd_sb.sb_bsize /
-                                          bdev_logical_block_size(sb->s_bdev);
        u64 blk;
        sector_t start = 0;
-       sector_t nr_sects = 0;
+       sector_t nr_blks = 0;
        int rv;
        unsigned int x;
        u32 trimmed = 0;
@@ -1206,35 +1203,34 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                if (diff == 0)
                        continue;
                blk = offset + ((bi->bi_start + x) * GFS2_NBBY);
-               blk *= sects_per_blk; /* convert to sectors */
                while(diff) {
                        if (diff & 1) {
-                               if (nr_sects == 0)
+                               if (nr_blks == 0)
                                        goto start_new_extent;
-                               if ((start + nr_sects) != blk) {
-                                       if (nr_sects >= minlen) {
-                                               rv = blkdev_issue_discard(bdev,
-                                                       start, nr_sects,
+                               if ((start + nr_blks) != blk) {
+                                       if (nr_blks >= minlen) {
+                                               rv = sb_issue_discard(sb,
+                                                       start, nr_blks,
                                                        GFP_NOFS, 0);
                                                if (rv)
                                                        goto fail;
-                                               trimmed += nr_sects;
+                                               trimmed += nr_blks;
                                        }
-                                       nr_sects = 0;
+                                       nr_blks = 0;
 start_new_extent:
                                        start = blk;
                                }
-                               nr_sects += sects_per_blk;
+                               nr_blks++;
                        }
                        diff >>= 2;
-                       blk += sects_per_blk;
+                       blk++;
                }
        }
-       if (nr_sects >= minlen) {
-               rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0);
+       if (nr_blks >= minlen) {
+               rv = sb_issue_discard(sb, start, nr_blks, GFP_NOFS, 0);
                if (rv)
                        goto fail;
-               trimmed += nr_sects;
+               trimmed += nr_blks;
        }
        if (ptrimmed)
                *ptrimmed = trimmed;
index 507141f..4be7823 100644 (file)
@@ -125,3 +125,8 @@ extern int invalidate_inodes(struct super_block *, bool);
  * dcache.c
  */
 extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
+
+/*
+ * read_write.c
+ */
+extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
index 50ca17d..d581e45 100644 (file)
@@ -798,6 +798,10 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
        }
 
        mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD;
+       /* Don't allow unprivileged users to change mount flags */
+       if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
+               mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
+
        atomic_inc(&sb->s_active);
        mnt->mnt.mnt_sb = sb;
        mnt->mnt.mnt_root = dget(root);
@@ -1713,6 +1717,9 @@ static int change_mount_flags(struct vfsmount *mnt, int ms_flags)
        if (readonly_request == __mnt_is_readonly(mnt))
                return 0;
 
+       if (mnt->mnt_flags & MNT_LOCK_READONLY)
+               return -EPERM;
+
        if (readonly_request)
                error = mnt_make_readonly(real_mount(mnt));
        else
@@ -2339,7 +2346,7 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        /* First pass: copy the tree topology */
        copy_flags = CL_COPY_ALL | CL_EXPIRE;
        if (user_ns != mnt_ns->user_ns)
-               copy_flags |= CL_SHARED_TO_SLAVE;
+               copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED;
        new = copy_tree(old, old->mnt.mnt_root, copy_flags);
        if (IS_ERR(new)) {
                up_write(&namespace_sem);
@@ -2732,6 +2739,51 @@ bool our_mnt(struct vfsmount *mnt)
        return check_mnt(real_mount(mnt));
 }
 
+bool current_chrooted(void)
+{
+       /* Does the current process have a non-standard root */
+       struct path ns_root;
+       struct path fs_root;
+       bool chrooted;
+
+       /* Find the namespace root */
+       ns_root.mnt = &current->nsproxy->mnt_ns->root->mnt;
+       ns_root.dentry = ns_root.mnt->mnt_root;
+       path_get(&ns_root);
+       while (d_mountpoint(ns_root.dentry) && follow_down_one(&ns_root))
+               ;
+
+       get_fs_root(current->fs, &fs_root);
+
+       chrooted = !path_equal(&fs_root, &ns_root);
+
+       path_put(&fs_root);
+       path_put(&ns_root);
+
+       return chrooted;
+}
+
+void update_mnt_policy(struct user_namespace *userns)
+{
+       struct mnt_namespace *ns = current->nsproxy->mnt_ns;
+       struct mount *mnt;
+
+       down_read(&namespace_sem);
+       list_for_each_entry(mnt, &ns->list, mnt_list) {
+               switch (mnt->mnt.mnt_sb->s_magic) {
+               case SYSFS_MAGIC:
+                       userns->may_mount_sysfs = true;
+                       break;
+               case PROC_SUPER_MAGIC:
+                       userns->may_mount_proc = true;
+                       break;
+               }
+               if (userns->may_mount_sysfs && userns->may_mount_proc)
+                       break;
+       }
+       up_read(&namespace_sem);
+}
+
 static void *mntns_get(struct task_struct *task)
 {
        struct mnt_namespace *ns = NULL;
index 737d839..6fc7b5c 100644 (file)
@@ -55,7 +55,8 @@ static void dev_remove(struct net *net, dev_t dev)
 
        bl_pipe_msg.bl_wq = &nn->bl_wq;
        memset(msg, 0, sizeof(*msg));
-       msg->data = kzalloc(1 + sizeof(bl_umount_request), GFP_NOFS);
+       msg->len = sizeof(bl_msg) + bl_msg.totallen;
+       msg->data = kzalloc(msg->len, GFP_NOFS);
        if (!msg->data)
                goto out;
 
@@ -66,7 +67,6 @@ static void dev_remove(struct net *net, dev_t dev)
        memcpy(msg->data, &bl_msg, sizeof(bl_msg));
        dataptr = (uint8_t *) msg->data;
        memcpy(&dataptr[sizeof(bl_msg)], &bl_umount_request, sizeof(bl_umount_request));
-       msg->len = sizeof(bl_msg) + bl_msg.totallen;
 
        add_wait_queue(&nn->bl_wq, &wq);
        if (rpc_queue_upcall(nn->bl_device_pipe, msg) < 0) {
index dc0f98d..c516da5 100644 (file)
@@ -726,9 +726,9 @@ out1:
        return ret;
 }
 
-static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data)
+static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)
 {
-       return key_instantiate_and_link(key, data, strlen(data) + 1,
+       return key_instantiate_and_link(key, data, datalen,
                                        id_resolver_cache->thread_keyring,
                                        authkey);
 }
@@ -738,6 +738,7 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
                struct key *key, struct key *authkey)
 {
        char id_str[NFS_UINT_MAXLEN];
+       size_t len;
        int ret = -ENOKEY;
 
        /* ret = -ENOKEY */
@@ -747,13 +748,15 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
        case IDMAP_CONV_NAMETOID:
                if (strcmp(upcall->im_name, im->im_name) != 0)
                        break;
-               sprintf(id_str, "%d", im->im_id);
-               ret = nfs_idmap_instantiate(key, authkey, id_str);
+               /* Note: here we store the NUL terminator too */
+               len = sprintf(id_str, "%d", im->im_id) + 1;
+               ret = nfs_idmap_instantiate(key, authkey, id_str, len);
                break;
        case IDMAP_CONV_IDTONAME:
                if (upcall->im_id != im->im_id)
                        break;
-               ret = nfs_idmap_instantiate(key, authkey, im->im_name);
+               len = strlen(im->im_name);
+               ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);
                break;
        default:
                ret = -EINVAL;
index 49eeb04..4fb234d 100644 (file)
@@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo)
 {
        if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
                return;
-       clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags);
        pnfs_return_layout(inode);
 }
 
index b2671cb..26431cf 100644 (file)
@@ -2632,7 +2632,7 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        int status;
 
        if (pnfs_ld_layoutret_on_setattr(inode))
-               pnfs_return_layout(inode);
+               pnfs_commit_and_return_layout(inode);
 
        nfs_fattr_init(fattr);
        
@@ -6416,22 +6416,8 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
 static void nfs4_layoutcommit_release(void *calldata)
 {
        struct nfs4_layoutcommit_data *data = calldata;
-       struct pnfs_layout_segment *lseg, *tmp;
-       unsigned long *bitlock = &NFS_I(data->args.inode)->flags;
 
        pnfs_cleanup_layoutcommit(data);
-       /* Matched by references in pnfs_set_layoutcommit */
-       list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
-               list_del_init(&lseg->pls_lc_list);
-               if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
-                                      &lseg->pls_flags))
-                       pnfs_put_lseg(lseg);
-       }
-
-       clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
-       smp_mb__after_clear_bit();
-       wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
-
        put_rpccred(data->cred);
        kfree(data);
 }
index 48ac5aa..4bdffe0 100644 (file)
@@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range,
               lo_seg_intersecting(lseg_range, recall_range);
 }
 
+static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg,
+               struct list_head *tmp_list)
+{
+       if (!atomic_dec_and_test(&lseg->pls_refcount))
+               return false;
+       pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
+       list_add(&lseg->pls_list, tmp_list);
+       return true;
+}
+
 /* Returns 1 if lseg is removed from list, 0 otherwise */
 static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
                             struct list_head *tmp_list)
@@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
                 */
                dprintk("%s: lseg %p ref %d\n", __func__, lseg,
                        atomic_read(&lseg->pls_refcount));
-               if (atomic_dec_and_test(&lseg->pls_refcount)) {
-                       pnfs_layout_remove_lseg(lseg->pls_layout, lseg);
-                       list_add(&lseg->pls_list, tmp_list);
+               if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list))
                        rv = 1;
-               }
        }
        return rv;
 }
@@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        return lseg;
 }
 
+static void pnfs_clear_layoutcommit(struct inode *inode,
+               struct list_head *head)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct pnfs_layout_segment *lseg, *tmp;
+
+       if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
+               return;
+       list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) {
+               if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
+                       continue;
+               pnfs_lseg_dec_and_remove_zero(lseg, head);
+       }
+}
+
 /*
  * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
  * when the layout segment list is empty.
@@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino)
        /* Reference matched in nfs4_layoutreturn_release */
        pnfs_get_layout_hdr(lo);
        empty = list_empty(&lo->plh_segs);
+       pnfs_clear_layoutcommit(ino, &tmp_list);
        pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
        /* Don't send a LAYOUTRETURN if list was initially empty */
        if (empty) {
@@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino)
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
 
-       WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
-
        lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
        if (unlikely(lrp == NULL)) {
                status = -ENOMEM;
@@ -845,6 +866,33 @@ out:
 }
 EXPORT_SYMBOL_GPL(_pnfs_return_layout);
 
+int
+pnfs_commit_and_return_layout(struct inode *inode)
+{
+       struct pnfs_layout_hdr *lo;
+       int ret;
+
+       spin_lock(&inode->i_lock);
+       lo = NFS_I(inode)->layout;
+       if (lo == NULL) {
+               spin_unlock(&inode->i_lock);
+               return 0;
+       }
+       pnfs_get_layout_hdr(lo);
+       /* Block new layoutgets and read/write to ds */
+       lo->plh_block_lgets++;
+       spin_unlock(&inode->i_lock);
+       filemap_fdatawait(inode->i_mapping);
+       ret = pnfs_layoutcommit_inode(inode, true);
+       if (ret == 0)
+               ret = _pnfs_return_layout(inode);
+       spin_lock(&inode->i_lock);
+       lo->plh_block_lgets--;
+       spin_unlock(&inode->i_lock);
+       pnfs_put_layout_hdr(lo);
+       return ret;
+}
+
 bool pnfs_roc(struct inode *ino)
 {
        struct pnfs_layout_hdr *lo;
@@ -1458,7 +1506,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data)
        dprintk("pnfs write error = %d\n", hdr->pnfs_error);
        if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
            PNFS_LAYOUTRET_ON_ERROR) {
-               clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
                pnfs_return_layout(hdr->inode);
        }
        if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
@@ -1613,7 +1660,6 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data)
        dprintk("pnfs read error = %d\n", hdr->pnfs_error);
        if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
            PNFS_LAYOUTRET_ON_ERROR) {
-               clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
                pnfs_return_layout(hdr->inode);
        }
        if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
@@ -1746,11 +1792,27 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
 
        list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
                if (lseg->pls_range.iomode == IOMODE_RW &&
-                   test_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
+                   test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags))
                        list_add(&lseg->pls_lc_list, listp);
        }
 }
 
+static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp)
+{
+       struct pnfs_layout_segment *lseg, *tmp;
+       unsigned long *bitlock = &NFS_I(inode)->flags;
+
+       /* Matched by references in pnfs_set_layoutcommit */
+       list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) {
+               list_del_init(&lseg->pls_lc_list);
+               pnfs_put_lseg(lseg);
+       }
+
+       clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
+       smp_mb__after_clear_bit();
+       wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
+}
+
 void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
 {
        pnfs_layout_io_set_failed(lseg->pls_layout, lseg->pls_range.iomode);
@@ -1795,6 +1857,7 @@ void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data)
 
        if (nfss->pnfs_curr_ld->cleanup_layoutcommit)
                nfss->pnfs_curr_ld->cleanup_layoutcommit(data);
+       pnfs_list_write_lseg_done(data->args.inode, &data->lseg_list);
 }
 
 /*
index 94ba804..f5f8a47 100644 (file)
@@ -219,6 +219,7 @@ void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
 void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
 int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
 int _pnfs_return_layout(struct inode *);
+int pnfs_commit_and_return_layout(struct inode *);
 void pnfs_ld_write_done(struct nfs_write_data *);
 void pnfs_ld_read_done(struct nfs_read_data *);
 struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino,
@@ -407,6 +408,11 @@ static inline int pnfs_return_layout(struct inode *ino)
        return 0;
 }
 
+static inline int pnfs_commit_and_return_layout(struct inode *inode)
+{
+       return 0;
+}
+
 static inline bool
 pnfs_ld_layoutret_on_setattr(struct inode *inode)
 {
index 0116886..a272007 100644 (file)
@@ -264,7 +264,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                iattr->ia_valid |= ATTR_SIZE;
        }
        if (bmval[0] & FATTR4_WORD0_ACL) {
-               int nace;
+               u32 nace;
                struct nfs4_ace *ace;
 
                READ_BUF(4); len += 4;
index 62c1ee1..ca05f6d 100644 (file)
@@ -102,7 +102,8 @@ nfsd_reply_cache_free_locked(struct svc_cacherep *rp)
 {
        if (rp->c_type == RC_REPLBUFF)
                kfree(rp->c_replvec.iov_base);
-       hlist_del(&rp->c_hash);
+       if (!hlist_unhashed(&rp->c_hash))
+               hlist_del(&rp->c_hash);
        list_del(&rp->c_lru);
        --num_drc_entries;
        kmem_cache_free(drc_slab, rp);
@@ -118,6 +119,10 @@ nfsd_reply_cache_free(struct svc_cacherep *rp)
 
 int nfsd_reply_cache_init(void)
 {
+       INIT_LIST_HEAD(&lru_head);
+       max_drc_entries = nfsd_cache_size_limit();
+       num_drc_entries = 0;
+
        register_shrinker(&nfsd_reply_cache_shrinker);
        drc_slab = kmem_cache_create("nfsd_drc", sizeof(struct svc_cacherep),
                                        0, 0, NULL);
@@ -128,10 +133,6 @@ int nfsd_reply_cache_init(void)
        if (!cache_hash)
                goto out_nomem;
 
-       INIT_LIST_HEAD(&lru_head);
-       max_drc_entries = nfsd_cache_size_limit();
-       num_drc_entries = 0;
-
        return 0;
 out_nomem:
        printk(KERN_ERR "nfsd: failed to allocate reply cache\n");
index 2a7eb53..2b2e239 100644 (file)
@@ -1013,6 +1013,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        int                     host_err;
        int                     stable = *stablep;
        int                     use_wgather;
+       loff_t                  pos = offset;
 
        dentry = file->f_path.dentry;
        inode = dentry->d_inode;
@@ -1025,7 +1026,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 
        /* Write the data. */
        oldfs = get_fs(); set_fs(KERNEL_DS);
-       host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
+       host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &pos);
        set_fs(oldfs);
        if (host_err < 0)
                goto out_nfserr;
index 3e000a5..8b29d21 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/mnt_namespace.h>
 #include <linux/mount.h>
 #include <linux/fs.h>
+#include <linux/nsproxy.h>
 #include "internal.h"
 #include "pnode.h"
 
@@ -220,6 +221,7 @@ static struct mount *get_source(struct mount *dest,
 int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,
                    struct mount *source_mnt, struct list_head *tree_list)
 {
+       struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns;
        struct mount *m, *child;
        int ret = 0;
        struct mount *prev_dest_mnt = dest_mnt;
@@ -237,6 +239,10 @@ int propagate_mnt(struct mount *dest_mnt, struct dentry *dest_dentry,
 
                source =  get_source(m, prev_dest_mnt, prev_src_mnt, &type);
 
+               /* Notice when we are propagating across user namespaces */
+               if (m->mnt_ns->user_ns != user_ns)
+                       type |= CL_UNPRIVILEGED;
+
                child = copy_tree(source, source->mnt.mnt_root, type);
                if (IS_ERR(child)) {
                        ret = PTR_ERR(child);
index 19b853a..a0493d5 100644 (file)
@@ -23,6 +23,7 @@
 #define CL_MAKE_SHARED                 0x08
 #define CL_PRIVATE             0x10
 #define CL_SHARED_TO_SLAVE     0x20
+#define CL_UNPRIVILEGED                0x40
 
 static inline void set_mnt_shared(struct mount *mnt)
 {
index c6e9fac..9c7fab1 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/bitops.h>
+#include <linux/user_namespace.h>
 #include <linux/mount.h>
 #include <linux/pid_namespace.h>
 #include <linux/parser.h>
@@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
        } else {
                ns = task_active_pid_ns(current);
                options = data;
+
+               if (!current_user_ns()->may_mount_proc)
+                       return ERR_PTR(-EPERM);
        }
 
        sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns);
index a698eff..e6ddc8d 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/splice.h>
 #include <linux/compat.h>
 #include "read_write.h"
+#include "internal.h"
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -417,6 +418,33 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof
 
 EXPORT_SYMBOL(do_sync_write);
 
+ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos)
+{
+       mm_segment_t old_fs;
+       const char __user *p;
+       ssize_t ret;
+
+       if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
+               return -EINVAL;
+
+       old_fs = get_fs();
+       set_fs(get_ds());
+       p = (__force const char __user *)buf;
+       if (count > MAX_RW_COUNT)
+               count =  MAX_RW_COUNT;
+       if (file->f_op->write)
+               ret = file->f_op->write(file, p, count, pos);
+       else
+               ret = do_sync_write(file, p, count, pos);
+       set_fs(old_fs);
+       if (ret > 0) {
+               fsnotify_modify(file);
+               add_wchar(current, ret);
+       }
+       inc_syscw(current);
+       return ret;
+}
+
 ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
 {
        ssize_t ret;
index c196369..4cce1d9 100644 (file)
@@ -187,8 +187,8 @@ fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
        if (dbuf->count == ARRAY_SIZE(dbuf->dentries))
                return -ENOSPC;
 
-       if (name[0] == '.' && (name[1] == '\0' ||
-                              (name[1] == '.' && name[2] == '\0')))
+       if (name[0] == '.' && (namelen < 2 ||
+                              (namelen == 2 && name[1] == '.')))
                return 0;
 
        dentry = lookup_one_len(name, dbuf->xadir, namelen);
index 718bd00..29e394e 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/security.h>
 #include <linux/gfp.h>
 #include <linux/socket.h>
+#include "internal.h"
 
 /*
  * Attempt to steal a page from a pipe buffer. This should perhaps go into
@@ -1048,9 +1049,10 @@ static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
 {
        int ret;
        void *data;
+       loff_t tmp = sd->pos;
 
        data = buf->ops->map(pipe, buf, 0);
-       ret = kernel_write(sd->u.file, data + buf->offset, sd->len, sd->pos);
+       ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp);
        buf->ops->unmap(pipe, buf, data);
 
        return ret;
index 2fbdff6..e145126 100644 (file)
@@ -1020,6 +1020,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
                ino = parent_sd->s_ino;
                if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
                        filp->f_pos++;
+               else
+                       return 0;
        }
        if (filp->f_pos == 1) {
                if (parent_sd->s_parent)
@@ -1028,6 +1030,8 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
                        ino = parent_sd->s_ino;
                if (filldir(dirent, "..", 2, filp->f_pos, ino, DT_DIR) == 0)
                        filp->f_pos++;
+               else
+                       return 0;
        }
        mutex_lock(&sysfs_mutex);
        for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos);
@@ -1058,10 +1062,21 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
        return 0;
 }
 
+static loff_t sysfs_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+       struct inode *inode = file_inode(file);
+       loff_t ret;
+
+       mutex_lock(&inode->i_mutex);
+       ret = generic_file_llseek(file, offset, whence);
+       mutex_unlock(&inode->i_mutex);
+
+       return ret;
+}
 
 const struct file_operations sysfs_dir_operations = {
        .read           = generic_read_dir,
        .readdir        = sysfs_readdir,
        .release        = sysfs_dir_release,
-       .llseek         = generic_file_llseek,
+       .llseek         = sysfs_dir_llseek,
 };
index 8d924b5..afd8327 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <linux/user_namespace.h>
 
 #include "sysfs.h"
 
@@ -111,6 +112,9 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
        struct super_block *sb;
        int error;
 
+       if (!(flags & MS_KERNMOUNT) && !current_user_ns()->may_mount_sysfs)
+               return ERR_PTR(-EPERM);
+
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
                return ERR_PTR(-ENOMEM);
index ac838b8..f21acf0 100644 (file)
@@ -1568,6 +1568,12 @@ static int ubifs_remount_rw(struct ubifs_info *c)
        c->remounting_rw = 1;
        c->ro_mount = 0;
 
+       if (c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err)
+                       return err;
+       }
+
        err = check_free_space(c);
        if (err)
                goto out;
@@ -1684,12 +1690,6 @@ static int ubifs_remount_rw(struct ubifs_info *c)
                err = dbg_check_space_info(c);
        }
 
-       if (c->space_fixup) {
-               err = ubifs_fixup_free_space(c);
-               if (err)
-                       goto out;
-       }
-
        mutex_unlock(&c->umount_mutex);
        return err;
 
index 76a87fb..377cd8c 100644 (file)
@@ -141,11 +141,11 @@ typedef struct {
 } compat_sigset_t;
 
 struct compat_sigaction {
-#ifndef __ARCH_HAS_ODD_SIGACTION
+#ifndef __ARCH_HAS_IRIX_SIGACTION
        compat_uptr_t                   sa_handler;
        compat_ulong_t                  sa_flags;
 #else
-       compat_ulong_t                  sa_flags;
+       compat_uint_t                   sa_flags;
        compat_uptr_t                   sa_handler;
 #endif
 #ifdef __ARCH_HAS_SA_RESTORER
index a975de1..3bd46f7 100644 (file)
@@ -51,7 +51,7 @@ struct task_struct;
 extern void debug_show_all_locks(void);
 extern void debug_show_held_locks(struct task_struct *task);
 extern void debug_check_no_locks_freed(const void *from, unsigned long len);
-extern void debug_check_no_locks_held(void);
+extern void debug_check_no_locks_held(struct task_struct *task);
 #else
 static inline void debug_show_all_locks(void)
 {
@@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len)
 }
 
 static inline void
-debug_check_no_locks_held(void)
+debug_check_no_locks_held(struct task_struct *task)
 {
 }
 #endif
index e83ef39..fe8c447 100644 (file)
@@ -213,7 +213,7 @@ struct devfreq_simple_ondemand_data {
 #endif
 
 #else /* !CONFIG_PM_DEVFREQ */
-static struct devfreq *devfreq_add_device(struct device *dev,
+static inline struct devfreq *devfreq_add_device(struct device *dev,
                                          struct devfreq_dev_profile *profile,
                                          const char *governor_name,
                                          void *data)
@@ -221,34 +221,34 @@ static struct devfreq *devfreq_add_device(struct device *dev,
        return NULL;
 }
 
-static int devfreq_remove_device(struct devfreq *devfreq)
+static inline int devfreq_remove_device(struct devfreq *devfreq)
 {
        return 0;
 }
 
-static int devfreq_suspend_device(struct devfreq *devfreq)
+static inline int devfreq_suspend_device(struct devfreq *devfreq)
 {
        return 0;
 }
 
-static int devfreq_resume_device(struct devfreq *devfreq)
+static inline int devfreq_resume_device(struct devfreq *devfreq)
 {
        return 0;
 }
 
-static struct opp *devfreq_recommended_opp(struct device *dev,
+static inline struct opp *devfreq_recommended_opp(struct device *dev,
                                           unsigned long *freq, u32 flags)
 {
-       return -EINVAL;
+       return ERR_PTR(-EINVAL);
 }
 
-static int devfreq_register_opp_notifier(struct device *dev,
+static inline int devfreq_register_opp_notifier(struct device *dev,
                                         struct devfreq *devfreq)
 {
        return -EINVAL;
 }
 
-static int devfreq_unregister_opp_notifier(struct device *dev,
+static inline int devfreq_unregister_opp_notifier(struct device *dev,
                                           struct devfreq *devfreq)
 {
        return -EINVAL;
index 043a5cf..e70df40 100644 (file)
@@ -3,7 +3,6 @@
 #ifndef FREEZER_H_INCLUDED
 #define FREEZER_H_INCLUDED
 
-#include <linux/debug_locks.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/atomic.h>
@@ -49,8 +48,6 @@ extern void thaw_kernel_threads(void);
 
 static inline bool try_to_freeze(void)
 {
-       if (!(current->flags & PF_NOFREEZE))
-               debug_check_no_locks_held();
        might_sleep();
        if (likely(!freezing(current)))
                return false;
index 729eded..2b93a9a 100644 (file)
@@ -50,4 +50,6 @@ static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root,
        spin_unlock(&fs->lock);
 }
 
+extern bool current_chrooted(void);
+
 #endif /* _LINUX_FS_STRUCT_H */
index cad77fe..c139582 100644 (file)
@@ -518,7 +518,7 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,
 int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
                           void *data, unsigned long len);
 int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
-                             gpa_t gpa);
+                             gpa_t gpa, unsigned long len);
 int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);
 int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len);
 struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
index fa7cc72..b0bcce0 100644 (file)
@@ -71,6 +71,7 @@ struct gfn_to_hva_cache {
        u64 generation;
        gpa_t gpa;
        unsigned long hva;
+       unsigned long len;
        struct kvm_memory_slot *memslot;
 };
 
index a710255..cc28136 100644 (file)
@@ -100,6 +100,9 @@ struct arizona {
        struct regmap_irq_chip_data *aod_irq_chip;
        struct regmap_irq_chip_data *irq_chip;
 
+       bool hpdet_magic;
+       unsigned int hp_ena;
+
        struct mutex clk_lock;
        int clk32k_ref;
 
index 3403551..a47fd35 100644 (file)
 #define ARIZONA_FLL1_CONTROL_6                   0x176
 #define ARIZONA_FLL1_LOOP_FILTER_TEST_1          0x177
 #define ARIZONA_FLL1_NCO_TEST_0                  0x178
+#define ARIZONA_FLL1_CONTROL_7                   0x179
 #define ARIZONA_FLL1_SYNCHRONISER_1              0x181
 #define ARIZONA_FLL1_SYNCHRONISER_2              0x182
 #define ARIZONA_FLL1_SYNCHRONISER_3              0x183
 #define ARIZONA_FLL1_SYNCHRONISER_4              0x184
 #define ARIZONA_FLL1_SYNCHRONISER_5              0x185
 #define ARIZONA_FLL1_SYNCHRONISER_6              0x186
+#define ARIZONA_FLL1_SYNCHRONISER_7              0x187
 #define ARIZONA_FLL1_SPREAD_SPECTRUM             0x189
 #define ARIZONA_FLL1_GPIO_CLOCK                  0x18A
 #define ARIZONA_FLL2_CONTROL_1                   0x191
 #define ARIZONA_FLL2_CONTROL_6                   0x196
 #define ARIZONA_FLL2_LOOP_FILTER_TEST_1          0x197
 #define ARIZONA_FLL2_NCO_TEST_0                  0x198
+#define ARIZONA_FLL2_CONTROL_7                   0x199
 #define ARIZONA_FLL2_SYNCHRONISER_1              0x1A1
 #define ARIZONA_FLL2_SYNCHRONISER_2              0x1A2
 #define ARIZONA_FLL2_SYNCHRONISER_3              0x1A3
 #define ARIZONA_FLL2_SYNCHRONISER_4              0x1A4
 #define ARIZONA_FLL2_SYNCHRONISER_5              0x1A5
 #define ARIZONA_FLL2_SYNCHRONISER_6              0x1A6
+#define ARIZONA_FLL2_SYNCHRONISER_7              0x1A7
 #define ARIZONA_FLL2_SPREAD_SPECTRUM             0x1A9
 #define ARIZONA_FLL2_GPIO_CLOCK                  0x1AA
 #define ARIZONA_MIC_CHARGE_PUMP_1                0x200
 #define ARIZONA_PDM_SPK1_CTRL_2                  0x491
 #define ARIZONA_PDM_SPK2_CTRL_1                  0x492
 #define ARIZONA_PDM_SPK2_CTRL_2                  0x493
+#define ARIZONA_SPK_CTRL_2                       0x4B5
+#define ARIZONA_SPK_CTRL_3                       0x4B6
 #define ARIZONA_DAC_COMP_1                       0x4DC
 #define ARIZONA_DAC_COMP_2                       0x4DD
 #define ARIZONA_DAC_COMP_3                       0x4DE
 #define ARIZONA_FLL1_FRC_INTEG_VAL_SHIFT              0  /* FLL1_FRC_INTEG_VAL - [11:0] */
 #define ARIZONA_FLL1_FRC_INTEG_VAL_WIDTH             12  /* FLL1_FRC_INTEG_VAL - [11:0] */
 
+/*
+ * R377 (0x179) - FLL1 Control 7
+ */
+#define ARIZONA_FLL1_GAIN_MASK                   0x003c  /* FLL1_GAIN */
+#define ARIZONA_FLL1_GAIN_SHIFT                       2  /* FLL1_GAIN */
+#define ARIZONA_FLL1_GAIN_WIDTH                       4  /* FLL1_GAIN */
+
 /*
  * R385 (0x181) - FLL1 Synchroniser 1
  */
 #define ARIZONA_FLL1_CLK_SYNC_SRC_SHIFT               0  /* FLL1_CLK_SYNC_SRC - [3:0] */
 #define ARIZONA_FLL1_CLK_SYNC_SRC_WIDTH               4  /* FLL1_CLK_SYNC_SRC - [3:0] */
 
+/*
+ * R391 (0x187) - FLL1 Synchroniser 7
+ */
+#define ARIZONA_FLL1_SYNC_GAIN_MASK              0x003c  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_GAIN_SHIFT                  2  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_GAIN_WIDTH                  4  /* FLL1_SYNC_GAIN */
+#define ARIZONA_FLL1_SYNC_BW                     0x0001  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_MASK                0x0001  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_SHIFT                    0  /* FLL1_SYNC_BW */
+#define ARIZONA_FLL1_SYNC_BW_WIDTH                    1  /* FLL1_SYNC_BW */
+
 /*
  * R393 (0x189) - FLL1 Spread Spectrum
  */
 #define ARIZONA_FLL2_FRC_INTEG_VAL_SHIFT              0  /* FLL2_FRC_INTEG_VAL - [11:0] */
 #define ARIZONA_FLL2_FRC_INTEG_VAL_WIDTH             12  /* FLL2_FRC_INTEG_VAL - [11:0] */
 
+/*
+ * R409 (0x199) - FLL2 Control 7
+ */
+#define ARIZONA_FLL2_GAIN_MASK                   0x003c  /* FLL2_GAIN */
+#define ARIZONA_FLL2_GAIN_SHIFT                       2  /* FLL2_GAIN */
+#define ARIZONA_FLL2_GAIN_WIDTH                       4  /* FLL2_GAIN */
+
 /*
  * R417 (0x1A1) - FLL2 Synchroniser 1
  */
 #define ARIZONA_FLL2_CLK_SYNC_SRC_SHIFT               0  /* FLL2_CLK_SYNC_SRC - [3:0] */
 #define ARIZONA_FLL2_CLK_SYNC_SRC_WIDTH               4  /* FLL2_CLK_SYNC_SRC - [3:0] */
 
+/*
+ * R423 (0x1A7) - FLL2 Synchroniser 7
+ */
+#define ARIZONA_FLL2_SYNC_GAIN_MASK              0x003c  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_GAIN_SHIFT                  2  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_GAIN_WIDTH                  4  /* FLL2_SYNC_GAIN */
+#define ARIZONA_FLL2_SYNC_BW_MASK                0x0001  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_MASK                0x0001  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_SHIFT                    0  /* FLL2_SYNC_BW */
+#define ARIZONA_FLL2_SYNC_BW_WIDTH                    1  /* FLL2_SYNC_BW */
+
 /*
  * R425 (0x1A9) - FLL2 Spread Spectrum
  */
index 5b18ecd..1aa4f13 100644 (file)
@@ -106,6 +106,29 @@ enum max77693_muic_reg {
        MAX77693_MUIC_REG_END,
 };
 
+/* MAX77693 INTMASK1~2 Register */
+#define INTMASK1_ADC1K_SHIFT           3
+#define INTMASK1_ADCERR_SHIFT          2
+#define INTMASK1_ADCLOW_SHIFT          1
+#define INTMASK1_ADC_SHIFT             0
+#define INTMASK1_ADC1K_MASK            (1 << INTMASK1_ADC1K_SHIFT)
+#define INTMASK1_ADCERR_MASK           (1 << INTMASK1_ADCERR_SHIFT)
+#define INTMASK1_ADCLOW_MASK           (1 << INTMASK1_ADCLOW_SHIFT)
+#define INTMASK1_ADC_MASK              (1 << INTMASK1_ADC_SHIFT)
+
+#define INTMASK2_VIDRM_SHIFT           5
+#define INTMASK2_VBVOLT_SHIFT          4
+#define INTMASK2_DXOVP_SHIFT           3
+#define INTMASK2_DCDTMR_SHIFT          2
+#define INTMASK2_CHGDETRUN_SHIFT       1
+#define INTMASK2_CHGTYP_SHIFT          0
+#define INTMASK2_VIDRM_MASK            (1 << INTMASK2_VIDRM_SHIFT)
+#define INTMASK2_VBVOLT_MASK           (1 << INTMASK2_VBVOLT_SHIFT)
+#define INTMASK2_DXOVP_MASK            (1 << INTMASK2_DXOVP_SHIFT)
+#define INTMASK2_DCDTMR_MASK           (1 << INTMASK2_DCDTMR_SHIFT)
+#define INTMASK2_CHGDETRUN_MASK                (1 << INTMASK2_CHGDETRUN_SHIFT)
+#define INTMASK2_CHGTYP_MASK           (1 << INTMASK2_CHGTYP_SHIFT)
+
 /* MAX77693 MUIC - STATUS1~3 Register */
 #define STATUS1_ADC_SHIFT              (0)
 #define STATUS1_ADCLOW_SHIFT           (5)
index 8e21a09..68e7765 100644 (file)
@@ -17,6 +17,7 @@
 
 #define WM8994_NUM_LDO   2
 #define WM8994_NUM_GPIO 11
+#define WM8994_NUM_AIF   3
 
 struct wm8994_ldo_pdata {
        /** GPIOs to enable regulator, 0 or less if not available */
@@ -215,6 +216,13 @@ struct wm8994_pdata {
         * system.
         */
        bool spkmode_pu;
+
+       /**
+        * Maximum number of channels clocks will be generated for,
+        * useful for systems where and I2S bus with multiple data
+        * lines is mastered.
+        */
+       int max_channels_clocked[WM8994_NUM_AIF];
 };
 
 #endif
index 7acc9dc..e19ff30 100644 (file)
@@ -87,7 +87,6 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_PFNMAP      0x00000400      /* Page-ranges managed without "struct page", just pure PFN */
 #define VM_DENYWRITE   0x00000800      /* ETXTBSY on write attempts.. */
 
-#define VM_POPULATE     0x00001000
 #define VM_LOCKED      0x00002000
 #define VM_IO           0x00004000     /* Memory mapped I/O or similar */
 
index 61c7a87..9aa863d 100644 (file)
@@ -79,8 +79,6 @@ calc_vm_flag_bits(unsigned long flags)
 {
        return _calc_vm_trans(flags, MAP_GROWSDOWN,  VM_GROWSDOWN ) |
               _calc_vm_trans(flags, MAP_DENYWRITE,  VM_DENYWRITE ) |
-              ((flags & MAP_LOCKED) ? (VM_LOCKED | VM_POPULATE) : 0) |
-              (((flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE) ?
-                                                       VM_POPULATE : 0);
+              _calc_vm_trans(flags, MAP_LOCKED,     VM_LOCKED    );
 }
 #endif /* _LINUX_MMAN_H */
index d7029f4..73005f9 100644 (file)
@@ -47,6 +47,8 @@ struct mnt_namespace;
 
 #define MNT_INTERNAL   0x4000
 
+#define MNT_LOCK_READONLY      0x400000
+
 struct vfsmount {
        struct dentry *mnt_root;        /* root of the mounted tree */
        struct super_block *mnt_sb;     /* pointer to superblock */
index f14943d..f80af86 100644 (file)
@@ -24,8 +24,8 @@
 #define STMLCDIF_18BIT 2 /** pixel data bus to the display is of 18 bit width */
 #define STMLCDIF_24BIT 3 /** pixel data bus to the display is of 24 bit width */
 
-#define FB_SYNC_DATA_ENABLE_HIGH_ACT   (1 << 6)
-#define FB_SYNC_DOTCLK_FAILING_ACT     (1 << 7) /* failing/negtive edge sampling */
+#define MXSFB_SYNC_DATA_ENABLE_HIGH_ACT        (1 << 6)
+#define MXSFB_SYNC_DOTCLK_FAILING_ACT  (1 << 7) /* failing/negtive edge sampling */
 
 struct mxsfb_platform_data {
        struct fb_videomode *mode_list;
@@ -44,6 +44,9 @@ struct mxsfb_platform_data {
                                 * allocated. If specified,fb_size must also be specified.
                                 * fb_phys must be unused by Linux.
                                 */
+       u32 sync;               /* sync mask, contains MXSFB specifics not
+                                * carried in fb_info->var.sync
+                                */
 };
 
 #endif /* __LINUX_MXSFB_H */
index b3d00fa..6151e90 100644 (file)
@@ -210,9 +210,9 @@ struct netdev_hw_addr {
 #define NETDEV_HW_ADDR_T_SLAVE         3
 #define NETDEV_HW_ADDR_T_UNICAST       4
 #define NETDEV_HW_ADDR_T_MULTICAST     5
-       bool                    synced;
        bool                    global_use;
        int                     refcount;
+       int                     synced;
        struct rcu_head         rcu_head;
 };
 
@@ -895,7 +895,7 @@ struct netdev_fcoe_hbainfo {
  *
  * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh)
  * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq,
- *                          struct net_device *dev)
+ *                          struct net_device *dev, u32 filter_mask)
  *
  * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
  *     Called to change device carrier. Soft-devices (like dummy, team, etc)
index 2461033..710067f 100644 (file)
@@ -916,6 +916,7 @@ void pci_disable_rom(struct pci_dev *pdev);
 void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
 void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom);
 size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size);
+void __iomem __must_check *pci_platform_rom(struct pci_dev *pdev, size_t *size);
 
 /* Power management related routines */
 int pci_save_state(struct pci_dev *dev);
index a2dcb94..9475c5c 100644 (file)
@@ -250,11 +250,11 @@ extern int show_unhandled_signals;
 extern int sigsuspend(sigset_t *);
 
 struct sigaction {
-#ifndef __ARCH_HAS_ODD_SIGACTION
+#ifndef __ARCH_HAS_IRIX_SIGACTION
        __sighandler_t  sa_handler;
        unsigned long   sa_flags;
 #else
-       unsigned long   sa_flags;
+       unsigned int    sa_flags;
        __sighandler_t  sa_handler;
 #endif
 #ifdef __ARCH_HAS_SA_RESTORER
index 441f5bf..b8292d8 100644 (file)
@@ -2643,6 +2643,13 @@ static inline void nf_reset(struct sk_buff *skb)
 #endif
 }
 
+static inline void nf_reset_trace(struct sk_buff *skb)
+{
+#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
+       skb->nf_trace = 0;
+#endif
+}
+
 /* Note: This doesn't put any conntrack and bridge info in dst. */
 static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src)
 {
index f0bd7f9..e3c0ae9 100644 (file)
@@ -44,7 +44,7 @@
 /* Adding event notification support elements */
 #define THERMAL_GENL_FAMILY_NAME                "thermal_event"
 #define THERMAL_GENL_VERSION                    0x01
-#define THERMAL_GENL_MCAST_GROUP_NAME           "thermal_mc_group"
+#define THERMAL_GENL_MCAST_GROUP_NAME           "thermal_mc_grp"
 
 /* Default Thermal Governor */
 #if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE)
index 9d81de1..42278bb 100644 (file)
@@ -68,6 +68,7 @@ struct udp_sock {
         * For encapsulation sockets.
         */
        int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
+       void (*encap_destroy)(struct sock *sk);
 };
 
 static inline struct udp_sock *udp_sk(const struct sock *sk)
index 0a78df5..59694b5 100644 (file)
@@ -357,6 +357,7 @@ struct hc_driver {
                 */
        int     (*disable_usb3_lpm_timeout)(struct usb_hcd *,
                        struct usb_device *, enum usb3_link_state state);
+       int     (*find_raw_port_number)(struct usb_hcd *, int);
 };
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -396,6 +397,7 @@ extern int usb_hcd_is_primary_hcd(struct usb_hcd *hcd);
 extern int usb_add_hcd(struct usb_hcd *hcd,
                unsigned int irqnum, unsigned long irqflags);
 extern void usb_remove_hcd(struct usb_hcd *hcd);
+extern int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1);
 
 struct platform_device;
 extern void usb_hcd_platform_shutdown(struct platform_device *dev);
index 4ce0093..b6b215f 100644 (file)
@@ -26,6 +26,8 @@ struct user_namespace {
        kuid_t                  owner;
        kgid_t                  group;
        unsigned int            proc_inum;
+       bool                    may_mount_sysfs;
+       bool                    may_mount_proc;
 };
 
 extern struct user_namespace init_user_ns;
@@ -82,4 +84,6 @@ static inline void put_user_ns(struct user_namespace *ns)
 
 #endif
 
+void update_mnt_policy(struct user_namespace *userns);
+
 #endif /* _LINUX_USER_H */
index 80461c1..bb8271d 100644 (file)
@@ -9,6 +9,7 @@ struct flow_keys {
                __be32 ports;
                __be16 port16[2];
        };
+       u16 thoff;
        u8 ip_proto;
 };
 
index 68c69d5..fce8e6b 100644 (file)
@@ -976,6 +976,7 @@ struct netns_ipvs {
        int                     sysctl_sync_retries;
        int                     sysctl_nat_icmp_send;
        int                     sysctl_pmtu_disc;
+       int                     sysctl_backup_only;
 
        /* ip_vs_lblc */
        int                     sysctl_lblc_expiration;
@@ -1067,6 +1068,12 @@ static inline int sysctl_pmtu_disc(struct netns_ipvs *ipvs)
        return ipvs->sysctl_pmtu_disc;
 }
 
+static inline int sysctl_backup_only(struct netns_ipvs *ipvs)
+{
+       return ipvs->sync_state & IP_VS_STATE_BACKUP &&
+              ipvs->sysctl_backup_only;
+}
+
 #else
 
 static inline int sysctl_sync_threshold(struct netns_ipvs *ipvs)
@@ -1114,6 +1121,11 @@ static inline int sysctl_pmtu_disc(struct netns_ipvs *ipvs)
        return 1;
 }
 
+static inline int sysctl_backup_only(struct netns_ipvs *ipvs)
+{
+       return 0;
+}
+
 #endif
 
 /*
index fd19625..982141c 100644 (file)
@@ -77,15 +77,11 @@ static inline void tunnel_ip_select_ident(struct sk_buff *skb,
 {
        struct iphdr *iph = ip_hdr(skb);
 
-       if (iph->frag_off & htons(IP_DF))
-               iph->id = 0;
-       else {
-               /* 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);
-       }
+       /* 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);
 }
 #endif
index 399162b..e1379b4 100644 (file)
@@ -1074,7 +1074,8 @@ void fc_rport_terminate_io(struct fc_rport *);
 /*
  * DISCOVERY LAYER
  *****************************/
-int fc_disc_init(struct fc_lport *);
+void fc_disc_init(struct fc_lport *);
+void fc_disc_config(struct fc_lport *, void *);
 
 static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc)
 {
index b877334..9562042 100644 (file)
@@ -32,9 +32,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
                return DMA_DEV_TO_MEM;
 }
 
-void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data);
-void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream);
-
 int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
        const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
 int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
@@ -47,4 +44,28 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
 
 struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
 
+/**
+ * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data
+ * @addr: Address of the DAI data source or destination register.
+ * @addr_width: Width of the DAI data source or destination register.
+ * @maxburst: Maximum number of words(note: words, as in units of the
+ * src_addr_width member, not bytes) that can be send to or received from the
+ * DAI in one burst.
+ * @slave_id: Slave requester id for the DMA channel.
+ * @filter_data: Custom DMA channel filter data, this will usually be used when
+ * requesting the DMA channel.
+ */
+struct snd_dmaengine_dai_dma_data {
+       dma_addr_t addr;
+       enum dma_slave_buswidth addr_width;
+       u32 maxburst;
+       unsigned int slave_id;
+       void *filter_data;
+};
+
+void snd_dmaengine_pcm_set_config_from_dai_data(
+       const struct snd_pcm_substream *substream,
+       const struct snd_dmaengine_dai_dma_data *dma_data,
+       struct dma_slave_config *config);
+
 #endif
index 3d84808..ae9a227 100644 (file)
@@ -95,14 +95,6 @@ struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 
-/* Digital Audio Interface registration */
-int snd_soc_register_dai(struct device *dev,
-               struct snd_soc_dai_driver *dai_drv);
-void snd_soc_unregister_dai(struct device *dev);
-int snd_soc_register_dais(struct device *dev,
-               struct snd_soc_dai_driver *dai_drv, size_t count);
-void snd_soc_unregister_dais(struct device *dev, size_t count);
-
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir);
index 44a30b1..d460902 100644 (file)
@@ -566,7 +566,6 @@ struct snd_soc_dapm_update {
 
 /* DAPM context */
 struct snd_soc_dapm_context {
-       int n_widgets; /* number of widgets in this context */
        enum snd_soc_bias_level bias_level;
        enum snd_soc_bias_level suspend_bias_level;
        struct delayed_work delayed_work;
index a6a059c..9eb0e4d 100644 (file)
@@ -324,6 +324,8 @@ struct snd_soc_dai_link;
 struct snd_soc_platform_driver;
 struct snd_soc_codec;
 struct snd_soc_codec_driver;
+struct snd_soc_component;
+struct snd_soc_component_driver;
 struct soc_enum;
 struct snd_soc_jack;
 struct snd_soc_jack_zone;
@@ -371,12 +373,16 @@ int snd_soc_suspend(struct device *dev);
 int snd_soc_resume(struct device *dev);
 int snd_soc_poweroff(struct device *dev);
 int snd_soc_register_platform(struct device *dev,
-               struct snd_soc_platform_driver *platform_drv);
+               const struct snd_soc_platform_driver *platform_drv);
 void snd_soc_unregister_platform(struct device *dev);
 int snd_soc_register_codec(struct device *dev,
                const struct snd_soc_codec_driver *codec_drv,
                struct snd_soc_dai_driver *dai_drv, int num_dai);
 void snd_soc_unregister_codec(struct device *dev);
+int snd_soc_register_component(struct device *dev,
+                        const struct snd_soc_component_driver *cmpnt_drv,
+                        struct snd_soc_dai_driver *dai_drv, int num_dai);
+void snd_soc_unregister_component(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec,
                                    unsigned int reg);
 int snd_soc_codec_readable_register(struct snd_soc_codec *codec,
@@ -801,10 +807,10 @@ struct snd_soc_platform_driver {
                struct snd_soc_dai *);
 
        /* platform stream pcm ops */
-       struct snd_pcm_ops *ops;
+       const struct snd_pcm_ops *ops;
 
        /* platform stream compress ops */
-       struct snd_compr_ops *compr_ops;
+       const struct snd_compr_ops *compr_ops;
 
        /* platform stream completion event */
        int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
@@ -823,7 +829,7 @@ struct snd_soc_platform {
        const char *name;
        int id;
        struct device *dev;
-       struct snd_soc_platform_driver *driver;
+       const struct snd_soc_platform_driver *driver;
        struct mutex mutex;
 
        unsigned int suspended:1; /* platform is suspended */
@@ -841,6 +847,20 @@ struct snd_soc_platform {
 #endif
 };
 
+struct snd_soc_component_driver {
+       const char *name;
+};
+
+struct snd_soc_component {
+       const char *name;
+       int id;
+       int num_dai;
+       struct device *dev;
+       struct list_head list;
+
+       const struct snd_soc_component_driver *driver;
+};
+
 struct snd_soc_dai_link {
        /* config - must be set by machine driver */
        const char *name;                       /* Codec name */
@@ -1086,7 +1106,6 @@ struct soc_enum {
        unsigned int mask;
        const char * const *texts;
        const unsigned int *values;
-       void *dapm;
 };
 
 /* codec IO */
diff --git a/include/sound/tas5086.h b/include/sound/tas5086.h
new file mode 100644 (file)
index 0000000..aac481b
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _SND_SOC_CODEC_TAS5086_H_
+#define _SND_SOC_CODEC_TAS5086_H_
+
+#define TAS5086_CLK_IDX_MCLK   0
+#define TAS5086_CLK_IDX_SCLK   1
+
+#endif /* _SND_SOC_CODEC_TAS5086_H_ */
diff --git a/include/sound/tegra_wm8903.h b/include/sound/tegra_wm8903.h
deleted file mode 100644 (file)
index 57b202e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2011 NVIDIA, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __SOUND_TEGRA_WM38903_H
-#define __SOUND_TEGRA_WM38903_H
-
-struct tegra_wm8903_platform_data {
-       int gpio_spkr_en;
-       int gpio_hp_det;
-       int gpio_hp_mute;
-       int gpio_int_mic_en;
-       int gpio_ext_mic_en;
-};
-
-#endif
index 93f5fa9..afafd70 100644 (file)
@@ -33,9 +33,11 @@ enum {
        PACKET_DIAG_TX_RING,
        PACKET_DIAG_FANOUT,
 
-       PACKET_DIAG_MAX,
+       __PACKET_DIAG_MAX,
 };
 
+#define PACKET_DIAG_MAX (__PACKET_DIAG_MAX - 1)
+
 struct packet_diag_info {
        __u32   pdi_index;
        __u32   pdi_version;
index b8a2494..b9e2a6a 100644 (file)
@@ -39,9 +39,11 @@ enum {
        UNIX_DIAG_MEMINFO,
        UNIX_DIAG_SHUTDOWN,
 
-       UNIX_DIAG_MAX,
+       __UNIX_DIAG_MAX,
 };
 
+#define UNIX_DIAG_MAX (__UNIX_DIAG_MAX - 1)
+
 struct unix_diag_vfs {
        __u32   udiag_vfs_ino;
        __u32   udiag_vfs_dev;
index 01c3d62..ffd4652 100644 (file)
@@ -138,11 +138,21 @@ struct blkif_request_discard {
        uint8_t        _pad3;
 } __attribute__((__packed__));
 
+struct blkif_request_other {
+       uint8_t      _pad1;
+       blkif_vdev_t _pad2;        /* only for read/write requests         */
+#ifdef CONFIG_X86_64
+       uint32_t     _pad3;        /* offsetof(blkif_req..,u.other.id)==8*/
+#endif
+       uint64_t     id;           /* private guest value, echoed in resp  */
+} __attribute__((__packed__));
+
 struct blkif_request {
        uint8_t        operation;    /* BLKIF_OP_???                         */
        union {
                struct blkif_request_rw rw;
                struct blkif_request_discard discard;
+               struct blkif_request_other other;
        } u;
 } __attribute__((__packed__));
 
index 1844d31..7000bb1 100644 (file)
@@ -251,6 +251,12 @@ struct physdev_pci_device_add {
 
 #define PHYSDEVOP_pci_device_remove     26
 #define PHYSDEVOP_restore_msi_ext       27
+/*
+ * Dom0 should use these two to announce MMIO resources assigned to
+ * MSI-X capable devices won't (prepare) or may (release) change.
+ */
+#define PHYSDEVOP_prepare_msix          30
+#define PHYSDEVOP_release_msix          31
 struct physdev_pci_device {
     /* IN */
     uint16_t seg;
index 3953fda..e4e47f6 100644 (file)
@@ -330,8 +330,16 @@ static struct dentry *mqueue_mount(struct file_system_type *fs_type,
                         int flags, const char *dev_name,
                         void *data)
 {
-       if (!(flags & MS_KERNMOUNT))
-               data = current->nsproxy->ipc_ns;
+       if (!(flags & MS_KERNMOUNT)) {
+               struct ipc_namespace *ns = current->nsproxy->ipc_ns;
+               /* Don't allow mounting unless the caller has CAP_SYS_ADMIN
+                * over the ipc namespace.
+                */
+               if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
+                       return ERR_PTR(-EPERM);
+
+               data = ns;
+       }
        return mount_ns(fs_type, flags, data, mqueue_fill_super);
 }
 
index 31cd1bf..fede1d0 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -872,6 +872,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp,
                                                        goto out_unlock;
                                                break;
                                        }
+                                       msg = ERR_PTR(-EAGAIN);
                                } else
                                        break;
                                msg_counter++;
index 51e485c..60bc027 100644 (file)
@@ -835,7 +835,7 @@ void do_exit(long code)
        /*
         * Make sure we are holding no locks:
         */
-       debug_check_no_locks_held();
+       debug_check_no_locks_held(tsk);
        /*
         * We can do this unlocked here. The futex code uses this flag
         * just to verify whether the pi state cleanup has been done
index 259db20..8a0efac 100644 (file)
@@ -4088,7 +4088,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len)
 }
 EXPORT_SYMBOL_GPL(debug_check_no_locks_freed);
 
-static void print_held_locks_bug(void)
+static void print_held_locks_bug(struct task_struct *curr)
 {
        if (!debug_locks_off())
                return;
@@ -4097,21 +4097,22 @@ static void print_held_locks_bug(void)
 
        printk("\n");
        printk("=====================================\n");
-       printk("[ BUG: %s/%d still has locks held! ]\n",
-              current->comm, task_pid_nr(current));
+       printk("[ BUG: lock held at task exit time! ]\n");
        print_kernel_ident();
        printk("-------------------------------------\n");
-       lockdep_print_held_locks(current);
+       printk("%s/%d is exiting with locks still held!\n",
+               curr->comm, task_pid_nr(curr));
+       lockdep_print_held_locks(curr);
+
        printk("\nstack backtrace:\n");
        dump_stack();
 }
 
-void debug_check_no_locks_held(void)
+void debug_check_no_locks_held(struct task_struct *task)
 {
-       if (unlikely(current->lockdep_depth > 0))
-               print_held_locks_bug();
+       if (unlikely(task->lockdep_depth > 0))
+               print_held_locks_bug(task);
 }
-EXPORT_SYMBOL_GPL(debug_check_no_locks_held);
 
 void debug_show_all_locks(void)
 {
index c1c3dc1..bea15bd 100644 (file)
@@ -181,6 +181,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
        int nr;
        int rc;
        struct task_struct *task, *me = current;
+       int init_pids = thread_group_leader(me) ? 1 : 2;
 
        /* Don't allow any more processes into the pid namespace */
        disable_pid_allocation(pid_ns);
@@ -230,7 +231,7 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
         */
        for (;;) {
                set_current_state(TASK_UNINTERRUPTIBLE);
-               if (pid_ns->nr_hashed == 1)
+               if (pid_ns->nr_hashed == init_pids)
                        break;
                schedule();
        }
index 2fb8cb8..7f32fe0 100644 (file)
@@ -67,7 +67,8 @@ static void tick_broadcast_start_periodic(struct clock_event_device *bc)
  */
 int tick_check_broadcast_device(struct clock_event_device *dev)
 {
-       if ((tick_broadcast_device.evtdev &&
+       if ((dev->features & CLOCK_EVT_FEAT_DUMMY) ||
+           (tick_broadcast_device.evtdev &&
             tick_broadcast_device.evtdev->rating >= dev->rating) ||
             (dev->features & CLOCK_EVT_FEAT_C3STOP))
                return 0;
index e81978e..8e635a1 100644 (file)
@@ -51,6 +51,8 @@ struct user_namespace init_user_ns = {
        .owner = GLOBAL_ROOT_UID,
        .group = GLOBAL_ROOT_GID,
        .proc_inum = PROC_USER_INIT_INO,
+       .may_mount_sysfs = true,
+       .may_mount_proc = true,
 };
 EXPORT_SYMBOL_GPL(init_user_ns);
 
index b14f4d3..a54f26f 100644 (file)
@@ -61,6 +61,15 @@ int create_user_ns(struct cred *new)
        kgid_t group = new->egid;
        int ret;
 
+       /*
+        * Verify that we can not violate the policy of which files
+        * may be accessed that is specified by the root directory,
+        * by verifing that the root directory is at the root of the
+        * mount namespace which allows all files to be accessed.
+        */
+       if (current_chrooted())
+               return -EPERM;
+
        /* The creator needs a mapping in the parent user namespace
         * or else we won't be able to reasonably tell userspace who
         * created a user_namespace.
@@ -87,6 +96,8 @@ int create_user_ns(struct cred *new)
 
        set_cred_user_ns(new, ns);
 
+       update_mnt_policy(ns);
+
        return 0;
 }
 
index 4723ac8..87da359 100644 (file)
@@ -204,10 +204,8 @@ get_write_lock:
                        unsigned long addr;
                        struct file *file = get_file(vma->vm_file);
 
-                       vm_flags = vma->vm_flags;
-                       if (!(flags & MAP_NONBLOCK))
-                               vm_flags |= VM_POPULATE;
-                       addr = mmap_region(file, start, size, vm_flags, pgoff);
+                       addr = mmap_region(file, start, size,
+                                       vma->vm_flags, pgoff);
                        fput(file);
                        if (IS_ERR_VALUE(addr)) {
                                err = addr;
@@ -226,12 +224,6 @@ get_write_lock:
                mutex_unlock(&mapping->i_mmap_mutex);
        }
 
-       if (!(flags & MAP_NONBLOCK) && !(vma->vm_flags & VM_POPULATE)) {
-               if (!has_write_lock)
-                       goto get_write_lock;
-               vma->vm_flags |= VM_POPULATE;
-       }
-
        if (vma->vm_flags & VM_LOCKED) {
                /*
                 * drop PG_Mlocked flag for over-mapped range
index 1c5e33f..79b7cf7 100644 (file)
@@ -358,7 +358,7 @@ static int do_mlock(unsigned long start, size_t len, int on)
 
                newflags = vma->vm_flags & ~VM_LOCKED;
                if (on)
-                       newflags |= VM_LOCKED | VM_POPULATE;
+                       newflags |= VM_LOCKED;
 
                tmp = vma->vm_end;
                if (tmp > end)
@@ -418,8 +418,7 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors)
                 * range with the first VMA. Also, skip undesirable VMA types.
                 */
                nend = min(end, vma->vm_end);
-               if ((vma->vm_flags & (VM_IO | VM_PFNMAP | VM_POPULATE)) !=
-                   VM_POPULATE)
+               if (vma->vm_flags & (VM_IO | VM_PFNMAP))
                        continue;
                if (nstart < vma->vm_start)
                        nstart = vma->vm_start;
@@ -492,9 +491,9 @@ static int do_mlockall(int flags)
        struct vm_area_struct * vma, * prev = NULL;
 
        if (flags & MCL_FUTURE)
-               current->mm->def_flags |= VM_LOCKED | VM_POPULATE;
+               current->mm->def_flags |= VM_LOCKED;
        else
-               current->mm->def_flags &= ~(VM_LOCKED | VM_POPULATE);
+               current->mm->def_flags &= ~VM_LOCKED;
        if (flags == MCL_FUTURE)
                goto out;
 
@@ -503,7 +502,7 @@ static int do_mlockall(int flags)
 
                newflags = vma->vm_flags & ~VM_LOCKED;
                if (flags & MCL_CURRENT)
-                       newflags |= VM_LOCKED | VM_POPULATE;
+                       newflags |= VM_LOCKED;
 
                /* Ignore errors */
                mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
index 2664a47..0db0de1 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1306,7 +1306,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        }
 
        addr = mmap_region(file, addr, len, vm_flags, pgoff);
-       if (!IS_ERR_VALUE(addr) && (vm_flags & VM_POPULATE))
+       if (!IS_ERR_VALUE(addr) &&
+           ((vm_flags & VM_LOCKED) ||
+            (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
                *populate = len;
        return addr;
 }
@@ -1938,7 +1940,7 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
 
        /* Check the cache first. */
        /* (Cache hit rate is typically around 35%.) */
-       vma = mm->mmap_cache;
+       vma = ACCESS_ONCE(mm->mmap_cache);
        if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
                struct rb_node *rb_node;
 
index e193280..2f3ea74 100644 (file)
@@ -821,7 +821,7 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
        struct vm_area_struct *vma;
 
        /* check the cache first */
-       vma = mm->mmap_cache;
+       vma = ACCESS_ONCE(mm->mmap_cache);
        if (vma && vma->vm_start <= addr && vma->vm_end > addr)
                return vma;
 
index a187144..85addcd 100644 (file)
@@ -86,13 +86,6 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
 
        grp = &vlan_info->grp;
 
-       /* Take it out of our own structures, but be sure to interlock with
-        * HW accelerating devices or SW vlan input packet processing if
-        * VLAN is not 0 (leave it there for 802.1p).
-        */
-       if (vlan_id)
-               vlan_vid_del(real_dev, vlan_id);
-
        grp->nr_vlan_devs--;
 
        if (vlan->flags & VLAN_FLAG_MVRP)
@@ -114,6 +107,13 @@ void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
                vlan_gvrp_uninit_applicant(real_dev);
        }
 
+       /* Take it out of our own structures, but be sure to interlock with
+        * HW accelerating devices or SW vlan input packet processing if
+        * VLAN is not 0 (leave it there for 802.1p).
+        */
+       if (vlan_id)
+               vlan_vid_del(real_dev, vlan_id);
+
        /* Get rid of the vlan's reference to real_dev */
        dev_put(real_dev);
 }
index 79d87d8..fad0302 100644 (file)
@@ -359,6 +359,7 @@ static void __sco_sock_close(struct sock *sk)
                        sco_chan_del(sk, ECONNRESET);
                break;
 
+       case BT_CONNECT2:
        case BT_CONNECT:
        case BT_DISCONN:
                sco_chan_del(sk, ECONNRESET);
index b0812c9..bab338e 100644 (file)
@@ -423,7 +423,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
                        return 0;
                br_warn(br, "adding interface %s with same address "
                       "as a received packet\n",
-                      source->dev->name);
+                      source ? source->dev->name : br->dev->name);
                fdb_delete(br, fdb);
        }
 
index d540ced..e7d68ed 100644 (file)
@@ -1545,7 +1545,6 @@ void net_enable_timestamp(void)
                return;
        }
 #endif
-       WARN_ON(in_interrupt());
        static_key_slow_inc(&netstamp_needed);
 }
 EXPORT_SYMBOL(net_enable_timestamp);
@@ -1625,7 +1624,6 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
        }
 
        skb_orphan(skb);
-       nf_reset(skb);
 
        if (unlikely(!is_skb_forwardable(dev, skb))) {
                atomic_long_inc(&dev->rx_dropped);
@@ -1641,6 +1639,7 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
        skb->mark = 0;
        secpath_reset(skb);
        nf_reset(skb);
+       nf_reset_trace(skb);
        return netif_rx(skb);
 }
 EXPORT_SYMBOL_GPL(dev_forward_skb);
@@ -3315,6 +3314,7 @@ int netdev_rx_handler_register(struct net_device *dev,
        if (dev->rx_handler)
                return -EBUSY;
 
+       /* Note: rx_handler_data must be set before rx_handler */
        rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
        rcu_assign_pointer(dev->rx_handler, rx_handler);
 
@@ -3335,6 +3335,11 @@ void netdev_rx_handler_unregister(struct net_device *dev)
 
        ASSERT_RTNL();
        RCU_INIT_POINTER(dev->rx_handler, NULL);
+       /* a reader seeing a non NULL rx_handler in a rcu_read_lock()
+        * section has a guarantee to see a non NULL rx_handler_data
+        * as well.
+        */
+       synchronize_net();
        RCU_INIT_POINTER(dev->rx_handler_data, NULL);
 }
 EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
index bd2eb9d..abdc9e6 100644 (file)
@@ -37,7 +37,7 @@ static int __hw_addr_create_ex(struct netdev_hw_addr_list *list,
        ha->type = addr_type;
        ha->refcount = 1;
        ha->global_use = global;
-       ha->synced = false;
+       ha->synced = 0;
        list_add_tail_rcu(&ha->list, &list->list);
        list->count++;
 
@@ -165,7 +165,7 @@ int __hw_addr_sync(struct netdev_hw_addr_list *to_list,
                                            addr_len, ha->type);
                        if (err)
                                break;
-                       ha->synced = true;
+                       ha->synced++;
                        ha->refcount++;
                } else if (ha->refcount == 1) {
                        __hw_addr_del(to_list, ha->addr, addr_len, ha->type);
@@ -186,7 +186,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list,
                if (ha->synced) {
                        __hw_addr_del(to_list, ha->addr,
                                      addr_len, ha->type);
-                       ha->synced = false;
+                       ha->synced--;
                        __hw_addr_del(from_list, ha->addr,
                                      addr_len, ha->type);
                }
index c56ea6f..2bfd081 100644 (file)
@@ -328,7 +328,7 @@ static void flow_cache_flush_per_cpu(void *data)
        struct flow_flush_info *info = data;
        struct tasklet_struct *tasklet;
 
-       tasklet = this_cpu_ptr(&info->cache->percpu->flush_tasklet);
+       tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet;
        tasklet->data = (unsigned long)info;
        tasklet_schedule(tasklet);
 }
index 9d4c720..e187bf0 100644 (file)
@@ -140,6 +140,8 @@ ipv6:
                        flow->ports = *ports;
        }
 
+       flow->thoff = (u16) nhoff;
+
        return true;
 }
 EXPORT_SYMBOL(skb_flow_dissect);
index 5fb8d7e..b65441d 100644 (file)
@@ -496,8 +496,10 @@ static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev)
        }
        if (ops->fill_info) {
                data = nla_nest_start(skb, IFLA_INFO_DATA);
-               if (data == NULL)
+               if (data == NULL) {
+                       err = -EMSGSIZE;
                        goto err_cancel_link;
+               }
                err = ops->fill_info(skb, dev);
                if (err < 0)
                        goto err_cancel_data;
index 905dcc6..2dc6cda 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/security.h>
+#include <linux/pid_namespace.h>
 #include <linux/pid.h>
 #include <linux/nsproxy.h>
 #include <linux/slab.h>
@@ -52,7 +53,8 @@ static __inline__ int scm_check_creds(struct ucred *creds)
        if (!uid_valid(uid) || !gid_valid(gid))
                return -EINVAL;
 
-       if ((creds->pid == task_tgid_vnr(current) || nsown_capable(CAP_SYS_ADMIN)) &&
+       if ((creds->pid == task_tgid_vnr(current) ||
+            ns_capable(current->nsproxy->pid_ns->user_ns, CAP_SYS_ADMIN)) &&
            ((uid_eq(uid, cred->uid)   || uid_eq(uid, cred->euid) ||
              uid_eq(uid, cred->suid)) || nsown_capable(CAP_SETUID)) &&
            ((gid_eq(gid, cred->gid)   || gid_eq(gid, cred->egid) ||
index 68f6a94..c929d9c 100644 (file)
@@ -1333,8 +1333,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                                iph->frag_off |= htons(IP_MF);
                        offset += (skb->len - skb->mac_len - iph->ihl * 4);
                } else  {
-                       if (!(iph->frag_off & htons(IP_DF)))
-                               iph->id = htons(id++);
+                       iph->id = htons(id++);
                }
                iph->tot_len = htons(skb->len - skb->mac_len);
                iph->check = 0;
index f678507..96083b7 100644 (file)
@@ -802,8 +802,10 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
                if (nlh->nlmsg_flags & NLM_F_EXCL ||
                    !(nlh->nlmsg_flags & NLM_F_REPLACE))
                        return -EEXIST;
-
-               set_ifa_lifetime(ifa_existing, valid_lft, prefered_lft);
+               ifa = ifa_existing;
+               set_ifa_lifetime(ifa, valid_lft, prefered_lft);
+               rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid);
+               blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);
        }
        return 0;
 }
index 98cbc68..bf6c5cf 100644 (file)
@@ -1522,7 +1522,8 @@ static int __init ip_auto_config(void)
                }
        for (i++; i < CONF_NAMESERVERS_MAX; i++)
                if (ic_nameservers[i] != NONE)
-                       pr_cont(", nameserver%u=%pI4\n", i, &ic_nameservers[i]);
+                       pr_cont(", nameserver%u=%pI4", i, &ic_nameservers[i]);
+       pr_cont("\n");
 #endif /* !SILENT */
 
        return 0;
index ce2d43e..0d755c5 100644 (file)
@@ -36,19 +36,6 @@ config NF_CONNTRACK_PROC_COMPAT
 
          If unsure, say Y.
 
-config IP_NF_QUEUE
-       tristate "IP Userspace queueing via NETLINK (OBSOLETE)"
-       depends on NETFILTER_ADVANCED
-       help
-         Netfilter has the ability to queue packets to user space: the
-         netlink device can be used to access them using this driver.
-
-         This option enables the old IPv4-only "ip_queue" implementation
-         which has been obsoleted by the new "nfnetlink_queue" code (see
-         CONFIG_NETFILTER_NETLINK_QUEUE).
-
-         To compile it as a module, choose M here.  If unsure, say N.
-
 config IP_NF_IPTABLES
        tristate "IP tables support (required for filtering/masq/NAT)"
        default m if NETFILTER_ADVANCED=n
index 0d9bdac..3bd55ba 100644 (file)
@@ -2059,11 +2059,8 @@ void tcp_enter_loss(struct sock *sk, int how)
        if (tcp_is_reno(tp))
                tcp_reset_reno_sack(tp);
 
-       if (!how) {
-               /* Push undo marker, if it was plain RTO and nothing
-                * was retransmitted. */
-               tp->undo_marker = tp->snd_una;
-       } else {
+       tp->undo_marker = tp->snd_una;
+       if (how) {
                tp->sacked_out = 0;
                tp->fackets_out = 0;
        }
index 817fbb3..5d0b438 100644 (file)
@@ -1809,8 +1809,11 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
                        goto send_now;
        }
 
-       /* Ok, it looks like it is advisable to defer.  */
-       tp->tso_deferred = 1 | (jiffies << 1);
+       /* Ok, it looks like it is advisable to defer.
+        * Do not rearm the timer if already set to not break TCP ACK clocking.
+        */
+       if (!tp->tso_deferred)
+               tp->tso_deferred = 1 | (jiffies << 1);
 
        return true;
 
index 265c42c..0a073a2 100644 (file)
@@ -1762,9 +1762,16 @@ int udp_rcv(struct sk_buff *skb)
 
 void udp_destroy_sock(struct sock *sk)
 {
+       struct udp_sock *up = udp_sk(sk);
        bool slow = lock_sock_fast(sk);
        udp_flush_pending_frames(sk);
        unlock_sock_fast(sk, slow);
+       if (static_key_false(&udp_encap_needed) && up->encap_type) {
+               void (*encap_destroy)(struct sock *sk);
+               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               if (encap_destroy)
+                       encap_destroy(sk);
+       }
 }
 
 /*
index f2c7e61..a459c4f 100644 (file)
@@ -2529,6 +2529,9 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
 static void init_loopback(struct net_device *dev)
 {
        struct inet6_dev  *idev;
+       struct net_device *sp_dev;
+       struct inet6_ifaddr *sp_ifa;
+       struct rt6_info *sp_rt;
 
        /* ::1 */
 
@@ -2540,6 +2543,30 @@ static void init_loopback(struct net_device *dev)
        }
 
        add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
+
+       /* Add routes to other interface's IPv6 addresses */
+       for_each_netdev(dev_net(dev), sp_dev) {
+               if (!strcmp(sp_dev->name, dev->name))
+                       continue;
+
+               idev = __in6_dev_get(sp_dev);
+               if (!idev)
+                       continue;
+
+               read_lock_bh(&idev->lock);
+               list_for_each_entry(sp_ifa, &idev->addr_list, if_list) {
+
+                       if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))
+                               continue;
+
+                       sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, 0);
+
+                       /* Failure cases are ignored */
+                       if (!IS_ERR(sp_rt))
+                               ip6_ins_rt(sp_rt);
+               }
+               read_unlock_bh(&idev->lock);
+       }
 }
 
 static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr)
@@ -4784,26 +4811,20 @@ static void addrconf_sysctl_unregister(struct inet6_dev *idev)
 
 static int __net_init addrconf_init_net(struct net *net)
 {
-       int err;
+       int err = -ENOMEM;
        struct ipv6_devconf *all, *dflt;
 
-       err = -ENOMEM;
-       all = &ipv6_devconf;
-       dflt = &ipv6_devconf_dflt;
+       all = kmemdup(&ipv6_devconf, sizeof(ipv6_devconf), GFP_KERNEL);
+       if (all == NULL)
+               goto err_alloc_all;
 
-       if (!net_eq(net, &init_net)) {
-               all = kmemdup(all, sizeof(ipv6_devconf), GFP_KERNEL);
-               if (all == NULL)
-                       goto err_alloc_all;
+       dflt = kmemdup(&ipv6_devconf_dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
+       if (dflt == NULL)
+               goto err_alloc_dflt;
 
-               dflt = kmemdup(dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL);
-               if (dflt == NULL)
-                       goto err_alloc_dflt;
-       } else {
-               /* these will be inherited by all namespaces */
-               dflt->autoconf = ipv6_defaults.autoconf;
-               dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
-       }
+       /* these will be inherited by all namespaces */
+       dflt->autoconf = ipv6_defaults.autoconf;
+       dflt->disable_ipv6 = ipv6_defaults.disable_ipv6;
 
        net->ipv6.devconf_all = all;
        net->ipv6.devconf_dflt = dflt;
index e33fe0a..2bab2aa 100644 (file)
@@ -118,6 +118,18 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
            ipv6_addr_loopback(&hdr->daddr))
                goto err;
 
+       /* RFC4291 Errata ID: 3480
+        * Interface-Local scope spans only a single interface on a
+        * node and is useful only for loopback transmission of
+        * multicast.  Packets with interface-local scope received
+        * from another node must be discarded.
+        */
+       if (!(skb->pkt_type == PACKET_LOOPBACK ||
+             dev->flags & IFF_LOOPBACK) &&
+           ipv6_addr_is_multicast(&hdr->daddr) &&
+           IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1)
+               goto err;
+
        /* RFC4291 2.7
         * Nodes must not originate a packet to a multicast address whose scope
         * field contains the reserved value 0; if such a packet is received, it
index 83acc14..cb63114 100644 (file)
@@ -57,7 +57,7 @@ static bool ip6t_npt_map_pfx(const struct ip6t_npt_tginfo *npt,
                if (pfx_len - i >= 32)
                        mask = 0;
                else
-                       mask = htonl(~((1 << (pfx_len - i)) - 1));
+                       mask = htonl((1 << (i - pfx_len + 32)) - 1);
 
                idx = i / 32;
                addr->s6_addr32[idx] &= mask;
@@ -114,6 +114,7 @@ ip6t_dnpt_tg(struct sk_buff *skb, const struct xt_action_param *par)
 static struct xt_target ip6t_npt_target_reg[] __read_mostly = {
        {
                .name           = "SNPT",
+               .table          = "mangle",
                .target         = ip6t_snpt_tg,
                .targetsize     = sizeof(struct ip6t_npt_tginfo),
                .checkentry     = ip6t_npt_checkentry,
@@ -124,6 +125,7 @@ static struct xt_target ip6t_npt_target_reg[] __read_mostly = {
        },
        {
                .name           = "DNPT",
+               .table          = "mangle",
                .target         = ip6t_dnpt_tg,
                .targetsize     = sizeof(struct ip6t_npt_tginfo),
                .checkentry     = ip6t_npt_checkentry,
index 599e1ba..d8e5e85 100644 (file)
@@ -1285,10 +1285,18 @@ do_confirm:
 
 void udpv6_destroy_sock(struct sock *sk)
 {
+       struct udp_sock *up = udp_sk(sk);
        lock_sock(sk);
        udp_v6_flush_pending_frames(sk);
        release_sock(sk);
 
+       if (static_key_false(&udpv6_encap_needed) && up->encap_type) {
+               void (*encap_destroy)(struct sock *sk);
+               encap_destroy = ACCESS_ONCE(up->encap_destroy);
+               if (encap_destroy)
+                       encap_destroy(sk);
+       }
+
        inet6_destroy_sock(sk);
 }
 
index d07e3a6..d28e7f0 100644 (file)
@@ -2583,8 +2583,10 @@ bed:
                                    NULL, NULL, NULL);
 
                /* Check if the we got some results */
-               if (!self->cachedaddr)
-                       return -EAGAIN;         /* Didn't find any devices */
+               if (!self->cachedaddr) {
+                       err = -EAGAIN;          /* Didn't find any devices */
+                       goto out;
+               }
                daddr = self->cachedaddr;
                /* Cleanup */
                self->cachedaddr = 0;
index 8555f33..5b1e5af 100644 (file)
@@ -2693,6 +2693,7 @@ static int key_notify_policy_flush(const struct km_event *c)
        hdr->sadb_msg_pid = c->portid;
        hdr->sadb_msg_version = PF_KEY_V2;
        hdr->sadb_msg_errno = (uint8_t) 0;
+       hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
        hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
        pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net);
        return 0;
index d36875f..8aecf5d 100644 (file)
@@ -114,7 +114,6 @@ struct l2tp_net {
 
 static void l2tp_session_set_header_len(struct l2tp_session *session, int version);
 static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
-static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
 
 static inline struct l2tp_net *l2tp_pernet(struct net *net)
 {
@@ -192,6 +191,7 @@ struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
        } else {
                /* Socket is owned by kernelspace */
                sk = tunnel->sock;
+               sock_hold(sk);
        }
 
 out:
@@ -210,6 +210,7 @@ void l2tp_tunnel_sock_put(struct sock *sk)
                }
                sock_put(sk);
        }
+       sock_put(sk);
 }
 EXPORT_SYMBOL_GPL(l2tp_tunnel_sock_put);
 
@@ -373,10 +374,8 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk
        struct sk_buff *skbp;
        struct sk_buff *tmp;
        u32 ns = L2TP_SKB_CB(skb)->ns;
-       struct l2tp_stats *sstats;
 
        spin_lock_bh(&session->reorder_q.lock);
-       sstats = &session->stats;
        skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
                if (L2TP_SKB_CB(skbp)->ns > ns) {
                        __skb_queue_before(&session->reorder_q, skbp, skb);
@@ -384,9 +383,7 @@ static void l2tp_recv_queue_skb(struct l2tp_session *session, struct sk_buff *sk
                                 "%s: pkt %hu, inserted before %hu, reorder_q len=%d\n",
                                 session->name, ns, L2TP_SKB_CB(skbp)->ns,
                                 skb_queue_len(&session->reorder_q));
-                       u64_stats_update_begin(&sstats->syncp);
-                       sstats->rx_oos_packets++;
-                       u64_stats_update_end(&sstats->syncp);
+                       atomic_long_inc(&session->stats.rx_oos_packets);
                        goto out;
                }
        }
@@ -403,23 +400,16 @@ static void l2tp_recv_dequeue_skb(struct l2tp_session *session, struct sk_buff *
 {
        struct l2tp_tunnel *tunnel = session->tunnel;
        int length = L2TP_SKB_CB(skb)->length;
-       struct l2tp_stats *tstats, *sstats;
 
        /* We're about to requeue the skb, so return resources
         * to its current owner (a socket receive buffer).
         */
        skb_orphan(skb);
 
-       tstats = &tunnel->stats;
-       u64_stats_update_begin(&tstats->syncp);
-       sstats = &session->stats;
-       u64_stats_update_begin(&sstats->syncp);
-       tstats->rx_packets++;
-       tstats->rx_bytes += length;
-       sstats->rx_packets++;
-       sstats->rx_bytes += length;
-       u64_stats_update_end(&tstats->syncp);
-       u64_stats_update_end(&sstats->syncp);
+       atomic_long_inc(&tunnel->stats.rx_packets);
+       atomic_long_add(length, &tunnel->stats.rx_bytes);
+       atomic_long_inc(&session->stats.rx_packets);
+       atomic_long_add(length, &session->stats.rx_bytes);
 
        if (L2TP_SKB_CB(skb)->has_seq) {
                /* Bump our Nr */
@@ -450,7 +440,6 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
 {
        struct sk_buff *skb;
        struct sk_buff *tmp;
-       struct l2tp_stats *sstats;
 
        /* If the pkt at the head of the queue has the nr that we
         * expect to send up next, dequeue it and any other
@@ -458,13 +447,10 @@ static void l2tp_recv_dequeue(struct l2tp_session *session)
         */
 start:
        spin_lock_bh(&session->reorder_q.lock);
-       sstats = &session->stats;
        skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
                if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) {
-                       u64_stats_update_begin(&sstats->syncp);
-                       sstats->rx_seq_discards++;
-                       sstats->rx_errors++;
-                       u64_stats_update_end(&sstats->syncp);
+                       atomic_long_inc(&session->stats.rx_seq_discards);
+                       atomic_long_inc(&session->stats.rx_errors);
                        l2tp_dbg(session, L2TP_MSG_SEQ,
                                 "%s: oos pkt %u len %d discarded (too old), waiting for %u, reorder_q_len=%d\n",
                                 session->name, L2TP_SKB_CB(skb)->ns,
@@ -623,7 +609,6 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
        struct l2tp_tunnel *tunnel = session->tunnel;
        int offset;
        u32 ns, nr;
-       struct l2tp_stats *sstats = &session->stats;
 
        /* The ref count is increased since we now hold a pointer to
         * the session. Take care to decrement the refcnt when exiting
@@ -640,9 +625,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                                  "%s: cookie mismatch (%u/%u). Discarding.\n",
                                  tunnel->name, tunnel->tunnel_id,
                                  session->session_id);
-                       u64_stats_update_begin(&sstats->syncp);
-                       sstats->rx_cookie_discards++;
-                       u64_stats_update_end(&sstats->syncp);
+                       atomic_long_inc(&session->stats.rx_cookie_discards);
                        goto discard;
                }
                ptr += session->peer_cookie_len;
@@ -711,9 +694,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                        l2tp_warn(session, L2TP_MSG_SEQ,
                                  "%s: recv data has no seq numbers when required. Discarding.\n",
                                  session->name);
-                       u64_stats_update_begin(&sstats->syncp);
-                       sstats->rx_seq_discards++;
-                       u64_stats_update_end(&sstats->syncp);
+                       atomic_long_inc(&session->stats.rx_seq_discards);
                        goto discard;
                }
 
@@ -732,9 +713,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                        l2tp_warn(session, L2TP_MSG_SEQ,
                                  "%s: recv data has no seq numbers when required. Discarding.\n",
                                  session->name);
-                       u64_stats_update_begin(&sstats->syncp);
-                       sstats->rx_seq_discards++;
-                       u64_stats_update_end(&sstats->syncp);
+                       atomic_long_inc(&session->stats.rx_seq_discards);
                        goto discard;
                }
        }
@@ -788,9 +767,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
                         * packets
                         */
                        if (L2TP_SKB_CB(skb)->ns != session->nr) {
-                               u64_stats_update_begin(&sstats->syncp);
-                               sstats->rx_seq_discards++;
-                               u64_stats_update_end(&sstats->syncp);
+                               atomic_long_inc(&session->stats.rx_seq_discards);
                                l2tp_dbg(session, L2TP_MSG_SEQ,
                                         "%s: oos pkt %u len %d discarded, waiting for %u, reorder_q_len=%d\n",
                                         session->name, L2TP_SKB_CB(skb)->ns,
@@ -816,9 +793,7 @@ void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb,
        return;
 
 discard:
-       u64_stats_update_begin(&sstats->syncp);
-       sstats->rx_errors++;
-       u64_stats_update_end(&sstats->syncp);
+       atomic_long_inc(&session->stats.rx_errors);
        kfree_skb(skb);
 
        if (session->deref)
@@ -828,6 +803,23 @@ discard:
 }
 EXPORT_SYMBOL(l2tp_recv_common);
 
+/* Drop skbs from the session's reorder_q
+ */
+int l2tp_session_queue_purge(struct l2tp_session *session)
+{
+       struct sk_buff *skb = NULL;
+       BUG_ON(!session);
+       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+       while ((skb = skb_dequeue(&session->reorder_q))) {
+               atomic_long_inc(&session->stats.rx_errors);
+               kfree_skb(skb);
+               if (session->deref)
+                       (*session->deref)(session);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_queue_purge);
+
 /* Internal UDP receive frame. Do the real work of receiving an L2TP data frame
  * here. The skb is not on a list when we get here.
  * Returns 0 if the packet was a data packet and was successfully passed on.
@@ -843,7 +835,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
        u32 tunnel_id, session_id;
        u16 version;
        int length;
-       struct l2tp_stats *tstats;
 
        if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb))
                goto discard_bad_csum;
@@ -932,10 +923,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
 discard_bad_csum:
        LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
        UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0);
-       tstats = &tunnel->stats;
-       u64_stats_update_begin(&tstats->syncp);
-       tstats->rx_errors++;
-       u64_stats_update_end(&tstats->syncp);
+       atomic_long_inc(&tunnel->stats.rx_errors);
        kfree_skb(skb);
 
        return 0;
@@ -1062,7 +1050,6 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        struct l2tp_tunnel *tunnel = session->tunnel;
        unsigned int len = skb->len;
        int error;
-       struct l2tp_stats *tstats, *sstats;
 
        /* Debug */
        if (session->send_seq)
@@ -1091,21 +1078,15 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
                error = ip_queue_xmit(skb, fl);
 
        /* Update stats */
-       tstats = &tunnel->stats;
-       u64_stats_update_begin(&tstats->syncp);
-       sstats = &session->stats;
-       u64_stats_update_begin(&sstats->syncp);
        if (error >= 0) {
-               tstats->tx_packets++;
-               tstats->tx_bytes += len;
-               sstats->tx_packets++;
-               sstats->tx_bytes += len;
+               atomic_long_inc(&tunnel->stats.tx_packets);
+               atomic_long_add(len, &tunnel->stats.tx_bytes);
+               atomic_long_inc(&session->stats.tx_packets);
+               atomic_long_add(len, &session->stats.tx_bytes);
        } else {
-               tstats->tx_errors++;
-               sstats->tx_errors++;
+               atomic_long_inc(&tunnel->stats.tx_errors);
+               atomic_long_inc(&session->stats.tx_errors);
        }
-       u64_stats_update_end(&tstats->syncp);
-       u64_stats_update_end(&sstats->syncp);
 
        return 0;
 }
@@ -1282,6 +1263,7 @@ static void l2tp_tunnel_destruct(struct sock *sk)
                /* No longer an encapsulation socket. See net/ipv4/udp.c */
                (udp_sk(sk))->encap_type = 0;
                (udp_sk(sk))->encap_rcv = NULL;
+               (udp_sk(sk))->encap_destroy = NULL;
                break;
        case L2TP_ENCAPTYPE_IP:
                break;
@@ -1311,7 +1293,7 @@ end:
 
 /* When the tunnel is closed, all the attached sessions need to go too.
  */
-static void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
+void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
 {
        int hash;
        struct hlist_node *walk;
@@ -1334,25 +1316,13 @@ again:
 
                        hlist_del_init(&session->hlist);
 
-                       /* Since we should hold the sock lock while
-                        * doing any unbinding, we need to release the
-                        * lock we're holding before taking that lock.
-                        * Hold a reference to the sock so it doesn't
-                        * disappear as we're jumping between locks.
-                        */
                        if (session->ref != NULL)
                                (*session->ref)(session);
 
                        write_unlock_bh(&tunnel->hlist_lock);
 
-                       if (tunnel->version != L2TP_HDR_VER_2) {
-                               struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
-
-                               spin_lock_bh(&pn->l2tp_session_hlist_lock);
-                               hlist_del_init_rcu(&session->global_hlist);
-                               spin_unlock_bh(&pn->l2tp_session_hlist_lock);
-                               synchronize_rcu();
-                       }
+                       __l2tp_session_unhash(session);
+                       l2tp_session_queue_purge(session);
 
                        if (session->session_close != NULL)
                                (*session->session_close)(session);
@@ -1360,6 +1330,8 @@ again:
                        if (session->deref != NULL)
                                (*session->deref)(session);
 
+                       l2tp_session_dec_refcount(session);
+
                        write_lock_bh(&tunnel->hlist_lock);
 
                        /* Now restart from the beginning of this hash
@@ -1372,6 +1344,17 @@ again:
        }
        write_unlock_bh(&tunnel->hlist_lock);
 }
+EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall);
+
+/* Tunnel socket destroy hook for UDP encapsulation */
+static void l2tp_udp_encap_destroy(struct sock *sk)
+{
+       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
+       if (tunnel) {
+               l2tp_tunnel_closeall(tunnel);
+               sock_put(sk);
+       }
+}
 
 /* Really kill the tunnel.
  * Come here only when all sessions have been cleared from the tunnel.
@@ -1397,19 +1380,21 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
                return;
 
        sock = sk->sk_socket;
-       BUG_ON(!sock);
 
-       /* If the tunnel socket was created directly by the kernel, use the
-        * sk_* API to release the socket now.  Otherwise go through the
-        * inet_* layer to shut the socket down, and let userspace close it.
+       /* If the tunnel socket was created by userspace, then go through the
+        * inet layer to shut the socket down, and let userspace close it.
+        * Otherwise, if we created the socket directly within the kernel, use
+        * the sk API to release it here.
         * In either case the tunnel resources are freed in the socket
         * destructor when the tunnel socket goes away.
         */
-       if (sock->file == NULL) {
-               kernel_sock_shutdown(sock, SHUT_RDWR);
-               sk_release_kernel(sk);
+       if (tunnel->fd >= 0) {
+               if (sock)
+                       inet_shutdown(sock, 2);
        } else {
-               inet_shutdown(sock, 2);
+               if (sock)
+                       kernel_sock_shutdown(sock, SHUT_RDWR);
+               sk_release_kernel(sk);
        }
 
        l2tp_tunnel_sock_put(sk);
@@ -1668,6 +1653,7 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
                udp_sk(sk)->encap_type = UDP_ENCAP_L2TPINUDP;
                udp_sk(sk)->encap_rcv = l2tp_udp_encap_recv;
+               udp_sk(sk)->encap_destroy = l2tp_udp_encap_destroy;
 #if IS_ENABLED(CONFIG_IPV6)
                if (sk->sk_family == PF_INET6)
                        udpv6_encap_enable();
@@ -1723,6 +1709,7 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_create);
  */
 int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel)
 {
+       l2tp_tunnel_closeall(tunnel);
        return (false == queue_work(l2tp_wq, &tunnel->del_work));
 }
 EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
@@ -1731,62 +1718,71 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_delete);
  */
 void l2tp_session_free(struct l2tp_session *session)
 {
-       struct l2tp_tunnel *tunnel;
+       struct l2tp_tunnel *tunnel = session->tunnel;
 
        BUG_ON(atomic_read(&session->ref_count) != 0);
 
-       tunnel = session->tunnel;
-       if (tunnel != NULL) {
+       if (tunnel) {
                BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
+               if (session->session_id != 0)
+                       atomic_dec(&l2tp_session_count);
+               sock_put(tunnel->sock);
+               session->tunnel = NULL;
+               l2tp_tunnel_dec_refcount(tunnel);
+       }
+
+       kfree(session);
 
-               /* Delete the session from the hash */
+       return;
+}
+EXPORT_SYMBOL_GPL(l2tp_session_free);
+
+/* Remove an l2tp session from l2tp_core's hash lists.
+ * Provides a tidyup interface for pseudowire code which can't just route all
+ * shutdown via. l2tp_session_delete and a pseudowire-specific session_close
+ * callback.
+ */
+void __l2tp_session_unhash(struct l2tp_session *session)
+{
+       struct l2tp_tunnel *tunnel = session->tunnel;
+
+       /* Remove the session from core hashes */
+       if (tunnel) {
+               /* Remove from the per-tunnel hash */
                write_lock_bh(&tunnel->hlist_lock);
                hlist_del_init(&session->hlist);
                write_unlock_bh(&tunnel->hlist_lock);
 
-               /* Unlink from the global hash if not L2TPv2 */
+               /* For L2TPv3 we have a per-net hash: remove from there, too */
                if (tunnel->version != L2TP_HDR_VER_2) {
                        struct l2tp_net *pn = l2tp_pernet(tunnel->l2tp_net);
-
                        spin_lock_bh(&pn->l2tp_session_hlist_lock);
                        hlist_del_init_rcu(&session->global_hlist);
                        spin_unlock_bh(&pn->l2tp_session_hlist_lock);
                        synchronize_rcu();
                }
-
-               if (session->session_id != 0)
-                       atomic_dec(&l2tp_session_count);
-
-               sock_put(tunnel->sock);
-
-               /* This will delete the tunnel context if this
-                * is the last session on the tunnel.
-                */
-               session->tunnel = NULL;
-               l2tp_tunnel_dec_refcount(tunnel);
        }
-
-       kfree(session);
-
-       return;
 }
-EXPORT_SYMBOL_GPL(l2tp_session_free);
+EXPORT_SYMBOL_GPL(__l2tp_session_unhash);
 
 /* This function is used by the netlink SESSION_DELETE command and by
    pseudowire modules.
  */
 int l2tp_session_delete(struct l2tp_session *session)
 {
+       if (session->ref)
+               (*session->ref)(session);
+       __l2tp_session_unhash(session);
+       l2tp_session_queue_purge(session);
        if (session->session_close != NULL)
                (*session->session_close)(session);
-
+       if (session->deref)
+               (*session->ref)(session);
        l2tp_session_dec_refcount(session);
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(l2tp_session_delete);
 
-
 /* We come here whenever a session's send_seq, cookie_len or
  * l2specific_len parameters are set.
  */
index 8eb8f1d..485a490 100644 (file)
@@ -36,16 +36,15 @@ enum {
 struct sk_buff;
 
 struct l2tp_stats {
-       u64                     tx_packets;
-       u64                     tx_bytes;
-       u64                     tx_errors;
-       u64                     rx_packets;
-       u64                     rx_bytes;
-       u64                     rx_seq_discards;
-       u64                     rx_oos_packets;
-       u64                     rx_errors;
-       u64                     rx_cookie_discards;
-       struct u64_stats_sync   syncp;
+       atomic_long_t           tx_packets;
+       atomic_long_t           tx_bytes;
+       atomic_long_t           tx_errors;
+       atomic_long_t           rx_packets;
+       atomic_long_t           rx_bytes;
+       atomic_long_t           rx_seq_discards;
+       atomic_long_t           rx_oos_packets;
+       atomic_long_t           rx_errors;
+       atomic_long_t           rx_cookie_discards;
 };
 
 struct l2tp_tunnel;
@@ -240,11 +239,14 @@ extern struct l2tp_tunnel *l2tp_tunnel_find(struct net *net, u32 tunnel_id);
 extern struct l2tp_tunnel *l2tp_tunnel_find_nth(struct net *net, int nth);
 
 extern int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 peer_tunnel_id, struct l2tp_tunnel_cfg *cfg, struct l2tp_tunnel **tunnelp);
+extern void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel);
 extern int l2tp_tunnel_delete(struct l2tp_tunnel *tunnel);
 extern struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunnel, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg);
+extern void __l2tp_session_unhash(struct l2tp_session *session);
 extern int l2tp_session_delete(struct l2tp_session *session);
 extern void l2tp_session_free(struct l2tp_session *session);
 extern void l2tp_recv_common(struct l2tp_session *session, struct sk_buff *skb, unsigned char *ptr, unsigned char *optr, u16 hdrflags, int length, int (*payload_hook)(struct sk_buff *skb));
+extern int l2tp_session_queue_purge(struct l2tp_session *session);
 extern int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb);
 
 extern int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len);
index c3813bc..072d720 100644 (file)
@@ -146,14 +146,14 @@ static void l2tp_dfs_seq_tunnel_show(struct seq_file *m, void *v)
                   tunnel->sock ? atomic_read(&tunnel->sock->sk_refcnt) : 0,
                   atomic_read(&tunnel->ref_count));
 
-       seq_printf(m, " %08x rx %llu/%llu/%llu rx %llu/%llu/%llu\n",
+       seq_printf(m, " %08x rx %ld/%ld/%ld rx %ld/%ld/%ld\n",
                   tunnel->debug,
-                  (unsigned long long)tunnel->stats.tx_packets,
-                  (unsigned long long)tunnel->stats.tx_bytes,
-                  (unsigned long long)tunnel->stats.tx_errors,
-                  (unsigned long long)tunnel->stats.rx_packets,
-                  (unsigned long long)tunnel->stats.rx_bytes,
-                  (unsigned long long)tunnel->stats.rx_errors);
+                  atomic_long_read(&tunnel->stats.tx_packets),
+                  atomic_long_read(&tunnel->stats.tx_bytes),
+                  atomic_long_read(&tunnel->stats.tx_errors),
+                  atomic_long_read(&tunnel->stats.rx_packets),
+                  atomic_long_read(&tunnel->stats.rx_bytes),
+                  atomic_long_read(&tunnel->stats.rx_errors));
 
        if (tunnel->show != NULL)
                tunnel->show(m, tunnel);
@@ -203,14 +203,14 @@ static void l2tp_dfs_seq_session_show(struct seq_file *m, void *v)
                seq_printf(m, "\n");
        }
 
-       seq_printf(m, "   %hu/%hu tx %llu/%llu/%llu rx %llu/%llu/%llu\n",
+       seq_printf(m, "   %hu/%hu tx %ld/%ld/%ld rx %ld/%ld/%ld\n",
                   session->nr, session->ns,
-                  (unsigned long long)session->stats.tx_packets,
-                  (unsigned long long)session->stats.tx_bytes,
-                  (unsigned long long)session->stats.tx_errors,
-                  (unsigned long long)session->stats.rx_packets,
-                  (unsigned long long)session->stats.rx_bytes,
-                  (unsigned long long)session->stats.rx_errors);
+                  atomic_long_read(&session->stats.tx_packets),
+                  atomic_long_read(&session->stats.tx_bytes),
+                  atomic_long_read(&session->stats.tx_errors),
+                  atomic_long_read(&session->stats.rx_packets),
+                  atomic_long_read(&session->stats.rx_bytes),
+                  atomic_long_read(&session->stats.rx_errors));
 
        if (session->show != NULL)
                session->show(m, session);
index 7f41b70..571db8d 100644 (file)
@@ -228,10 +228,16 @@ static void l2tp_ip_close(struct sock *sk, long timeout)
 static void l2tp_ip_destroy_sock(struct sock *sk)
 {
        struct sk_buff *skb;
+       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
 
        while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
                kfree_skb(skb);
 
+       if (tunnel) {
+               l2tp_tunnel_closeall(tunnel);
+               sock_put(sk);
+       }
+
        sk_refcnt_debug_dec(sk);
 }
 
index 41f2f81..c74f5a9 100644 (file)
@@ -241,10 +241,17 @@ static void l2tp_ip6_close(struct sock *sk, long timeout)
 
 static void l2tp_ip6_destroy_sock(struct sock *sk)
 {
+       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
+
        lock_sock(sk);
        ip6_flush_pending_frames(sk);
        release_sock(sk);
 
+       if (tunnel) {
+               l2tp_tunnel_closeall(tunnel);
+               sock_put(sk);
+       }
+
        inet6_destroy_sock(sk);
 }
 
index c1bab22..0825ff2 100644 (file)
@@ -246,8 +246,6 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
 #if IS_ENABLED(CONFIG_IPV6)
        struct ipv6_pinfo *np = NULL;
 #endif
-       struct l2tp_stats stats;
-       unsigned int start;
 
        hdr = genlmsg_put(skb, portid, seq, &l2tp_nl_family, flags,
                          L2TP_CMD_TUNNEL_GET);
@@ -265,28 +263,22 @@ static int l2tp_nl_tunnel_send(struct sk_buff *skb, u32 portid, u32 seq, int fla
        if (nest == NULL)
                goto nla_put_failure;
 
-       do {
-               start = u64_stats_fetch_begin(&tunnel->stats.syncp);
-               stats.tx_packets = tunnel->stats.tx_packets;
-               stats.tx_bytes = tunnel->stats.tx_bytes;
-               stats.tx_errors = tunnel->stats.tx_errors;
-               stats.rx_packets = tunnel->stats.rx_packets;
-               stats.rx_bytes = tunnel->stats.rx_bytes;
-               stats.rx_errors = tunnel->stats.rx_errors;
-               stats.rx_seq_discards = tunnel->stats.rx_seq_discards;
-               stats.rx_oos_packets = tunnel->stats.rx_oos_packets;
-       } while (u64_stats_fetch_retry(&tunnel->stats.syncp, start));
-
-       if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) ||
-           nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) ||
-           nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) ||
-           nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) ||
-           nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) ||
+       if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS,
+                   atomic_long_read(&tunnel->stats.tx_packets)) ||
+           nla_put_u64(skb, L2TP_ATTR_TX_BYTES,
+                   atomic_long_read(&tunnel->stats.tx_bytes)) ||
+           nla_put_u64(skb, L2TP_ATTR_TX_ERRORS,
+                   atomic_long_read(&tunnel->stats.tx_errors)) ||
+           nla_put_u64(skb, L2TP_ATTR_RX_PACKETS,
+                   atomic_long_read(&tunnel->stats.rx_packets)) ||
+           nla_put_u64(skb, L2TP_ATTR_RX_BYTES,
+                   atomic_long_read(&tunnel->stats.rx_bytes)) ||
            nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS,
-                       stats.rx_seq_discards) ||
+                   atomic_long_read(&tunnel->stats.rx_seq_discards)) ||
            nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS,
-                       stats.rx_oos_packets) ||
-           nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors))
+                   atomic_long_read(&tunnel->stats.rx_oos_packets)) ||
+           nla_put_u64(skb, L2TP_ATTR_RX_ERRORS,
+                   atomic_long_read(&tunnel->stats.rx_errors)))
                goto nla_put_failure;
        nla_nest_end(skb, nest);
 
@@ -612,8 +604,6 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
        struct nlattr *nest;
        struct l2tp_tunnel *tunnel = session->tunnel;
        struct sock *sk = NULL;
-       struct l2tp_stats stats;
-       unsigned int start;
 
        sk = tunnel->sock;
 
@@ -656,28 +646,22 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl
        if (nest == NULL)
                goto nla_put_failure;
 
-       do {
-               start = u64_stats_fetch_begin(&session->stats.syncp);
-               stats.tx_packets = session->stats.tx_packets;
-               stats.tx_bytes = session->stats.tx_bytes;
-               stats.tx_errors = session->stats.tx_errors;
-               stats.rx_packets = session->stats.rx_packets;
-               stats.rx_bytes = session->stats.rx_bytes;
-               stats.rx_errors = session->stats.rx_errors;
-               stats.rx_seq_discards = session->stats.rx_seq_discards;
-               stats.rx_oos_packets = session->stats.rx_oos_packets;
-       } while (u64_stats_fetch_retry(&session->stats.syncp, start));
-
-       if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS, stats.tx_packets) ||
-           nla_put_u64(skb, L2TP_ATTR_TX_BYTES, stats.tx_bytes) ||
-           nla_put_u64(skb, L2TP_ATTR_TX_ERRORS, stats.tx_errors) ||
-           nla_put_u64(skb, L2TP_ATTR_RX_PACKETS, stats.rx_packets) ||
-           nla_put_u64(skb, L2TP_ATTR_RX_BYTES, stats.rx_bytes) ||
+       if (nla_put_u64(skb, L2TP_ATTR_TX_PACKETS,
+               atomic_long_read(&session->stats.tx_packets)) ||
+           nla_put_u64(skb, L2TP_ATTR_TX_BYTES,
+               atomic_long_read(&session->stats.tx_bytes)) ||
+           nla_put_u64(skb, L2TP_ATTR_TX_ERRORS,
+               atomic_long_read(&session->stats.tx_errors)) ||
+           nla_put_u64(skb, L2TP_ATTR_RX_PACKETS,
+               atomic_long_read(&session->stats.rx_packets)) ||
+           nla_put_u64(skb, L2TP_ATTR_RX_BYTES,
+               atomic_long_read(&session->stats.rx_bytes)) ||
            nla_put_u64(skb, L2TP_ATTR_RX_SEQ_DISCARDS,
-                       stats.rx_seq_discards) ||
+               atomic_long_read(&session->stats.rx_seq_discards)) ||
            nla_put_u64(skb, L2TP_ATTR_RX_OOS_PACKETS,
-                       stats.rx_oos_packets) ||
-           nla_put_u64(skb, L2TP_ATTR_RX_ERRORS, stats.rx_errors))
+               atomic_long_read(&session->stats.rx_oos_packets)) ||
+           nla_put_u64(skb, L2TP_ATTR_RX_ERRORS,
+               atomic_long_read(&session->stats.rx_errors)))
                goto nla_put_failure;
        nla_nest_end(skb, nest);
 
index 6a53371..637a341 100644 (file)
@@ -97,6 +97,7 @@
 #include <net/ip.h>
 #include <net/udp.h>
 #include <net/xfrm.h>
+#include <net/inet_common.h>
 
 #include <asm/byteorder.h>
 #include <linux/atomic.h>
@@ -259,7 +260,7 @@ static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int
                          session->name);
 
                /* Not bound. Nothing we can do, so discard. */
-               session->stats.rx_errors++;
+               atomic_long_inc(&session->stats.rx_errors);
                kfree_skb(skb);
        }
 
@@ -447,34 +448,16 @@ static void pppol2tp_session_close(struct l2tp_session *session)
 {
        struct pppol2tp_session *ps = l2tp_session_priv(session);
        struct sock *sk = ps->sock;
-       struct sk_buff *skb;
+       struct socket *sock = sk->sk_socket;
 
        BUG_ON(session->magic != L2TP_SESSION_MAGIC);
 
-       if (session->session_id == 0)
-               goto out;
-
-       if (sk != NULL) {
-               lock_sock(sk);
-
-               if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
-                       pppox_unbind_sock(sk);
-                       sk->sk_state = PPPOX_DEAD;
-                       sk->sk_state_change(sk);
-               }
-
-               /* Purge any queued data */
-               skb_queue_purge(&sk->sk_receive_queue);
-               skb_queue_purge(&sk->sk_write_queue);
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
 
-               release_sock(sk);
+       if (sock) {
+               inet_shutdown(sock, 2);
+               /* Don't let the session go away before our socket does */
+               l2tp_session_inc_refcount(session);
        }
-
-out:
        return;
 }
 
@@ -483,19 +466,12 @@ out:
  */
 static void pppol2tp_session_destruct(struct sock *sk)
 {
-       struct l2tp_session *session;
-
-       if (sk->sk_user_data != NULL) {
-               session = sk->sk_user_data;
-               if (session == NULL)
-                       goto out;
-
+       struct l2tp_session *session = sk->sk_user_data;
+       if (session) {
                sk->sk_user_data = NULL;
                BUG_ON(session->magic != L2TP_SESSION_MAGIC);
                l2tp_session_dec_refcount(session);
        }
-
-out:
        return;
 }
 
@@ -525,16 +501,13 @@ static int pppol2tp_release(struct socket *sock)
        session = pppol2tp_sock_to_session(sk);
 
        /* Purge any queued data */
-       skb_queue_purge(&sk->sk_receive_queue);
-       skb_queue_purge(&sk->sk_write_queue);
        if (session != NULL) {
-               struct sk_buff *skb;
-               while ((skb = skb_dequeue(&session->reorder_q))) {
-                       kfree_skb(skb);
-                       sock_put(sk);
-               }
+               __l2tp_session_unhash(session);
+               l2tp_session_queue_purge(session);
                sock_put(sk);
        }
+       skb_queue_purge(&sk->sk_receive_queue);
+       skb_queue_purge(&sk->sk_write_queue);
 
        release_sock(sk);
 
@@ -880,18 +853,6 @@ out:
        return error;
 }
 
-/* Called when deleting sessions via the netlink interface.
- */
-static int pppol2tp_session_delete(struct l2tp_session *session)
-{
-       struct pppol2tp_session *ps = l2tp_session_priv(session);
-
-       if (ps->sock == NULL)
-               l2tp_session_dec_refcount(session);
-
-       return 0;
-}
-
 #endif /* CONFIG_L2TP_V3 */
 
 /* getname() support.
@@ -1025,14 +986,14 @@ end:
 static void pppol2tp_copy_stats(struct pppol2tp_ioc_stats *dest,
                                struct l2tp_stats *stats)
 {
-       dest->tx_packets = stats->tx_packets;
-       dest->tx_bytes = stats->tx_bytes;
-       dest->tx_errors = stats->tx_errors;
-       dest->rx_packets = stats->rx_packets;
-       dest->rx_bytes = stats->rx_bytes;
-       dest->rx_seq_discards = stats->rx_seq_discards;
-       dest->rx_oos_packets = stats->rx_oos_packets;
-       dest->rx_errors = stats->rx_errors;
+       dest->tx_packets = atomic_long_read(&stats->tx_packets);
+       dest->tx_bytes = atomic_long_read(&stats->tx_bytes);
+       dest->tx_errors = atomic_long_read(&stats->tx_errors);
+       dest->rx_packets = atomic_long_read(&stats->rx_packets);
+       dest->rx_bytes = atomic_long_read(&stats->rx_bytes);
+       dest->rx_seq_discards = atomic_long_read(&stats->rx_seq_discards);
+       dest->rx_oos_packets = atomic_long_read(&stats->rx_oos_packets);
+       dest->rx_errors = atomic_long_read(&stats->rx_errors);
 }
 
 /* Session ioctl helper.
@@ -1666,14 +1627,14 @@ static void pppol2tp_seq_tunnel_show(struct seq_file *m, void *v)
                   tunnel->name,
                   (tunnel == tunnel->sock->sk_user_data) ? 'Y' : 'N',
                   atomic_read(&tunnel->ref_count) - 1);
-       seq_printf(m, " %08x %llu/%llu/%llu %llu/%llu/%llu\n",
+       seq_printf(m, " %08x %ld/%ld/%ld %ld/%ld/%ld\n",
                   tunnel->debug,
-                  (unsigned long long)tunnel->stats.tx_packets,
-                  (unsigned long long)tunnel->stats.tx_bytes,
-                  (unsigned long long)tunnel->stats.tx_errors,
-                  (unsigned long long)tunnel->stats.rx_packets,
-                  (unsigned long long)tunnel->stats.rx_bytes,
-                  (unsigned long long)tunnel->stats.rx_errors);
+                  atomic_long_read(&tunnel->stats.tx_packets),
+                  atomic_long_read(&tunnel->stats.tx_bytes),
+                  atomic_long_read(&tunnel->stats.tx_errors),
+                  atomic_long_read(&tunnel->stats.rx_packets),
+                  atomic_long_read(&tunnel->stats.rx_bytes),
+                  atomic_long_read(&tunnel->stats.rx_errors));
 }
 
 static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
@@ -1708,14 +1669,14 @@ static void pppol2tp_seq_session_show(struct seq_file *m, void *v)
                   session->lns_mode ? "LNS" : "LAC",
                   session->debug,
                   jiffies_to_msecs(session->reorder_timeout));
-       seq_printf(m, "   %hu/%hu %llu/%llu/%llu %llu/%llu/%llu\n",
+       seq_printf(m, "   %hu/%hu %ld/%ld/%ld %ld/%ld/%ld\n",
                   session->nr, session->ns,
-                  (unsigned long long)session->stats.tx_packets,
-                  (unsigned long long)session->stats.tx_bytes,
-                  (unsigned long long)session->stats.tx_errors,
-                  (unsigned long long)session->stats.rx_packets,
-                  (unsigned long long)session->stats.rx_bytes,
-                  (unsigned long long)session->stats.rx_errors);
+                  atomic_long_read(&session->stats.tx_packets),
+                  atomic_long_read(&session->stats.tx_bytes),
+                  atomic_long_read(&session->stats.tx_errors),
+                  atomic_long_read(&session->stats.rx_packets),
+                  atomic_long_read(&session->stats.rx_bytes),
+                  atomic_long_read(&session->stats.rx_errors));
 
        if (po)
                seq_printf(m, "   interface %s\n", ppp_dev_name(&po->chan));
@@ -1839,7 +1800,7 @@ static const struct pppox_proto pppol2tp_proto = {
 
 static const struct l2tp_nl_cmd_ops pppol2tp_nl_cmd_ops = {
        .session_create = pppol2tp_session_create,
-       .session_delete = pppol2tp_session_delete,
+       .session_delete = l2tp_session_delete,
 };
 
 #endif /* CONFIG_L2TP_V3 */
index fb30681..a689360 100644 (file)
@@ -2582,7 +2582,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
                        list_del(&dep->list);
                        mutex_unlock(&local->mtx);
 
-                       ieee80211_roc_notify_destroy(dep);
+                       ieee80211_roc_notify_destroy(dep, true);
                        return 0;
                }
 
@@ -2622,7 +2622,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
                        ieee80211_start_next_roc(local);
                mutex_unlock(&local->mtx);
 
-               ieee80211_roc_notify_destroy(found);
+               ieee80211_roc_notify_destroy(found, true);
        } else {
                /* work may be pending so use it all the time */
                found->abort = true;
@@ -2632,6 +2632,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
 
                /* work will clean up etc */
                flush_delayed_work(&found->work);
+               WARN_ON(!found->to_be_freed);
+               kfree(found);
        }
 
        return 0;
index 78c0d90..931be41 100644 (file)
@@ -63,6 +63,7 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
                      enum ieee80211_chanctx_mode mode)
 {
        struct ieee80211_chanctx *ctx;
+       u32 changed;
        int err;
 
        lockdep_assert_held(&local->chanctx_mtx);
@@ -76,6 +77,13 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
        ctx->conf.rx_chains_dynamic = 1;
        ctx->mode = mode;
 
+       /* acquire mutex to prevent idle from changing */
+       mutex_lock(&local->mtx);
+       /* turn idle off *before* setting channel -- some drivers need that */
+       changed = ieee80211_idle_off(local);
+       if (changed)
+               ieee80211_hw_config(local, changed);
+
        if (!local->use_chanctx) {
                local->_oper_channel_type =
                        cfg80211_get_chandef_type(chandef);
@@ -85,14 +93,17 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
                err = drv_add_chanctx(local, ctx);
                if (err) {
                        kfree(ctx);
-                       return ERR_PTR(err);
+                       ctx = ERR_PTR(err);
+
+                       ieee80211_recalc_idle(local);
+                       goto out;
                }
        }
 
+       /* and keep the mutex held until the new chanctx is on the list */
        list_add_rcu(&ctx->list, &local->chanctx_list);
 
-       mutex_lock(&local->mtx);
-       ieee80211_recalc_idle(local);
+ out:
        mutex_unlock(&local->mtx);
 
        return ctx;
index 388580a..5672533 100644 (file)
@@ -309,6 +309,7 @@ struct ieee80211_roc_work {
        struct ieee80211_channel *chan;
 
        bool started, abort, hw_begun, notified;
+       bool to_be_freed;
 
        unsigned long hw_start_time;
 
@@ -1347,7 +1348,7 @@ void ieee80211_offchannel_return(struct ieee80211_local *local);
 void ieee80211_roc_setup(struct ieee80211_local *local);
 void ieee80211_start_next_roc(struct ieee80211_local *local);
 void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata);
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc);
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free);
 void ieee80211_sw_roc_work(struct work_struct *work);
 void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc);
 
@@ -1361,6 +1362,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata,
                             enum nl80211_iftype type);
 void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata);
 void ieee80211_remove_interfaces(struct ieee80211_local *local);
+u32 ieee80211_idle_off(struct ieee80211_local *local);
 void ieee80211_recalc_idle(struct ieee80211_local *local);
 void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
                                    const int offset);
index baaa860..58150f8 100644 (file)
@@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
 }
 
-static u32 ieee80211_idle_off(struct ieee80211_local *local)
+u32 ieee80211_idle_off(struct ieee80211_local *local)
 {
        if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
                return 0;
@@ -349,21 +349,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
 static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata;
-       int ret = 0;
+       int ret;
 
        if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
                return 0;
 
-       mutex_lock(&local->iflist_mtx);
+       ASSERT_RTNL();
 
        if (local->monitor_sdata)
-               goto out_unlock;
+               return 0;
 
        sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
-       if (!sdata) {
-               ret = -ENOMEM;
-               goto out_unlock;
-       }
+       if (!sdata)
+               return -ENOMEM;
 
        /* set up data */
        sdata->local = local;
@@ -377,13 +375,13 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        if (WARN_ON(ret)) {
                /* ok .. stupid driver, it asked for this! */
                kfree(sdata);
-               goto out_unlock;
+               return ret;
        }
 
        ret = ieee80211_check_queues(sdata);
        if (ret) {
                kfree(sdata);
-               goto out_unlock;
+               return ret;
        }
 
        ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
@@ -391,13 +389,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
        if (ret) {
                drv_remove_interface(local, sdata);
                kfree(sdata);
-               goto out_unlock;
+               return ret;
        }
 
+       mutex_lock(&local->iflist_mtx);
        rcu_assign_pointer(local->monitor_sdata, sdata);
- out_unlock:
        mutex_unlock(&local->iflist_mtx);
-       return ret;
+
+       return 0;
 }
 
 static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@@ -407,14 +406,20 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
        if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
                return;
 
+       ASSERT_RTNL();
+
        mutex_lock(&local->iflist_mtx);
 
        sdata = rcu_dereference_protected(local->monitor_sdata,
                                          lockdep_is_held(&local->iflist_mtx));
-       if (!sdata)
-               goto out_unlock;
+       if (!sdata) {
+               mutex_unlock(&local->iflist_mtx);
+               return;
+       }
 
        rcu_assign_pointer(local->monitor_sdata, NULL);
+       mutex_unlock(&local->iflist_mtx);
+
        synchronize_net();
 
        ieee80211_vif_release_channel(sdata);
@@ -422,8 +427,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
        drv_remove_interface(local, sdata);
 
        kfree(sdata);
- out_unlock:
-       mutex_unlock(&local->iflist_mtx);
 }
 
 /*
index 29ce2aa..4749b38 100644 (file)
@@ -1060,7 +1060,8 @@ void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local)
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               if (ieee80211_vif_is_mesh(&sdata->vif))
+               if (ieee80211_vif_is_mesh(&sdata->vif) &&
+                   ieee80211_sdata_running(sdata))
                        ieee80211_queue_work(&local->hw, &sdata->work);
        rcu_read_unlock();
 }
index 1415774..82cc303 100644 (file)
@@ -3608,8 +3608,10 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
 
        /* Restart STA timers */
        rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list)
-               ieee80211_restart_sta_timer(sdata);
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (ieee80211_sdata_running(sdata))
+                       ieee80211_restart_sta_timer(sdata);
+       }
        rcu_read_unlock();
 }
 
index cc79b4a..430bd25 100644 (file)
@@ -297,10 +297,13 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
        }
 }
 
-void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
+void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc, bool free)
 {
        struct ieee80211_roc_work *dep, *tmp;
 
+       if (WARN_ON(roc->to_be_freed))
+               return;
+
        /* was never transmitted */
        if (roc->frame) {
                cfg80211_mgmt_tx_status(&roc->sdata->wdev,
@@ -316,9 +319,12 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
                                                   GFP_KERNEL);
 
        list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
-               ieee80211_roc_notify_destroy(dep);
+               ieee80211_roc_notify_destroy(dep, true);
 
-       kfree(roc);
+       if (free)
+               kfree(roc);
+       else
+               roc->to_be_freed = true;
 }
 
 void ieee80211_sw_roc_work(struct work_struct *work)
@@ -331,6 +337,9 @@ void ieee80211_sw_roc_work(struct work_struct *work)
 
        mutex_lock(&local->mtx);
 
+       if (roc->to_be_freed)
+               goto out_unlock;
+
        if (roc->abort)
                goto finish;
 
@@ -370,7 +379,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
  finish:
                list_del(&roc->list);
                started = roc->started;
-               ieee80211_roc_notify_destroy(roc);
+               ieee80211_roc_notify_destroy(roc, !roc->abort);
 
                if (started) {
                        drv_flush(local, false);
@@ -410,7 +419,7 @@ static void ieee80211_hw_roc_done(struct work_struct *work)
 
        list_del(&roc->list);
 
-       ieee80211_roc_notify_destroy(roc);
+       ieee80211_roc_notify_destroy(roc, true);
 
        /* if there's another roc, start it now */
        ieee80211_start_next_roc(local);
@@ -460,12 +469,14 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata)
        list_for_each_entry_safe(roc, tmp, &tmp_list, list) {
                if (local->ops->remain_on_channel) {
                        list_del(&roc->list);
-                       ieee80211_roc_notify_destroy(roc);
+                       ieee80211_roc_notify_destroy(roc, true);
                } else {
                        ieee80211_queue_delayed_work(&local->hw, &roc->work, 0);
 
                        /* work will clean up etc */
                        flush_delayed_work(&roc->work);
+                       WARN_ON(!roc->to_be_freed);
+                       kfree(roc);
                }
        }
 
index bb73ed2..c6844ad 100644 (file)
@@ -2675,7 +2675,19 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
 
                memset(nskb->cb, 0, sizeof(nskb->cb));
 
-               ieee80211_tx_skb(rx->sdata, nskb);
+               if (rx->sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE) {
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
+
+                       info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
+                                     IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
+                                     IEEE80211_TX_CTL_NO_CCK_RATE;
+                       if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
+                               info->hw_queue =
+                                       local->hw.offchannel_tx_hw_queue;
+               }
+
+               __ieee80211_tx_skb_tid_band(rx->sdata, nskb, 7,
+                                           status->band);
        }
        dev_kfree_skb(rx->skb);
        return RX_QUEUED;
index a79ce82..238a0cc 100644 (file)
@@ -766,6 +766,7 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
        struct ieee80211_local *local;
        struct ieee80211_sub_if_data *sdata;
        int ret, i;
+       bool have_key = false;
 
        might_sleep();
 
@@ -793,12 +794,19 @@ int __must_check __sta_info_destroy(struct sta_info *sta)
        list_del_rcu(&sta->list);
 
        mutex_lock(&local->key_mtx);
-       for (i = 0; i < NUM_DEFAULT_KEYS; i++)
+       for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
                __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
-       if (sta->ptk)
+               have_key = true;
+       }
+       if (sta->ptk) {
                __ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
+               have_key = true;
+       }
        mutex_unlock(&local->key_mtx);
 
+       if (!have_key)
+               synchronize_net();
+
        sta->dead = true;
 
        local->num_sta--;
index 47edf5a..61f49d2 100644 (file)
@@ -1394,10 +1394,8 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
                        skb_reset_network_header(skb);
                        IP_VS_DBG(12, "ICMP for IPIP %pI4->%pI4: mtu=%u\n",
                                &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, mtu);
-                       rcu_read_lock();
                        ipv4_update_pmtu(skb, dev_net(skb->dev),
                                         mtu, 0, 0, 0, 0);
-                       rcu_read_unlock();
                        /* Client uses PMTUD? */
                        if (!(cih->frag_off & htons(IP_DF)))
                                goto ignore_ipip;
@@ -1577,7 +1575,8 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
        }
        /* ipvs enabled in this netns ? */
        net = skb_net(skb);
-       if (!net_ipvs(net)->enable)
+       ipvs = net_ipvs(net);
+       if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
                return NF_ACCEPT;
 
        ip_vs_fill_iph_skb(af, skb, &iph);
@@ -1654,7 +1653,6 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
        }
 
        IP_VS_DBG_PKT(11, af, pp, skb, 0, "Incoming packet");
-       ipvs = net_ipvs(net);
        /* Check the server status */
        if (cp->dest && !(cp->dest->flags & IP_VS_DEST_F_AVAILABLE)) {
                /* the destination server is not available */
@@ -1815,13 +1813,15 @@ ip_vs_forward_icmp(unsigned int hooknum, struct sk_buff *skb,
 {
        int r;
        struct net *net;
+       struct netns_ipvs *ipvs;
 
        if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
                return NF_ACCEPT;
 
        /* ipvs enabled in this netns ? */
        net = skb_net(skb);
-       if (!net_ipvs(net)->enable)
+       ipvs = net_ipvs(net);
+       if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
                return NF_ACCEPT;
 
        return ip_vs_in_icmp(skb, &r, hooknum);
@@ -1835,6 +1835,7 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
 {
        int r;
        struct net *net;
+       struct netns_ipvs *ipvs;
        struct ip_vs_iphdr iphdr;
 
        ip_vs_fill_iph_skb(AF_INET6, skb, &iphdr);
@@ -1843,7 +1844,8 @@ ip_vs_forward_icmp_v6(unsigned int hooknum, struct sk_buff *skb,
 
        /* ipvs enabled in this netns ? */
        net = skb_net(skb);
-       if (!net_ipvs(net)->enable)
+       ipvs = net_ipvs(net);
+       if (unlikely(sysctl_backup_only(ipvs) || !ipvs->enable))
                return NF_ACCEPT;
 
        return ip_vs_in_icmp_v6(skb, &r, hooknum, &iphdr);
index c68198b..9e2d1cc 100644 (file)
@@ -1808,6 +1808,12 @@ static struct ctl_table vs_vars[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "backup_only",
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
 #ifdef CONFIG_IP_VS_DEBUG
        {
                .procname       = "debug_level",
@@ -3741,6 +3747,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct net *net)
        tbl[idx++].data = &ipvs->sysctl_nat_icmp_send;
        ipvs->sysctl_pmtu_disc = 1;
        tbl[idx++].data = &ipvs->sysctl_pmtu_disc;
+       tbl[idx++].data = &ipvs->sysctl_backup_only;
 
 
        ipvs->sysctl_hdr = register_net_sysctl(net, "net/ipv4/vs", tbl);
index ae8ec6f..cd1d729 100644 (file)
@@ -906,7 +906,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
        sctp_chunkhdr_t _sctpch, *sch;
        unsigned char chunk_type;
        int event, next_state;
-       int ihl;
+       int ihl, cofs;
 
 #ifdef CONFIG_IP_VS_IPV6
        ihl = cp->af == AF_INET ? ip_hdrlen(skb) : sizeof(struct ipv6hdr);
@@ -914,8 +914,8 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
        ihl = ip_hdrlen(skb);
 #endif
 
-       sch = skb_header_pointer(skb, ihl + sizeof(sctp_sctphdr_t),
-                               sizeof(_sctpch), &_sctpch);
+       cofs = ihl + sizeof(sctp_sctphdr_t);
+       sch = skb_header_pointer(skb, cofs, sizeof(_sctpch), &_sctpch);
        if (sch == NULL)
                return;
 
@@ -933,10 +933,12 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,
         */
        if ((sch->type == SCTP_CID_COOKIE_ECHO) ||
            (sch->type == SCTP_CID_COOKIE_ACK)) {
-               sch = skb_header_pointer(skb, (ihl + sizeof(sctp_sctphdr_t) +
-                               sch->length), sizeof(_sctpch), &_sctpch);
-               if (sch) {
-                       if (sch->type == SCTP_CID_ABORT)
+               int clen = ntohs(sch->length);
+
+               if (clen >= sizeof(sctp_chunkhdr_t)) {
+                       sch = skb_header_pointer(skb, cofs + ALIGN(clen, 4),
+                                                sizeof(_sctpch), &_sctpch);
+                       if (sch && sch->type == SCTP_CID_ABORT)
                                chunk_type = sch->type;
                }
        }
index 432f957..ba65b20 100644 (file)
@@ -969,6 +969,10 @@ static int __init nf_conntrack_proto_dccp_init(void)
 {
        int ret;
 
+       ret = register_pernet_subsys(&dccp_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
        ret = nf_ct_l4proto_register(&dccp_proto4);
        if (ret < 0)
                goto out_dccp4;
@@ -977,16 +981,12 @@ static int __init nf_conntrack_proto_dccp_init(void)
        if (ret < 0)
                goto out_dccp6;
 
-       ret = register_pernet_subsys(&dccp_net_ops);
-       if (ret < 0)
-               goto out_pernet;
-
        return 0;
-out_pernet:
-       nf_ct_l4proto_unregister(&dccp_proto6);
 out_dccp6:
        nf_ct_l4proto_unregister(&dccp_proto4);
 out_dccp4:
+       unregister_pernet_subsys(&dccp_net_ops);
+out_pernet:
        return ret;
 }
 
index bd7d01d..155ce9f 100644 (file)
@@ -420,18 +420,18 @@ static int __init nf_ct_proto_gre_init(void)
 {
        int ret;
 
-       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4);
-       if (ret < 0)
-               goto out_gre4;
-
        ret = register_pernet_subsys(&proto_gre_net_ops);
        if (ret < 0)
                goto out_pernet;
 
+       ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_gre4);
+       if (ret < 0)
+               goto out_gre4;
+
        return 0;
-out_pernet:
-       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_gre4);
 out_gre4:
+       unregister_pernet_subsys(&proto_gre_net_ops);
+out_pernet:
        return ret;
 }
 
index 480f616..ec83536 100644 (file)
@@ -888,6 +888,10 @@ static int __init nf_conntrack_proto_sctp_init(void)
 {
        int ret;
 
+       ret = register_pernet_subsys(&sctp_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
        ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_sctp4);
        if (ret < 0)
                goto out_sctp4;
@@ -896,16 +900,12 @@ static int __init nf_conntrack_proto_sctp_init(void)
        if (ret < 0)
                goto out_sctp6;
 
-       ret = register_pernet_subsys(&sctp_net_ops);
-       if (ret < 0)
-               goto out_pernet;
-
        return 0;
-out_pernet:
-       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
 out_sctp6:
        nf_ct_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
 out_sctp4:
+       unregister_pernet_subsys(&sctp_net_ops);
+out_pernet:
        return ret;
 }
 
index 1574895..ca969f6 100644 (file)
@@ -371,6 +371,10 @@ static int __init nf_conntrack_proto_udplite_init(void)
 {
        int ret;
 
+       ret = register_pernet_subsys(&udplite_net_ops);
+       if (ret < 0)
+               goto out_pernet;
+
        ret = nf_ct_l4proto_register(&nf_conntrack_l4proto_udplite4);
        if (ret < 0)
                goto out_udplite4;
@@ -379,16 +383,12 @@ static int __init nf_conntrack_proto_udplite_init(void)
        if (ret < 0)
                goto out_udplite6;
 
-       ret = register_pernet_subsys(&udplite_net_ops);
-       if (ret < 0)
-               goto out_pernet;
-
        return 0;
-out_pernet:
-       nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
 out_udplite6:
        nf_ct_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
 out_udplite4:
+       unregister_pernet_subsys(&udplite_net_ops);
+out_pernet:
        return ret;
 }
 
index 6bcce40..fedee39 100644 (file)
@@ -568,6 +568,7 @@ static int __init nf_conntrack_standalone_init(void)
                register_net_sysctl(&init_net, "net", nf_ct_netfilter_table);
        if (!nf_ct_netfilter_header) {
                pr_err("nf_conntrack: can't register to sysctl.\n");
+               ret = -ENOMEM;
                goto out_sysctl;
        }
 #endif
index 589d686..dc3fd5d 100644 (file)
@@ -49,6 +49,8 @@ nfnl_acct_new(struct sock *nfnl, struct sk_buff *skb,
                return -EINVAL;
 
        acct_name = nla_data(tb[NFACCT_NAME]);
+       if (strlen(acct_name) == 0)
+               return -EINVAL;
 
        list_for_each_entry(nfacct, &nfnl_acct_list, head) {
                if (strncmp(nfacct->name, acct_name, NFACCT_NAME_MAX) != 0)
index 858fd52..42680b2 100644 (file)
@@ -112,7 +112,7 @@ instance_create(u_int16_t queue_num, int portid)
        inst->queue_num = queue_num;
        inst->peer_portid = portid;
        inst->queue_maxlen = NFQNL_QMAX_DEFAULT;
-       inst->copy_range = 0xfffff;
+       inst->copy_range = 0xffff;
        inst->copy_mode = NFQNL_COPY_NONE;
        spin_lock_init(&inst->lock);
        INIT_LIST_HEAD(&inst->queue_list);
@@ -1062,8 +1062,10 @@ static int __init nfnetlink_queue_init(void)
 
 #ifdef CONFIG_PROC_FS
        if (!proc_create("nfnetlink_queue", 0440,
-                        proc_net_netfilter, &nfqnl_file_ops))
+                        proc_net_netfilter, &nfqnl_file_ops)) {
+               status = -ENOMEM;
                goto cleanup_subsys;
+       }
 #endif
 
        register_netdevice_notifier(&nfqnl_dev_notifier);
index f2aabb6..5a55be3 100644 (file)
@@ -142,6 +142,7 @@ int genl_register_mc_group(struct genl_family *family,
        int err = 0;
 
        BUG_ON(grp->name[0] == '\0');
+       BUG_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL);
 
        genl_lock();
 
index b530afa..ee25f25 100644 (file)
@@ -107,8 +107,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
                                accept_sk->sk_state_change(sk);
 
                                bh_unlock_sock(accept_sk);
-
-                               sock_orphan(accept_sk);
                        }
 
                        if (listen == true) {
@@ -134,8 +132,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
 
                bh_unlock_sock(sk);
 
-               sock_orphan(sk);
-
                sk_del_node_init(sk);
        }
 
@@ -164,8 +160,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
 
                bh_unlock_sock(sk);
 
-               sock_orphan(sk);
-
                sk_del_node_init(sk);
        }
 
@@ -827,7 +821,6 @@ static void nfc_llcp_recv_ui(struct nfc_llcp_local *local,
                skb_get(skb);
        } else {
                pr_err("Receive queue is full\n");
-               kfree_skb(skb);
        }
 
        nfc_llcp_sock_put(llcp_sock);
@@ -1028,7 +1021,6 @@ static void nfc_llcp_recv_hdlc(struct nfc_llcp_local *local,
                        skb_get(skb);
                } else {
                        pr_err("Receive queue is full\n");
-                       kfree_skb(skb);
                }
        }
 
index 5c7cdf3..8f02574 100644 (file)
@@ -270,7 +270,9 @@ struct sock *nfc_llcp_accept_dequeue(struct sock *parent,
                }
 
                if (sk->sk_state == LLCP_CONNECTED || !newsock) {
-                       nfc_llcp_accept_unlink(sk);
+                       list_del_init(&lsk->accept_queue);
+                       sock_put(sk);
+
                        if (newsock)
                                sock_graft(sk, newsock);
 
@@ -464,8 +466,6 @@ static int llcp_sock_release(struct socket *sock)
                        nfc_llcp_accept_unlink(accept_sk);
 
                        release_sock(accept_sk);
-
-                       sock_orphan(accept_sk);
                }
        }
 
index 13aa47a..1bc210f 100644 (file)
@@ -962,8 +962,11 @@ cbq_dequeue(struct Qdisc *sch)
                cbq_update(q);
                if ((incr -= incr2) < 0)
                        incr = 0;
+               q->now += incr;
+       } else {
+               if (now > q->now)
+                       q->now = now;
        }
-       q->now += incr;
        q->now_rt = now;
 
        for (;;) {
index 4e606fc..5578628 100644 (file)
@@ -195,7 +195,7 @@ static int fq_codel_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                flow->deficit = q->quantum;
                flow->dropped = 0;
        }
-       if (++sch->q.qlen < sch->limit)
+       if (++sch->q.qlen <= sch->limit)
                return NET_XMIT_SUCCESS;
 
        q->drop_overlimit++;
index ffad481..eac7e0e 100644 (file)
@@ -904,7 +904,7 @@ void psched_ratecfg_precompute(struct psched_ratecfg *r, u32 rate)
        u64 mult;
        int shift;
 
-       r->rate_bps = rate << 3;
+       r->rate_bps = (u64)rate << 3;
        r->shift = 0;
        r->mult = 1;
        /*
index fb20f25..f8529fc 100644 (file)
@@ -180,6 +180,8 @@ static void __rpc_add_wait_queue(struct rpc_wait_queue *queue,
                list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
        task->tk_waitqueue = queue;
        queue->qlen++;
+       /* barrier matches the read in rpc_wake_up_task_queue_locked() */
+       smp_wmb();
        rpc_set_queued(task);
 
        dprintk("RPC: %5u added to queue %p \"%s\"\n",
@@ -430,8 +432,11 @@ static void __rpc_do_wake_up_task(struct rpc_wait_queue *queue, struct rpc_task
  */
 static void rpc_wake_up_task_queue_locked(struct rpc_wait_queue *queue, struct rpc_task *task)
 {
-       if (RPC_IS_QUEUED(task) && task->tk_waitqueue == queue)
-               __rpc_do_wake_up_task(queue, task);
+       if (RPC_IS_QUEUED(task)) {
+               smp_rmb();
+               if (task->tk_waitqueue == queue)
+                       __rpc_do_wake_up_task(queue, task);
+       }
 }
 
 /*
index 51be64f..2db702d 100644 (file)
@@ -382,7 +382,7 @@ static void unix_sock_destructor(struct sock *sk)
 #endif
 }
 
-static int unix_release_sock(struct sock *sk, int embrion)
+static void unix_release_sock(struct sock *sk, int embrion)
 {
        struct unix_sock *u = unix_sk(sk);
        struct path path;
@@ -451,8 +451,6 @@ static int unix_release_sock(struct sock *sk, int embrion)
 
        if (unix_tot_inflight)
                unix_gc();              /* Garbage collect fds */
-
-       return 0;
 }
 
 static void init_peercred(struct sock *sk)
@@ -699,9 +697,10 @@ static int unix_release(struct socket *sock)
        if (!sk)
                return 0;
 
+       unix_release_sock(sk, 0);
        sock->sk = NULL;
 
-       return unix_release_sock(sk, 0);
+       return 0;
 }
 
 static int unix_autobind(struct socket *sock)
@@ -1994,7 +1993,7 @@ again:
                        if ((UNIXCB(skb).pid  != siocb->scm->pid) ||
                            (UNIXCB(skb).cred != siocb->scm->cred))
                                break;
-               } else {
+               } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
                        /* Copy credentials */
                        scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
                        check_creds = 1;
index ca511c4..d8079da 100644 (file)
@@ -207,7 +207,7 @@ static struct sock *__vsock_find_bound_socket(struct sockaddr_vm *addr)
        struct vsock_sock *vsk;
 
        list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table)
-               if (vsock_addr_equals_addr_any(addr, &vsk->local_addr))
+               if (addr->svm_port == vsk->local_addr.svm_port)
                        return sk_vsock(vsk);
 
        return NULL;
@@ -220,8 +220,8 @@ static struct sock *__vsock_find_connected_socket(struct sockaddr_vm *src,
 
        list_for_each_entry(vsk, vsock_connected_sockets(src, dst),
                            connected_table) {
-               if (vsock_addr_equals_addr(src, &vsk->remote_addr)
-                   && vsock_addr_equals_addr(dst, &vsk->local_addr)) {
+               if (vsock_addr_equals_addr(src, &vsk->remote_addr) &&
+                   dst->svm_port == vsk->local_addr.svm_port) {
                        return sk_vsock(vsk);
                }
        }
index a70ace8..1f6508e 100644 (file)
@@ -464,19 +464,16 @@ static struct sock *vmci_transport_get_pending(
        struct vsock_sock *vlistener;
        struct vsock_sock *vpending;
        struct sock *pending;
+       struct sockaddr_vm src;
+
+       vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
 
        vlistener = vsock_sk(listener);
 
        list_for_each_entry(vpending, &vlistener->pending_links,
                            pending_links) {
-               struct sockaddr_vm src;
-               struct sockaddr_vm dst;
-
-               vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
-               vsock_addr_init(&dst, pkt->dg.dst.context, pkt->dst_port);
-
                if (vsock_addr_equals_addr(&src, &vpending->remote_addr) &&
-                   vsock_addr_equals_addr(&dst, &vpending->local_addr)) {
+                   pkt->dst_port == vpending->local_addr.svm_port) {
                        pending = sk_vsock(vpending);
                        sock_hold(pending);
                        goto found;
@@ -739,10 +736,15 @@ static int vmci_transport_recv_stream_cb(void *data, struct vmci_datagram *dg)
         */
        bh_lock_sock(sk);
 
-       if (!sock_owned_by_user(sk) && sk->sk_state == SS_CONNECTED)
-               vmci_trans(vsk)->notify_ops->handle_notify_pkt(
-                               sk, pkt, true, &dst, &src,
-                               &bh_process_pkt);
+       if (!sock_owned_by_user(sk)) {
+               /* The local context ID may be out of date, update it. */
+               vsk->local_addr.svm_cid = dst.svm_cid;
+
+               if (sk->sk_state == SS_CONNECTED)
+                       vmci_trans(vsk)->notify_ops->handle_notify_pkt(
+                                       sk, pkt, true, &dst, &src,
+                                       &bh_process_pkt);
+       }
 
        bh_unlock_sock(sk);
 
@@ -902,6 +904,9 @@ static void vmci_transport_recv_pkt_work(struct work_struct *work)
 
        lock_sock(sk);
 
+       /* The local context ID may be out of date. */
+       vsock_sk(sk)->local_addr.svm_cid = pkt->dg.dst.context;
+
        switch (sk->sk_state) {
        case SS_LISTEN:
                vmci_transport_recv_listen(sk, pkt);
@@ -958,6 +963,10 @@ static int vmci_transport_recv_listen(struct sock *sk,
        pending = vmci_transport_get_pending(sk, pkt);
        if (pending) {
                lock_sock(pending);
+
+               /* The local context ID may be out of date. */
+               vsock_sk(pending)->local_addr.svm_cid = pkt->dg.dst.context;
+
                switch (pending->sk_state) {
                case SS_CONNECTING:
                        err = vmci_transport_recv_connecting_server(sk,
index b7df1ae..ec2611b 100644 (file)
@@ -64,16 +64,6 @@ bool vsock_addr_equals_addr(const struct sockaddr_vm *addr,
 }
 EXPORT_SYMBOL_GPL(vsock_addr_equals_addr);
 
-bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr,
-                               const struct sockaddr_vm *other)
-{
-       return (addr->svm_cid == VMADDR_CID_ANY ||
-               other->svm_cid == VMADDR_CID_ANY ||
-               addr->svm_cid == other->svm_cid) &&
-              addr->svm_port == other->svm_port;
-}
-EXPORT_SYMBOL_GPL(vsock_addr_equals_addr_any);
-
 int vsock_addr_cast(const struct sockaddr *addr,
                    size_t len, struct sockaddr_vm **out_addr)
 {
index cdfbcef..9ccd531 100644 (file)
@@ -24,8 +24,6 @@ bool vsock_addr_bound(const struct sockaddr_vm *addr);
 void vsock_addr_unbind(struct sockaddr_vm *addr);
 bool vsock_addr_equals_addr(const struct sockaddr_vm *addr,
                            const struct sockaddr_vm *other);
-bool vsock_addr_equals_addr_any(const struct sockaddr_vm *addr,
-                               const struct sockaddr_vm *other);
 int vsock_addr_cast(const struct sockaddr *addr, size_t len,
                    struct sockaddr_vm **out_addr);
 
index ea4155f..6ddf74f 100644 (file)
@@ -212,6 +212,39 @@ static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data)
        rdev_rfkill_poll(rdev);
 }
 
+void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev)
+{
+       lockdep_assert_held(&rdev->devlist_mtx);
+       lockdep_assert_held(&rdev->sched_scan_mtx);
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_P2P_DEVICE))
+               return;
+
+       if (!wdev->p2p_started)
+               return;
+
+       rdev_stop_p2p_device(rdev, wdev);
+       wdev->p2p_started = false;
+
+       rdev->opencount--;
+
+       if (rdev->scan_req && rdev->scan_req->wdev == wdev) {
+               bool busy = work_busy(&rdev->scan_done_wk);
+
+               /*
+                * If the work isn't pending or running (in which case it would
+                * be waiting for the lock we hold) the driver didn't properly
+                * cancel the scan when the interface was removed. In this case
+                * warn and leak the scan request object to not crash later.
+                */
+               WARN_ON(!busy);
+
+               rdev->scan_req->aborted = true;
+               ___cfg80211_scan_done(rdev, !busy);
+       }
+}
+
 static int cfg80211_rfkill_set_block(void *data, bool blocked)
 {
        struct cfg80211_registered_device *rdev = data;
@@ -221,7 +254,8 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
                return 0;
 
        rtnl_lock();
-       mutex_lock(&rdev->devlist_mtx);
+
+       /* read-only iteration need not hold the devlist_mtx */
 
        list_for_each_entry(wdev, &rdev->wdev_list, list) {
                if (wdev->netdev) {
@@ -231,18 +265,18 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked)
                /* otherwise, check iftype */
                switch (wdev->iftype) {
                case NL80211_IFTYPE_P2P_DEVICE:
-                       if (!wdev->p2p_started)
-                               break;
-                       rdev_stop_p2p_device(rdev, wdev);
-                       wdev->p2p_started = false;
-                       rdev->opencount--;
+                       /* but this requires it */
+                       mutex_lock(&rdev->devlist_mtx);
+                       mutex_lock(&rdev->sched_scan_mtx);
+                       cfg80211_stop_p2p_device(rdev, wdev);
+                       mutex_unlock(&rdev->sched_scan_mtx);
+                       mutex_unlock(&rdev->devlist_mtx);
                        break;
                default:
                        break;
                }
        }
 
-       mutex_unlock(&rdev->devlist_mtx);
        rtnl_unlock();
 
        return 0;
@@ -745,17 +779,13 @@ static void wdev_cleanup_work(struct work_struct *work)
        wdev = container_of(work, struct wireless_dev, cleanup_work);
        rdev = wiphy_to_dev(wdev->wiphy);
 
-       cfg80211_lock_rdev(rdev);
+       mutex_lock(&rdev->sched_scan_mtx);
 
        if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
                rdev->scan_req->aborted = true;
                ___cfg80211_scan_done(rdev, true);
        }
 
-       cfg80211_unlock_rdev(rdev);
-
-       mutex_lock(&rdev->sched_scan_mtx);
-
        if (WARN_ON(rdev->sched_scan_req &&
                    rdev->sched_scan_req->dev == wdev->netdev)) {
                __cfg80211_stop_sched_scan(rdev, false);
@@ -781,21 +811,19 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev)
                return;
 
        mutex_lock(&rdev->devlist_mtx);
+       mutex_lock(&rdev->sched_scan_mtx);
        list_del_rcu(&wdev->list);
        rdev->devlist_generation++;
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_P2P_DEVICE:
-               if (!wdev->p2p_started)
-                       break;
-               rdev_stop_p2p_device(rdev, wdev);
-               wdev->p2p_started = false;
-               rdev->opencount--;
+               cfg80211_stop_p2p_device(rdev, wdev);
                break;
        default:
                WARN_ON_ONCE(1);
                break;
        }
+       mutex_unlock(&rdev->sched_scan_mtx);
        mutex_unlock(&rdev->devlist_mtx);
 }
 EXPORT_SYMBOL(cfg80211_unregister_wdev);
@@ -936,6 +964,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                cfg80211_update_iface_num(rdev, wdev->iftype, 1);
                cfg80211_lock_rdev(rdev);
                mutex_lock(&rdev->devlist_mtx);
+               mutex_lock(&rdev->sched_scan_mtx);
                wdev_lock(wdev);
                switch (wdev->iftype) {
 #ifdef CONFIG_CFG80211_WEXT
@@ -967,6 +996,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                        break;
                }
                wdev_unlock(wdev);
+               mutex_unlock(&rdev->sched_scan_mtx);
                rdev->opencount++;
                mutex_unlock(&rdev->devlist_mtx);
                cfg80211_unlock_rdev(rdev);
index 3aec0e4..5845c2b 100644 (file)
@@ -503,6 +503,9 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
                               enum nl80211_iftype iftype, int num);
 
+void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev);
+
 #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
 
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
index d44ab21..58e13a8 100644 (file)
@@ -4702,14 +4702,19 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->scan)
                return -EOPNOTSUPP;
 
-       if (rdev->scan_req)
-               return -EBUSY;
+       mutex_lock(&rdev->sched_scan_mtx);
+       if (rdev->scan_req) {
+               err = -EBUSY;
+               goto unlock;
+       }
 
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                n_channels = validate_scan_freqs(
                                info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
-               if (!n_channels)
-                       return -EINVAL;
+               if (!n_channels) {
+                       err = -EINVAL;
+                       goto unlock;
+               }
        } else {
                enum ieee80211_band band;
                n_channels = 0;
@@ -4723,23 +4728,29 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp)
                        n_ssids++;
 
-       if (n_ssids > wiphy->max_scan_ssids)
-               return -EINVAL;
+       if (n_ssids > wiphy->max_scan_ssids) {
+               err = -EINVAL;
+               goto unlock;
+       }
 
        if (info->attrs[NL80211_ATTR_IE])
                ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        else
                ie_len = 0;
 
-       if (ie_len > wiphy->max_scan_ie_len)
-               return -EINVAL;
+       if (ie_len > wiphy->max_scan_ie_len) {
+               err = -EINVAL;
+               goto unlock;
+       }
 
        request = kzalloc(sizeof(*request)
                        + sizeof(*request->ssids) * n_ssids
                        + sizeof(*request->channels) * n_channels
                        + ie_len, GFP_KERNEL);
-       if (!request)
-               return -ENOMEM;
+       if (!request) {
+               err = -ENOMEM;
+               goto unlock;
+       }
 
        if (n_ssids)
                request->ssids = (void *)&request->channels[n_channels];
@@ -4876,6 +4887,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                kfree(request);
        }
 
+ unlock:
+       mutex_unlock(&rdev->sched_scan_mtx);
        return err;
 }
 
@@ -7749,20 +7762,9 @@ static int nl80211_stop_p2p_device(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->stop_p2p_device)
                return -EOPNOTSUPP;
 
-       if (!wdev->p2p_started)
-               return 0;
-
-       rdev_stop_p2p_device(rdev, wdev);
-       wdev->p2p_started = false;
-
-       mutex_lock(&rdev->devlist_mtx);
-       rdev->opencount--;
-       mutex_unlock(&rdev->devlist_mtx);
-
-       if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) {
-               rdev->scan_req->aborted = true;
-               ___cfg80211_scan_done(rdev, true);
-       }
+       mutex_lock(&rdev->sched_scan_mtx);
+       cfg80211_stop_p2p_device(rdev, wdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
 
        return 0;
 }
@@ -8486,7 +8488,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg,
        struct nlattr *nest;
        int i;
 
-       ASSERT_RDEV_LOCK(rdev);
+       lockdep_assert_held(&rdev->sched_scan_mtx);
 
        if (WARN_ON(!req))
                return 0;
index 674aadc..fd99ea4 100644 (file)
@@ -169,7 +169,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
        union iwreq_data wrqu;
 #endif
 
-       ASSERT_RDEV_LOCK(rdev);
+       lockdep_assert_held(&rdev->sched_scan_mtx);
 
        request = rdev->scan_req;
 
@@ -230,9 +230,9 @@ void __cfg80211_scan_done(struct work_struct *wk)
        rdev = container_of(wk, struct cfg80211_registered_device,
                            scan_done_wk);
 
-       cfg80211_lock_rdev(rdev);
+       mutex_lock(&rdev->sched_scan_mtx);
        ___cfg80211_scan_done(rdev, false);
-       cfg80211_unlock_rdev(rdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
 }
 
 void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
@@ -698,11 +698,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
        found = rb_find_bss(dev, tmp, BSS_CMP_REGULAR);
 
        if (found) {
-               found->pub.beacon_interval = tmp->pub.beacon_interval;
-               found->pub.signal = tmp->pub.signal;
-               found->pub.capability = tmp->pub.capability;
-               found->ts = tmp->ts;
-
                /* Update IEs */
                if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
                        const struct cfg80211_bss_ies *old;
@@ -723,6 +718,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
                        if (found->pub.hidden_beacon_bss &&
                            !list_empty(&found->hidden_list)) {
+                               const struct cfg80211_bss_ies *f;
+
                                /*
                                 * The found BSS struct is one of the probe
                                 * response members of a group, but we're
@@ -732,6 +729,10 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                                 * SSID to showing it, which is confusing so
                                 * drop this information.
                                 */
+
+                               f = rcu_access_pointer(tmp->pub.beacon_ies);
+                               kfree_rcu((struct cfg80211_bss_ies *)f,
+                                         rcu_head);
                                goto drop;
                        }
 
@@ -761,6 +762,11 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                                kfree_rcu((struct cfg80211_bss_ies *)old,
                                          rcu_head);
                }
+
+               found->pub.beacon_interval = tmp->pub.beacon_interval;
+               found->pub.signal = tmp->pub.signal;
+               found->pub.capability = tmp->pub.capability;
+               found->ts = tmp->ts;
        } else {
                struct cfg80211_internal_bss *new;
                struct cfg80211_internal_bss *hidden;
@@ -1056,6 +1062,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        if (IS_ERR(rdev))
                return PTR_ERR(rdev);
 
+       mutex_lock(&rdev->sched_scan_mtx);
        if (rdev->scan_req) {
                err = -EBUSY;
                goto out;
@@ -1162,6 +1169,7 @@ int cfg80211_wext_siwscan(struct net_device *dev,
                dev_hold(dev);
        }
  out:
+       mutex_unlock(&rdev->sched_scan_mtx);
        kfree(creq);
        cfg80211_unlock_rdev(rdev);
        return err;
index f432bd3..09d994d 100644 (file)
@@ -85,6 +85,7 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
        ASSERT_RTNL();
        ASSERT_RDEV_LOCK(rdev);
        ASSERT_WDEV_LOCK(wdev);
+       lockdep_assert_held(&rdev->sched_scan_mtx);
 
        if (rdev->scan_req)
                return -EBUSY;
@@ -320,11 +321,9 @@ void cfg80211_sme_scan_done(struct net_device *dev)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
 
-       mutex_lock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
        wdev_lock(wdev);
        __cfg80211_sme_scan_done(dev);
        wdev_unlock(wdev);
-       mutex_unlock(&wiphy_to_dev(wdev->wiphy)->devlist_mtx);
 }
 
 void cfg80211_sme_rx_auth(struct net_device *dev,
@@ -924,9 +923,12 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
        int err;
 
        mutex_lock(&rdev->devlist_mtx);
+       /* might request scan - scan_mtx -> wdev_mtx dependency */
+       mutex_lock(&rdev->sched_scan_mtx);
        wdev_lock(dev->ieee80211_ptr);
        err = __cfg80211_connect(rdev, dev, connect, connkeys, NULL);
        wdev_unlock(dev->ieee80211_ptr);
+       mutex_unlock(&rdev->sched_scan_mtx);
        mutex_unlock(&rdev->devlist_mtx);
 
        return err;
index b7a5313..7586de7 100644 (file)
@@ -27,7 +27,8 @@
 #define WIPHY_PR_ARG   __entry->wiphy_name
 
 #define WDEV_ENTRY     __field(u32, id)
-#define WDEV_ASSIGN    (__entry->id) = (wdev ? wdev->identifier : 0)
+#define WDEV_ASSIGN    (__entry->id) = (!IS_ERR_OR_NULL(wdev)  \
+                                        ? wdev->identifier : 0)
 #define WDEV_PR_FMT    "wdev(%u)"
 #define WDEV_PR_ARG    (__entry->id)
 
@@ -1778,7 +1779,7 @@ TRACE_EVENT(rdev_set_mac_acl,
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
-               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
                __entry->acl_policy = params->acl_policy;
        ),
        TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", acl policy: %d",
index fb9622f..e79cb5c 100644 (file)
@@ -89,6 +89,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
 
        cfg80211_lock_rdev(rdev);
        mutex_lock(&rdev->devlist_mtx);
+       mutex_lock(&rdev->sched_scan_mtx);
        wdev_lock(wdev);
 
        if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -135,6 +136,7 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
        err = cfg80211_mgd_wext_connect(rdev, wdev);
  out:
        wdev_unlock(wdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
        mutex_unlock(&rdev->devlist_mtx);
        cfg80211_unlock_rdev(rdev);
        return err;
@@ -190,6 +192,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
 
        cfg80211_lock_rdev(rdev);
        mutex_lock(&rdev->devlist_mtx);
+       mutex_lock(&rdev->sched_scan_mtx);
        wdev_lock(wdev);
 
        err = 0;
@@ -223,6 +226,7 @@ int cfg80211_mgd_wext_siwessid(struct net_device *dev,
        err = cfg80211_mgd_wext_connect(rdev, wdev);
  out:
        wdev_unlock(wdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
        mutex_unlock(&rdev->devlist_mtx);
        cfg80211_unlock_rdev(rdev);
        return err;
@@ -285,6 +289,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
 
        cfg80211_lock_rdev(rdev);
        mutex_lock(&rdev->devlist_mtx);
+       mutex_lock(&rdev->sched_scan_mtx);
        wdev_lock(wdev);
 
        if (wdev->sme_state != CFG80211_SME_IDLE) {
@@ -313,6 +318,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
        err = cfg80211_mgd_wext_connect(rdev, wdev);
  out:
        wdev_unlock(wdev);
+       mutex_unlock(&rdev->sched_scan_mtx);
        mutex_unlock(&rdev->devlist_mtx);
        cfg80211_unlock_rdev(rdev);
        return err;
index 35754cc..8dafe6d 100644 (file)
@@ -334,6 +334,70 @@ static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event)
                x->xflags &= ~XFRM_TIME_DEFER;
 }
 
+static void xfrm_replay_notify_esn(struct xfrm_state *x, int event)
+{
+       u32 seq_diff, oseq_diff;
+       struct km_event c;
+       struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
+       struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn;
+
+       /* we send notify messages in case
+        *  1. we updated on of the sequence numbers, and the seqno difference
+        *     is at least x->replay_maxdiff, in this case we also update the
+        *     timeout of our timer function
+        *  2. if x->replay_maxage has elapsed since last update,
+        *     and there were changes
+        *
+        *  The state structure must be locked!
+        */
+
+       switch (event) {
+       case XFRM_REPLAY_UPDATE:
+               if (!x->replay_maxdiff)
+                       break;
+
+               if (replay_esn->seq_hi == preplay_esn->seq_hi)
+                       seq_diff = replay_esn->seq - preplay_esn->seq;
+               else
+                       seq_diff = ~preplay_esn->seq + replay_esn->seq + 1;
+
+               if (replay_esn->oseq_hi == preplay_esn->oseq_hi)
+                       oseq_diff = replay_esn->oseq - preplay_esn->oseq;
+               else
+                       oseq_diff = ~preplay_esn->oseq + replay_esn->oseq + 1;
+
+               if (seq_diff < x->replay_maxdiff &&
+                   oseq_diff < x->replay_maxdiff) {
+
+                       if (x->xflags & XFRM_TIME_DEFER)
+                               event = XFRM_REPLAY_TIMEOUT;
+                       else
+                               return;
+               }
+
+               break;
+
+       case XFRM_REPLAY_TIMEOUT:
+               if (memcmp(x->replay_esn, x->preplay_esn,
+                          xfrm_replay_state_esn_len(replay_esn)) == 0) {
+                       x->xflags |= XFRM_TIME_DEFER;
+                       return;
+               }
+
+               break;
+       }
+
+       memcpy(x->preplay_esn, x->replay_esn,
+              xfrm_replay_state_esn_len(replay_esn));
+       c.event = XFRM_MSG_NEWAE;
+       c.data.aevent = event;
+       km_state_notify(x, &c);
+
+       if (x->replay_maxage &&
+           !mod_timer(&x->rtimer, jiffies + x->replay_maxage))
+               x->xflags &= ~XFRM_TIME_DEFER;
+}
+
 static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
 {
        int err = 0;
@@ -510,7 +574,7 @@ static struct xfrm_replay xfrm_replay_esn = {
        .advance        = xfrm_replay_advance_esn,
        .check          = xfrm_replay_check_esn,
        .recheck        = xfrm_replay_recheck_esn,
-       .notify         = xfrm_replay_notify_bmp,
+       .notify         = xfrm_replay_notify_esn,
        .overflow       = xfrm_replay_overflow_esn,
 };
 
index 23414b9..13c88fb 100644 (file)
@@ -347,10 +347,8 @@ int yama_ptrace_traceme(struct task_struct *parent)
        /* Only disallow PTRACE_TRACEME on more aggressive settings. */
        switch (ptrace_scope) {
        case YAMA_SCOPE_CAPABILITY:
-               rcu_read_lock();
-               if (!ns_capable(__task_cred(parent)->user_ns, CAP_SYS_PTRACE))
+               if (!has_ns_capability(parent, current_user_ns(), CAP_SYS_PTRACE))
                        rc = -EPERM;
-               rcu_read_unlock();
                break;
        case YAMA_SCOPE_NO_ATTACH:
                rc = -EPERM;
index 17286b3..e37b738 100644 (file)
@@ -173,7 +173,7 @@ const char *snd_hda_get_jack_type(u32 cfg)
                "Line Out", "Speaker", "HP Out", "CD",
                "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand",
                "Line In", "Aux", "Mic", "Telephony",
-               "SPDIF In", "Digitial In", "Reserved", "Other"
+               "SPDIF In", "Digital In", "Reserved", "Other"
        };
 
        return jack_types[(cfg & AC_DEFCFG_DEVICE)
index 29be37f..c7b59dd 100644 (file)
@@ -751,7 +751,7 @@ EXPORT_SYMBOL_HDA(snd_hda_activate_path);
 static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
 {
        struct hda_gen_spec *spec = codec->spec;
-       bool changed;
+       bool changed = false;
        int i;
 
        if (!spec->power_down_unused || path->active)
index 3e6f2c6..63734b5 100644 (file)
@@ -134,8 +134,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
  * this may give more power-saving, but will take longer time to
  * wake up.
  */
-static int power_save_controller = -1;
-module_param(power_save_controller, bint, 0644);
+static bool power_save_controller = 1;
+module_param(power_save_controller, bool, 0644);
 MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode.");
 #endif /* CONFIG_PM */
 
@@ -2959,8 +2959,6 @@ static int azx_runtime_idle(struct device *dev)
        struct snd_card *card = dev_get_drvdata(dev);
        struct azx *chip = card->private_data;
 
-       if (power_save_controller > 0)
-               return 0;
        if (!power_save_controller ||
            !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
                return -EBUSY;
index cba9dc6..74bf5f6 100644 (file)
@@ -3920,7 +3920,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec)
        const hda_nid_t *ssids;
 
        if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
-           codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
+           codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 ||
+           codec->vendor_id == 0x10ec0671)
                ssids = alc663_ssids;
        else
                ssids = alc662_ssids;
@@ -4392,6 +4393,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = {
        { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
        { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 },
        { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
+       { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 },
        { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
        { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
        { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
index 30184a4..bb07989 100644 (file)
@@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
 static void atmel_pcm_dma_irq(u32 ssc_sr,
        struct snd_pcm_substream *substream)
 {
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct atmel_pcm_dma_params *prtd;
 
-       prtd = snd_dmaengine_pcm_get_data(substream);
+       prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        if (ssc_sr & prtd->mask->ssc_error) {
                if (snd_pcm_running(substream))
@@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave)
 }
 
 static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
+       struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
 {
-       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_dmaengine_pcm_get_data(substream);
        ssc = prtd->ssc;
 
        ret = snd_hwparams_to_dma_slave_config(substream, params,
@@ -130,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
                slave_config.src_maxburst = 1;
        }
 
-       slave_config.device_fc = false;
-
        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");
@@ -164,9 +161,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       snd_dmaengine_pcm_set_data(substream, prtd);
-
-       ret = atmel_pcm_configure_dma(substream, params);
+       ret = atmel_pcm_configure_dma(substream, params, prtd);
        if (ret) {
                pr_err("atmel-pcm: failed to configure dmai\n");
                goto err;
@@ -182,9 +177,10 @@ err:
 
 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_dmaengine_pcm_get_data(substream);
+       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);
@@ -199,16 +195,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int atmel_pcm_close(struct snd_pcm_substream *substream)
-{
-       snd_dmaengine_pcm_close(substream);
-
-       return 0;
-}
-
 static struct snd_pcm_ops atmel_pcm_ops = {
        .open           = atmel_pcm_open,
-       .close          = atmel_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = atmel_pcm_hw_params,
        .prepare        = atmel_pcm_dma_prepare,
index e13580d..f3fdfa0 100644 (file)
@@ -533,6 +533,49 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                break;
 
        case SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM:
+               /*
+                * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
+                *
+                * The SSC transmit clock is obtained from the BCLK signal on
+                * on the TK line, and the SSC receive clock is
+                * generated from the transmit clock.
+                *
+                * Data is transferred on first BCLK after LRC pulse rising
+                * edge.If stereo, the right channel data is contiguous with
+                * the left channel data.
+                */
+               rcmr =    SSC_BF(RCMR_PERIOD, 0)
+                       | SSC_BF(RCMR_STTDLY, START_DELAY)
+                       | SSC_BF(RCMR_START, SSC_START_RISING_RF)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, SSC_CKS_PIN);
+
+               rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
+                       | SSC_BF(RFMR_FSLEN, 0)
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, 0)
+                       | SSC_BF(TCMR_STTDLY, START_DELAY)
+                       | SSC_BF(TCMR_START, SSC_START_RISING_RF)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(TCMR_CKS, SSC_CKS_PIN);
+
+               tfmr =    SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
+                       | SSC_BF(TFMR_FSLEN, 0)
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
        default:
                printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
                        ssc_p->daifmt);
@@ -707,13 +750,18 @@ static struct snd_soc_dai_driver atmel_ssc_dai = {
                .ops = &atmel_ssc_dai_ops,
 };
 
+static const struct snd_soc_component_driver atmel_ssc_component = {
+       .name           = "atmel-ssc",
+};
+
 static int asoc_ssc_init(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct ssc_device *ssc = platform_get_drvdata(pdev);
        int ret;
 
-       ret = snd_soc_register_dai(dev, &atmel_ssc_dai);
+       ret = snd_soc_register_component(dev, &atmel_ssc_component,
+                                        &atmel_ssc_dai, 1);
        if (ret) {
                dev_err(dev, "Could not register DAI: %d\n", ret);
                goto err;
@@ -732,7 +780,7 @@ static int asoc_ssc_init(struct device *dev)
        return 0;
 
 err_unregister_dai:
-       snd_soc_unregister_dai(dev);
+       snd_soc_unregister_component(dev);
 err:
        return ret;
 }
@@ -747,7 +795,7 @@ static void asoc_ssc_exit(struct device *dev)
        else
                atmel_pcm_pdc_platform_unregister(dev);
 
-       snd_soc_unregister_dai(dev);
+       snd_soc_unregister_component(dev);
 }
 
 /**
index ea7d9d1..44b8dce 100644 (file)
@@ -223,6 +223,10 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = {
        .ops                    = &alchemy_ac97c_ops,
 };
 
+static const struct snd_soc_component_driver au1xac97c_component = {
+       .name           = "au1xac97c",
+};
+
 static int au1xac97c_drvprobe(struct platform_device *pdev)
 {
        int ret;
@@ -268,7 +272,8 @@ static int au1xac97c_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
-       ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
+       ret = snd_soc_register_component(&pdev->dev, &au1xac97c_component,
+                                        &au1xac97c_dai_driver, 1);
        if (ret)
                return ret;
 
@@ -280,7 +285,7 @@ static int au1xac97c_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        WR(ctx, AC97_ENABLE, EN_D);     /* clock off, disable */
 
index 072448a..b3f37f6 100644 (file)
@@ -225,6 +225,10 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
        .ops = &au1xi2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xi2s_component = {
+       .name           = "au1xi2s",
+};
+
 static int au1xi2s_drvprobe(struct platform_device *pdev)
 {
        struct resource *iores, *dmares;
@@ -260,14 +264,15 @@ static int au1xi2s_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, ctx);
 
-       return snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
+       return snd_soc_register_component(&pdev->dev, &au1xi2s_component,
+                                         &au1xi2s_dai_driver, 1);
 }
 
 static int au1xi2s_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        WR(ctx, I2S_ENABLE, EN_D);      /* clock off, disable */
 
index 6ba07e3..8f1862a 100644 (file)
@@ -361,6 +361,10 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
        .ops = &au1xpsc_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xpsc_ac97_component = {
+       .name           = "au1xpsc-ac97",
+};
+
 static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 {
        int ret;
@@ -419,7 +423,8 @@ static int au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wd);
 
-       ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
+       ret = snd_soc_register_component(&pdev->dev, &au1xpsc_ac97_component,
+                                        &wd->dai_drv, 1);
        if (ret)
                return ret;
 
@@ -431,7 +436,7 @@ static int au1xpsc_ac97_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        /* disable PSC completely */
        au_writel(0, AC97_CFG(wd));
index 360b4e5..fe923a7 100644 (file)
@@ -288,6 +288,10 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
        .ops = &au1xpsc_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver au1xpsc_i2s_component = {
+       .name           = "au1xpsc-i2s",
+};
+
 static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 {
        struct resource *iores, *dmares;
@@ -350,14 +354,15 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, wd);
 
-       return snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
+       return snd_soc_register_component(&pdev->dev, &au1xpsc_i2s_component,
+                                         &wd->dai_drv, 1);
 }
 
 static int au1xpsc_i2s_drvremove(struct platform_device *pdev)
 {
        struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        au_writel(0, I2S_CFG(wd));
        au_sync();
index 8e41bcb..4902173 100644 (file)
@@ -282,6 +282,10 @@ static struct snd_soc_dai_driver bfin_ac97_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
 
+static const struct snd_soc_component_driver bfin_ac97_component = {
+       .name           = "bfin-ac97",
+};
+
 static int asoc_bfin_ac97_probe(struct platform_device *pdev)
 {
        struct sport_device *sport_handle;
@@ -331,7 +335,8 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+       ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
+                                        &bfin_ac97_dai, 1);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
@@ -356,7 +361,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
 {
        struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
        gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
index 168d88b..dd0c2a4 100644 (file)
@@ -245,6 +245,10 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = {
        .ops = &bf5xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver bf5xx_i2s_component = {
+       .name           = "bf5xx-i2s",
+};
+
 static int bf5xx_i2s_probe(struct platform_device *pdev)
 {
        struct sport_device *sport_handle;
@@ -257,7 +261,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
                return -ENODEV;
 
        /* register with the ASoC layers */
-       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
+                                        &bf5xx_i2s_dai, 1);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                sport_done(sport_handle);
@@ -273,7 +278,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
 
        pr_debug("%s enter\n", __func__);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
 
        return 0;
index c1e516e..69e9a3e 100644 (file)
@@ -249,6 +249,10 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = {
        .ops = &bf5xx_tdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver bf5xx_tdm_component = {
+       .name           = "bf5xx-tdm",
+};
+
 static int bfin_tdm_probe(struct platform_device *pdev)
 {
        struct sport_device *sport_handle;
@@ -282,7 +286,8 @@ static int bfin_tdm_probe(struct platform_device *pdev)
                goto sport_config_err;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
+       ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
+                                        &bf5xx_tdm_dai, 1);
        if (ret) {
                pr_err("Failed to register DAI: %d\n", ret);
                goto sport_config_err;
@@ -299,7 +304,7 @@ static int bfin_tdm_remove(struct platform_device *pdev)
 {
        struct sport_device *sport_handle = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_done(sport_handle);
 
        return 0;
index 8f33797..c02405c 100644 (file)
@@ -186,6 +186,10 @@ static struct snd_soc_dai_driver bfin_i2s_dai = {
        .ops = &bfin_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver bfin_i2s_component = {
+       .name           = "bfin-i2s",
+};
+
 static int bfin_i2s_probe(struct platform_device *pdev)
 {
        struct sport_device *sport;
@@ -197,7 +201,8 @@ static int bfin_i2s_probe(struct platform_device *pdev)
                return -ENODEV;
 
        /* register with the ASoC layers */
-       ret = snd_soc_register_dai(dev, &bfin_i2s_dai);
+       ret = snd_soc_register_component(dev, &bfin_i2s_component,
+                                        &bfin_i2s_dai, 1);
        if (ret) {
                dev_err(dev, "Failed to register DAI: %d\n", ret);
                sport_delete(sport);
@@ -212,7 +217,7 @@ static int bfin_i2s_remove(struct platform_device *pdev)
 {
        struct sport_device *sport = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        sport_delete(sport);
 
        return 0;
index 5db68cf..c43fb21 100644 (file)
@@ -27,7 +27,6 @@
 #include <sound/soc.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
-#include "ep93xx-pcm.h"
 
 static int edb93xx_hw_params(struct snd_pcm_substream *substream,
                             struct snd_pcm_hw_params *params)
index 1738d28..7798fbd 100644 (file)
@@ -23,7 +23,6 @@
 #include <sound/soc.h>
 
 #include <linux/platform_data/dma-ep93xx.h>
-#include "ep93xx-pcm.h"
 
 /*
  * Per channel (1-4) registers.
@@ -101,14 +100,16 @@ struct ep93xx_ac97_info {
 /* currently ALSA only supports a single AC97 device */
 static struct ep93xx_ac97_info *ep93xx_ac97_info;
 
-static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
+static struct ep93xx_dma_data ep93xx_ac97_pcm_out = {
        .name           = "ac97-pcm-out",
        .dma_port       = EP93XX_DMA_AAC1,
+       .direction      = DMA_MEM_TO_DEV,
 };
 
-static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
+static struct ep93xx_dma_data ep93xx_ac97_pcm_in = {
        .name           = "ac97-pcm-in",
        .dma_port       = EP93XX_DMA_AAC1,
+       .direction      = DMA_DEV_TO_MEM,
 };
 
 static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
@@ -316,7 +317,7 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
 static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
                               struct snd_soc_dai *dai)
 {
-       struct ep93xx_pcm_dma_params *dma_data;
+       struct ep93xx_dma_data *dma_data;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                dma_data = &ep93xx_ac97_pcm_out;
@@ -353,6 +354,10 @@ static struct snd_soc_dai_driver ep93xx_ac97_dai = {
        .ops                    = &ep93xx_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver ep93xx_ac97_component = {
+       .name           = "ep93xx-ac97",
+};
+
 static int ep93xx_ac97_probe(struct platform_device *pdev)
 {
        struct ep93xx_ac97_info *info;
@@ -390,7 +395,8 @@ static int ep93xx_ac97_probe(struct platform_device *pdev)
        ep93xx_ac97_info = info;
        platform_set_drvdata(pdev, info);
 
-       ret = snd_soc_register_dai(&pdev->dev, &ep93xx_ac97_dai);
+       ret = snd_soc_register_component(&pdev->dev, &ep93xx_ac97_component,
+                                        &ep93xx_ac97_dai, 1);
        if (ret)
                goto fail;
 
@@ -407,7 +413,7 @@ static int ep93xx_ac97_remove(struct platform_device *pdev)
 {
        struct ep93xx_ac97_info *info = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        /* disable the AC97 controller */
        ep93xx_ac97_write_reg(info, AC97GCR, 0);
index 323ed69..5c1102e 100644 (file)
@@ -30,8 +30,6 @@
 #include <mach/ep93xx-regs.h>
 #include <linux/platform_data/dma-ep93xx.h>
 
-#include "ep93xx-pcm.h"
-
 #define EP93XX_I2S_TXCLKCFG            0x00
 #define EP93XX_I2S_RXCLKCFG            0x04
 #define EP93XX_I2S_GLCTRL              0x0C
@@ -62,18 +60,20 @@ struct ep93xx_i2s_info {
        struct clk                      *mclk;
        struct clk                      *sclk;
        struct clk                      *lrclk;
-       struct ep93xx_pcm_dma_params    *dma_params;
+       struct ep93xx_dma_data          *dma_data;
        void __iomem                    *regs;
 };
 
-struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
+struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
        [SNDRV_PCM_STREAM_PLAYBACK] = {
                .name           = "i2s-pcm-out",
-               .dma_port       = EP93XX_DMA_I2S1,
+               .port           = EP93XX_DMA_I2S1,
+               .direction      = DMA_MEM_TO_DEV,
        },
        [SNDRV_PCM_STREAM_CAPTURE] = {
                .name           = "i2s-pcm-in",
-               .dma_port       = EP93XX_DMA_I2S1,
+               .port           = EP93XX_DMA_I2S1,
+               .direction      = DMA_DEV_TO_MEM,
        },
 };
 
@@ -147,7 +147,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
        snd_soc_dai_set_dma_data(cpu_dai, substream,
-                                &info->dma_params[substream->stream]);
+                                &info->dma_data[substream->stream]);
        return 0;
 }
 
@@ -366,6 +366,10 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = {
        .ops            = &ep93xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver ep93xx_i2s_component = {
+       .name           = "ep93xx-i2s",
+};
+
 static int ep93xx_i2s_probe(struct platform_device *pdev)
 {
        struct ep93xx_i2s_info *info;
@@ -403,9 +407,10 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
        }
 
        dev_set_drvdata(&pdev->dev, info);
-       info->dma_params = ep93xx_i2s_dma_params;
+       info->dma_data = ep93xx_i2s_dma_data;
 
-       err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
+       err = snd_soc_register_component(&pdev->dev, &ep93xx_i2s_component,
+                                        &ep93xx_i2s_dai, 1);
        if (err)
                goto fail_put_lrclk;
 
@@ -426,7 +431,7 @@ static int ep93xx_i2s_remove(struct platform_device *pdev)
 {
        struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
        clk_put(info->lrclk);
        clk_put(info->sclk);
index 72eb7a4..298946f 100644 (file)
@@ -29,8 +29,6 @@
 #include <mach/hardware.h>
 #include <mach/ep93xx-regs.h>
 
-#include "ep93xx-pcm.h"
-
 static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
        .info                   = (SNDRV_PCM_INFO_MMAP          |
                                   SNDRV_PCM_INFO_MMAP_VALID    |
@@ -68,40 +66,11 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
 static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct ep93xx_pcm_dma_params *dma_params;
-       struct ep93xx_dma_data *dma_data;
-       int ret;
 
        snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
 
-       dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL);
-       if (!dma_data)
-               return -ENOMEM;
-
-       dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
-       dma_data->port = dma_params->dma_port;
-       dma_data->name = dma_params->name;
-       dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
-
-       ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
-       if (ret) {
-               kfree(dma_data);
-               return ret;
-       }
-
-       snd_dmaengine_pcm_set_data(substream, dma_data);
-
-       return 0;
-}
-
-static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-
-       snd_dmaengine_pcm_close(substream);
-       kfree(dma_data);
-       return 0;
+       return snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter,
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
 }
 
 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -131,7 +100,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops ep93xx_pcm_ops = {
        .open           = ep93xx_pcm_open,
-       .close          = ep93xx_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = ep93xx_pcm_hw_params,
        .hw_free        = ep93xx_pcm_hw_free,
diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
deleted file mode 100644 (file)
index 111e112..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
- *
- * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
- * Copyright (C) 2006 Applied Data Systems
- *
- * 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 _EP93XX_SND_SOC_PCM_H
-#define _EP93XX_SND_SOC_PCM_H
-
-struct ep93xx_pcm_dma_params {
-       char    *name;
-       int     dma_port;
-};
-
-#endif /* _EP93XX_SND_SOC_PCM_H */
index a397bb0..4d094d0 100644 (file)
@@ -21,8 +21,6 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 
-#include "ep93xx-pcm.h"
-
 static struct snd_soc_dai_link simone_dai = {
        .name           = "AC97",
        .stream_name    = "AC97 HiFi",
index 9d77fe2..6904107 100644 (file)
@@ -21,7 +21,6 @@
 #include <mach/hardware.h>
 
 #include "../codecs/tlv320aic23.h"
-#include "ep93xx-pcm.h"
 
 #define CODEC_CLOCK 5644800
 
index 45b7256..2f45f00 100644 (file)
@@ -26,6 +26,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_AK4641 if I2C
        select SND_SOC_AK4642 if I2C
        select SND_SOC_AK4671 if I2C
+       select SND_SOC_AK5386
        select SND_SOC_ALC5623 if I2C
        select SND_SOC_ALC5632 if I2C
        select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
@@ -63,6 +64,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_STA32X if I2C
        select SND_SOC_STA529 if I2C
        select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
+       select SND_SOC_TAS5086 if I2C
        select SND_SOC_TLV320AIC23 if I2C
        select SND_SOC_TLV320AIC26 if SPI_MASTER
        select SND_SOC_TLV320AIC32X4 if I2C
@@ -203,6 +205,9 @@ config SND_SOC_AK4642
 config SND_SOC_AK4671
        tristate
 
+config SND_SOC_AK5386
+       tristate
+
 config SND_SOC_ALC5623
        tristate
 config SND_SOC_ALC5632
@@ -320,11 +325,14 @@ config SND_SOC_STA529
 config SND_SOC_STAC9766
        tristate
 
+config SND_SOC_TAS5086
+       tristate
+
 config SND_SOC_TLV320AIC23
        tristate
 
 config SND_SOC_TLV320AIC26
-       tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
+       tristate
        depends on SPI
 
 config SND_SOC_TLV320AIC32X4
index 6a3b3c3..b9e41c9 100644 (file)
@@ -14,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o
 snd-soc-ak4641-objs := ak4641.o
 snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
+snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs42l51-objs := cs42l51.o
@@ -55,6 +56,7 @@ snd-soc-ssm2602-objs := ssm2602.o
 snd-soc-sta32x-objs := sta32x.o
 snd-soc-sta529-objs := sta529.o
 snd-soc-stac9766-objs := stac9766.o
+snd-soc-tas5086-objs := tas5086.o
 snd-soc-tlv320aic23-objs := tlv320aic23.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
@@ -137,6 +139,7 @@ obj-$(CONFIG_SND_SOC_AK4535)        += snd-soc-ak4535.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
+obj-$(CONFIG_SND_SOC_AK5386)   += snd-soc-ak5386.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)  += snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)  += snd-soc-arizona.o
@@ -177,6 +180,7 @@ obj-$(CONFIG_SND_SOC_SSM2602)       += snd-soc-ssm2602.o
 obj-$(CONFIG_SND_SOC_STA32X)   += snd-soc-sta32x.o
 obj-$(CONFIG_SND_SOC_STA529)   += snd-soc-sta529.o
 obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
+obj-$(CONFIG_SND_SOC_TAS5086)  += snd-soc-tas5086.o
 obj-$(CONFIG_SND_SOC_TLV320AIC23)      += snd-soc-tlv320aic23.o
 obj-$(CONFIG_SND_SOC_TLV320AIC26)      += snd-soc-tlv320aic26.o
 obj-$(CONFIG_SND_SOC_TLV320AIC3X)      += snd-soc-tlv320aic3x.o
index 068b3ae..1aa10dd 100644 (file)
@@ -133,6 +133,8 @@ struct adau1373 {
 #define ADAU1373_DAI_FORMAT_DSP                0x3
 
 #define ADAU1373_BCLKDIV_SOURCE                BIT(5)
+#define ADAU1373_BCLKDIV_SR_MASK       (0x07 << 2)
+#define ADAU1373_BCLKDIV_BCLK_MASK     0x03
 #define ADAU1373_BCLKDIV_32            0x03
 #define ADAU1373_BCLKDIV_64            0x02
 #define ADAU1373_BCLKDIV_128           0x01
@@ -937,7 +939,8 @@ static int adau1373_hw_params(struct snd_pcm_substream *substream,
        adau1373_dai->enable_src = (div != 0);
 
        snd_soc_update_bits(codec, ADAU1373_BCLKDIV(dai->id),
-               ~ADAU1373_BCLKDIV_SOURCE, (div << 2) | ADAU1373_BCLKDIV_64);
+               ADAU1373_BCLKDIV_SR_MASK | ADAU1373_BCLKDIV_BCLK_MASK,
+               (div << 2) | ADAU1373_BCLKDIV_64);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
index 6f6c335..c7cfdf9 100644 (file)
@@ -55,6 +55,7 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
                              unsigned int format)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
        int val = 0;
        int ret;
 
@@ -77,9 +78,9 @@ static int ak4104_set_dai_fmt(struct snd_soc_dai *codec_dai,
        if ((format & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS)
                return -EINVAL;
 
-       ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-                                 AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
-                                 val);
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+                                AK4104_CONTROL1_DIF0 | AK4104_CONTROL1_DIF1,
+                                val);
        if (ret < 0)
                return ret;
 
@@ -91,11 +92,12 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                            struct snd_soc_dai *dai)
 {
        struct snd_soc_codec *codec = dai->codec;
-       int val = 0;
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+       int ret, val = 0;
 
        /* set the IEC958 bits: consumer mode, no copyright bit */
        val |= IEC958_AES0_CON_NOT_COPYRIGHT;
-       snd_soc_write(codec, AK4104_REG_CHN_STATUS(0), val);
+       regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(0), val);
 
        val = 0;
 
@@ -132,11 +134,33 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       return snd_soc_write(codec, AK4104_REG_CHN_STATUS(3), val);
+       ret = regmap_write(ak4104->regmap, AK4104_REG_CHN_STATUS(3), val);
+       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,
 };
 
@@ -160,20 +184,17 @@ static int ak4104_probe(struct snd_soc_codec *codec)
        int ret;
 
        codec->control_data = ak4104->regmap;
-       ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
-       if (ret != 0)
-               return ret;
 
        /* set power-up and non-reset bits */
-       ret = snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
-                                 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+                                AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,
+                                AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
        if (ret < 0)
                return ret;
 
        /* enable transmitter */
-       ret = snd_soc_update_bits(codec, AK4104_REG_TX,
-                                 AK4104_TX_TXE, AK4104_TX_TXE);
+       ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,
+                                AK4104_TX_TXE, AK4104_TX_TXE);
        if (ret < 0)
                return ret;
 
@@ -182,8 +203,10 @@ static int ak4104_probe(struct snd_soc_codec *codec)
 
 static int ak4104_remove(struct snd_soc_codec *codec)
 {
-       snd_soc_update_bits(codec, AK4104_REG_CONTROL1,
-                           AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
+       struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
+
+       regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,
+                          AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0);
 
        return 0;
 }
diff --git a/sound/soc/codecs/ak5386.c b/sound/soc/codecs/ak5386.c
new file mode 100644 (file)
index 0000000..1f30398
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * ALSA SoC driver for
+ *    Asahi Kasei AK5386 Single-ended 24-Bit 192kHz delta-sigma ADC
+ *
+ * (c) 2013 Daniel Mack <zonque@gmail.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/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+
+struct ak5386_priv {
+       int reset_gpio;
+};
+
+static struct snd_soc_codec_driver soc_codec_ak5386;
+
+static int ak5386_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                             unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+
+       format &= SND_SOC_DAIFMT_FORMAT_MASK;
+       if (format != SND_SOC_DAIFMT_LEFT_J &&
+           format != SND_SOC_DAIFMT_I2S) {
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ak5386_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 ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       /*
+        * From the datasheet:
+        *
+        * All external clocks (MCLK, SCLK and LRCK) must be present unless
+        * PDN pin = “L”. If these clocks are not provided, the AK5386 may
+        * draw excess current due to its use of internal dynamically
+        * refreshed logic. If the external clocks are not present, place
+        * the AK5386 in power-down mode (PDN pin = “L”).
+        */
+
+       if (gpio_is_valid(priv->reset_gpio))
+               gpio_set_value(priv->reset_gpio, 1);
+
+       return 0;
+}
+
+static int ak5386_hw_free(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct ak5386_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+       if (gpio_is_valid(priv->reset_gpio))
+               gpio_set_value(priv->reset_gpio, 0);
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops ak5386_dai_ops = {
+       .set_fmt        = ak5386_set_dai_fmt,
+       .hw_params      = ak5386_hw_params,
+       .hw_free        = ak5386_hw_free,
+};
+
+static struct snd_soc_dai_driver ak5386_dai = {
+       .name           = "ak5386-hifi",
+       .capture        = {
+               .stream_name    = "Capture",
+               .channels_min   = 1,
+               .channels_max   = 2,
+               .rates          = SNDRV_PCM_RATE_8000_192000,
+               .formats        = SNDRV_PCM_FMTBIT_S8     |
+                                 SNDRV_PCM_FMTBIT_S16_LE |
+                                 SNDRV_PCM_FMTBIT_S24_LE |
+                                 SNDRV_PCM_FMTBIT_S24_3LE,
+       },
+       .ops    = &ak5386_dai_ops,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id ak5386_dt_ids[] = {
+       { .compatible = "asahi-kasei,ak5386", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ak5386_dt_ids);
+#endif
+
+static int ak5386_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ak5386_priv *priv;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->reset_gpio = -EINVAL;
+       dev_set_drvdata(dev, priv);
+
+       if (of_match_device(of_match_ptr(ak5386_dt_ids), dev))
+               priv->reset_gpio = of_get_named_gpio(dev->of_node,
+                                                     "reset-gpio", 0);
+
+       if (gpio_is_valid(priv->reset_gpio))
+               if (devm_gpio_request_one(dev, priv->reset_gpio,
+                                         GPIOF_OUT_INIT_LOW,
+                                         "AK5386 Reset"))
+                       priv->reset_gpio = -EINVAL;
+
+       return snd_soc_register_codec(dev, &soc_codec_ak5386,
+                                     &ak5386_dai, 1);
+}
+
+static int ak5386_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_codec(&pdev->dev);
+       return 0;
+}
+
+static struct platform_driver ak5386_driver = {
+       .probe          = ak5386_probe,
+       .remove         = ak5386_remove,
+       .driver         = {
+               .name   = "ak5386",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(ak5386_dt_ids),
+       },
+};
+
+module_platform_driver(ak5386_driver);
+
+MODULE_DESCRIPTION("ASoC driver for AK5386 ADC");
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_LICENSE("GPL");
index ac948a6..389f232 100644 (file)
@@ -10,6 +10,7 @@
  * published by the Free Software Foundation.
  */
 
+#include <linux/delay.h>
 #include <linux/gcd.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
 #define arizona_aif_dbg(_dai, fmt, ...) \
        dev_dbg(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__)
 
+static int arizona_spk_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 arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       bool manual_ena = false;
+       int val;
+
+       switch (arizona->type) {
+       case WM5102:
+               switch (arizona->rev) {
+               case 0:
+                       break;
+               default:
+                       manual_ena = true;
+                       break;
+               }
+       default:
+               break;
+       }
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (!priv->spk_ena && manual_ena) {
+                       snd_soc_write(codec, 0x4f5, 0x25a);
+                       priv->spk_ena_pending = true;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3);
+               if (val & ARIZONA_SPK_SHUTDOWN_STS) {
+                       dev_crit(arizona->dev,
+                                "Speaker not enabled due to temperature\n");
+                       return -EBUSY;
+               }
+
+               snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
+                                   1 << w->shift, 1 << w->shift);
+
+               if (priv->spk_ena_pending) {
+                       msleep(75);
+                       snd_soc_write(codec, 0x4f5, 0xda);
+                       priv->spk_ena_pending = false;
+                       priv->spk_ena++;
+               }
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               if (manual_ena) {
+                       priv->spk_ena--;
+                       if (!priv->spk_ena)
+                               snd_soc_write(codec, 0x4f5, 0x25a);
+               }
+
+               snd_soc_update_bits(codec, ARIZONA_OUTPUT_ENABLES_1,
+                                   1 << w->shift, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (manual_ena) {
+                       if (!priv->spk_ena)
+                               snd_soc_write(codec, 0x4f5, 0x0da);
+               }
+               break;
+       }
+
+       return 0;
+}
+
+static irqreturn_t arizona_thermal_warn(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+                         &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+                       ret);
+       } else if (val & ARIZONA_SPK_SHUTDOWN_WARN_STS) {
+               dev_crit(arizona->dev, "Thermal warning\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t arizona_thermal_shutdown(int irq, void *data)
+{
+       struct arizona *arizona = data;
+       unsigned int val;
+       int ret;
+
+       ret = regmap_read(arizona->regmap, ARIZONA_INTERRUPT_RAW_STATUS_3,
+                         &val);
+       if (ret != 0) {
+               dev_err(arizona->dev, "Failed to read thermal status: %d\n",
+                       ret);
+       } else if (val & ARIZONA_SPK_SHUTDOWN_STS) {
+               dev_crit(arizona->dev, "Thermal shutdown\n");
+               ret = regmap_update_bits(arizona->regmap,
+                                        ARIZONA_OUTPUT_ENABLES_1,
+                                        ARIZONA_OUT4L_ENA |
+                                        ARIZONA_OUT4R_ENA, 0);
+               if (ret != 0)
+                       dev_crit(arizona->dev,
+                                "Failed to disable speaker outputs: %d\n",
+                                ret);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static const struct snd_soc_dapm_widget arizona_spkl =
+       SND_SOC_DAPM_PGA_E("OUT4L", SND_SOC_NOPM,
+                          ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+
+static const struct snd_soc_dapm_widget arizona_spkr =
+       SND_SOC_DAPM_PGA_E("OUT4R", SND_SOC_NOPM,
+                          ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_spk_ev,
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU);
+
+int arizona_init_spk(struct snd_soc_codec *codec)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       struct arizona *arizona = priv->arizona;
+       int ret;
+
+       ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkl, 1);
+       if (ret != 0)
+               return ret;
+
+       ret = snd_soc_dapm_new_controls(&codec->dapm, &arizona_spkr, 1);
+       if (ret != 0)
+               return ret;
+
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN_WARN,
+                                 "Thermal warning", arizona_thermal_warn,
+                                 arizona);
+       if (ret != 0)
+               dev_err(arizona->dev,
+                       "Failed to get thermal warning IRQ: %d\n",
+                       ret);
+
+       ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_SHUTDOWN,
+                                 "Thermal shutdown", arizona_thermal_shutdown,
+                                 arizona);
+       if (ret != 0)
+               dev_err(arizona->dev,
+                       "Failed to get thermal shutdown IRQ: %d\n",
+                       ret);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_init_spk);
+
 const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
        "None",
        "Tone Generator 1",
@@ -274,6 +432,33 @@ EXPORT_SYMBOL_GPL(arizona_mixer_values);
 const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0);
 EXPORT_SYMBOL_GPL(arizona_mixer_tlv);
 
+const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = {
+       "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate",
+};
+EXPORT_SYMBOL_GPL(arizona_rate_text);
+
+const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = {
+       0, 1, 2, 8,
+};
+EXPORT_SYMBOL_GPL(arizona_rate_val);
+
+
+const struct soc_enum arizona_isrc_fsl[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_1_CTRL_2,
+                             ARIZONA_ISRC1_FSL_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_2_CTRL_2,
+                             ARIZONA_ISRC2_FSL_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_ISRC_3_CTRL_2,
+                             ARIZONA_ISRC3_FSL_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+};
+EXPORT_SYMBOL_GPL(arizona_isrc_fsl);
+
 static const char *arizona_vol_ramp_text[] = {
        "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB",
        "15ms/6dB", "30ms/6dB",
@@ -332,9 +517,27 @@ const struct soc_enum arizona_ng_hold =
                        4, arizona_ng_hold_text);
 EXPORT_SYMBOL_GPL(arizona_ng_hold);
 
+static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int val;
+       int i;
+
+       if (ena)
+               val = ARIZONA_IN_VU;
+       else
+               val = 0;
+
+       for (i = 0; i < priv->num_inputs; i++)
+               snd_soc_update_bits(codec,
+                                   ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 4),
+                                   ARIZONA_IN_VU, val);
+}
+
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                  int event)
 {
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
        unsigned int reg;
 
        if (w->shift % 2)
@@ -343,13 +546,29 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                reg = ARIZONA_ADC_DIGITAL_VOLUME_1R + ((w->shift / 2) * 8);
 
        switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               priv->in_pending++;
+               break;
        case SND_SOC_DAPM_POST_PMU:
                snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
+
+               /* If this is the last input pending then allow VU */
+               priv->in_pending--;
+               if (priv->in_pending == 0) {
+                       msleep(1);
+                       arizona_in_set_vu(w->codec, 1);
+               }
                break;
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE,
-                                   ARIZONA_IN1L_MUTE);
+               snd_soc_update_bits(w->codec, reg,
+                                   ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
+                                   ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
                break;
+       case SND_SOC_DAPM_POST_PMD:
+               /* Disable volume updates if no inputs are enabled */
+               reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
+               if (reg == 0)
+                       arizona_in_set_vu(w->codec, 0);
        }
 
        return 0;
@@ -360,10 +579,61 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       msleep(17);
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
 
+int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+                  struct snd_kcontrol *kcontrol,
+                  int event)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       unsigned int mask = 1 << w->shift;
+       unsigned int val;
+
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+               val = mask;
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               val = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Store the desired state for the HP outputs */
+       priv->arizona->hp_ena &= ~mask;
+       priv->arizona->hp_ena |= val;
+
+       /* Force off if HPDET magic is active */
+       if (priv->arizona->hpdet_magic)
+               val = 0;
+
+       snd_soc_update_bits(w->codec, ARIZONA_OUTPUT_ENABLES_1, mask, val);
+
+       return arizona_out_ev(w, kcontrol, event);
+}
+EXPORT_SYMBOL_GPL(arizona_hp_ev);
+
 static unsigned int arizona_sysclk_48k_rates[] = {
        6144000,
        12288000,
@@ -469,27 +739,27 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                break;
        case 11289600:
        case 12288000:
-               val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_12MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 22579200:
        case 24576000:
-               val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_24MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 45158400:
        case 49152000:
-               val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_49MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 67737600:
        case 73728000:
-               val |= 4 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_73MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 90316800:
        case 98304000:
-               val |= 5 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_98MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 135475200:
        case 147456000:
-               val |= 6 << ARIZONA_SYSCLK_FREQ_SHIFT;
+               val |= ARIZONA_CLK_147MHZ << ARIZONA_SYSCLK_FREQ_SHIFT;
                break;
        case 0:
                dev_dbg(arizona->dev, "%s cleared\n", name);
@@ -783,7 +1053,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
        struct arizona *arizona = priv->arizona;
        int base = dai->driver->base;
        const int *rates;
-       int i, ret;
+       int i, ret, val;
        int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1];
        int bclk, lrclk, wl, frame, bclk_target;
 
@@ -799,6 +1069,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
                bclk_target *= chan_limit;
        }
 
+       /* Force stereo for I2S mode */
+       val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
+       if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) {
+               arizona_aif_dbg(dai, "Forcing stereo mode\n");
+               bclk_target *= 2;
+       }
+
        for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) {
                if (rates[i] >= bclk_target &&
                    rates[i] % params_rate(params) == 0) {
@@ -955,6 +1232,16 @@ static struct {
        { 1000000, 13500000, 0,  1 },
 };
 
+static struct {
+       unsigned int min;
+       unsigned int max;
+       u16 gain;
+} fll_gains[] = {
+       {       0,   256000, 0 },
+       {  256000,  1000000, 2 },
+       { 1000000, 13500000, 4 },
+};
+
 struct arizona_fll_cfg {
        int n;
        int theta;
@@ -962,6 +1249,7 @@ struct arizona_fll_cfg {
        int refdiv;
        int outdiv;
        int fratio;
+       int gain;
 };
 
 static int arizona_calc_fll(struct arizona_fll *fll,
@@ -1021,6 +1309,18 @@ static int arizona_calc_fll(struct arizona_fll *fll,
                return -EINVAL;
        }
 
+       for (i = 0; i < ARRAY_SIZE(fll_gains); i++) {
+               if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) {
+                       cfg->gain = fll_gains[i].gain;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(fll_gains)) {
+               arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n",
+                               Fref);
+               return -EINVAL;
+       }
+
        cfg->n = target / (ratio * Fref);
 
        if (target % (ratio * Fref)) {
@@ -1048,13 +1348,15 @@ static int arizona_calc_fll(struct arizona_fll *fll,
                        cfg->n, cfg->theta, cfg->lambda);
        arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n",
                        cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv);
+       arizona_fll_dbg(fll, "GAIN=%d\n", cfg->gain);
 
        return 0;
 
 }
 
 static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
-                             struct arizona_fll_cfg *cfg, int source)
+                             struct arizona_fll_cfg *cfg, int source,
+                             bool sync)
 {
        regmap_update_bits(arizona->regmap, base + 3,
                           ARIZONA_FLL1_THETA_MASK, cfg->theta);
@@ -1069,87 +1371,84 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base,
                           cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT |
                           source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT);
 
+       if (sync)
+               regmap_update_bits(arizona->regmap, base + 0x7,
+                                  ARIZONA_FLL1_GAIN_MASK,
+                                  cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+       else
+               regmap_update_bits(arizona->regmap, base + 0x9,
+                                  ARIZONA_FLL1_GAIN_MASK,
+                                  cfg->gain << ARIZONA_FLL1_GAIN_SHIFT);
+
        regmap_update_bits(arizona->regmap, base + 2,
                           ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK,
                           ARIZONA_FLL1_CTRL_UPD | cfg->n);
 }
 
-int arizona_set_fll(struct arizona_fll *fll, int source,
-                   unsigned int Fref, unsigned int Fout)
+static bool arizona_is_enabled_fll(struct arizona_fll *fll)
 {
        struct arizona *arizona = fll->arizona;
-       struct arizona_fll_cfg cfg, sync;
-       unsigned int reg, val;
-       int syncsrc;
-       bool ena;
+       unsigned int reg;
        int ret;
 
-       if (fll->fref == Fref && fll->fout == Fout)
-               return 0;
-
        ret = regmap_read(arizona->regmap, fll->base + 1, &reg);
        if (ret != 0) {
                arizona_fll_err(fll, "Failed to read current state: %d\n",
                                ret);
                return ret;
        }
-       ena = reg & ARIZONA_FLL1_ENA;
 
-       if (Fout) {
-               /* Do we have a 32kHz reference? */
-               regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
-               switch (val & ARIZONA_CLK_32K_SRC_MASK) {
-               case ARIZONA_CLK_SRC_MCLK1:
-               case ARIZONA_CLK_SRC_MCLK2:
-                       syncsrc = val & ARIZONA_CLK_32K_SRC_MASK;
-                       break;
-               default:
-                       syncsrc = -1;
-               }
+       return reg & ARIZONA_FLL1_ENA;
+}
 
-               if (source == syncsrc)
-                       syncsrc = -1;
+static void arizona_enable_fll(struct arizona_fll *fll,
+                             struct arizona_fll_cfg *ref,
+                             struct arizona_fll_cfg *sync)
+{
+       struct arizona *arizona = fll->arizona;
+       int ret;
 
-               if (syncsrc >= 0) {
-                       ret = arizona_calc_fll(fll, &sync, Fref, Fout);
-                       if (ret != 0)
-                               return ret;
+       /*
+        * If we have both REFCLK and SYNCCLK then enable both,
+        * otherwise apply the SYNCCLK settings to REFCLK.
+        */
+       if (fll->ref_src >= 0 && fll->ref_src != fll->sync_src) {
+               regmap_update_bits(arizona->regmap, fll->base + 5,
+                                  ARIZONA_FLL1_OUTDIV_MASK,
+                                  ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+               arizona_apply_fll(arizona, fll->base, ref, fll->ref_src,
+                                 false);
+               if (fll->sync_src >= 0)
+                       arizona_apply_fll(arizona, fll->base + 0x10, sync,
+                                         fll->sync_src, true);
+       } else if (fll->sync_src >= 0) {
+               regmap_update_bits(arizona->regmap, fll->base + 5,
+                                  ARIZONA_FLL1_OUTDIV_MASK,
+                                  sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
+
+               arizona_apply_fll(arizona, fll->base, sync,
+                                 fll->sync_src, false);
 
-                       ret = arizona_calc_fll(fll, &cfg, 32768, Fout);
-                       if (ret != 0)
-                               return ret;
-               } else {
-                       ret = arizona_calc_fll(fll, &cfg, Fref, Fout);
-                       if (ret != 0)
-                               return ret;
-               }
-       } else {
-               regmap_update_bits(arizona->regmap, fll->base + 1,
-                                  ARIZONA_FLL1_ENA, 0);
                regmap_update_bits(arizona->regmap, fll->base + 0x11,
                                   ARIZONA_FLL1_SYNC_ENA, 0);
-
-               if (ena)
-                       pm_runtime_put_autosuspend(arizona->dev);
-
-               fll->fref = Fref;
-               fll->fout = Fout;
-
-               return 0;
-       }
-
-       regmap_update_bits(arizona->regmap, fll->base + 5,
-                          ARIZONA_FLL1_OUTDIV_MASK,
-                          cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT);
-
-       if (syncsrc >= 0) {
-               arizona_apply_fll(arizona, fll->base, &cfg, syncsrc);
-               arizona_apply_fll(arizona, fll->base + 0x10, &sync, source);
        } else {
-               arizona_apply_fll(arizona, fll->base, &cfg, source);
+               arizona_fll_err(fll, "No clocks provided\n");
+               return;
        }
 
-       if (!ena)
+       /*
+        * Increase the bandwidth if we're not using a low frequency
+        * sync source.
+        */
+       if (fll->sync_src >= 0 && fll->sync_freq > 100000)
+               regmap_update_bits(arizona->regmap, fll->base + 0x17,
+                                  ARIZONA_FLL1_SYNC_BW, 0);
+       else
+               regmap_update_bits(arizona->regmap, fll->base + 0x17,
+                                  ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW);
+
+       if (!arizona_is_enabled_fll(fll))
                pm_runtime_get(arizona->dev);
 
        /* Clear any pending completions */
@@ -1157,7 +1456,8 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
 
        regmap_update_bits(arizona->regmap, fll->base + 1,
                           ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA);
-       if (syncsrc >= 0)
+       if (fll->ref_src >= 0 && fll->sync_src >= 0 &&
+           fll->ref_src != fll->sync_src)
                regmap_update_bits(arizona->regmap, fll->base + 0x11,
                                   ARIZONA_FLL1_SYNC_ENA,
                                   ARIZONA_FLL1_SYNC_ENA);
@@ -1166,10 +1466,88 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
                                          msecs_to_jiffies(250));
        if (ret == 0)
                arizona_fll_warn(fll, "Timed out waiting for lock\n");
+}
+
+static void arizona_disable_fll(struct arizona_fll *fll)
+{
+       struct arizona *arizona = fll->arizona;
+       bool change;
+
+       regmap_update_bits_check(arizona->regmap, fll->base + 1,
+                                ARIZONA_FLL1_ENA, 0, &change);
+       regmap_update_bits(arizona->regmap, fll->base + 0x11,
+                          ARIZONA_FLL1_SYNC_ENA, 0);
+
+       if (change)
+               pm_runtime_put_autosuspend(arizona->dev);
+}
+
+int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+                          unsigned int Fref, unsigned int Fout)
+{
+       struct arizona_fll_cfg ref, sync;
+       int ret;
+
+       if (fll->ref_src == source && fll->ref_freq == Fref)
+               return 0;
+
+       if (fll->fout && Fref > 0) {
+               ret = arizona_calc_fll(fll, &ref, Fref, fll->fout);
+               if (ret != 0)
+                       return ret;
+
+               if (fll->sync_src >= 0) {
+                       ret = arizona_calc_fll(fll, &sync, fll->sync_freq,
+                                              fll->fout);
+                       if (ret != 0)
+                               return ret;
+               }
+       }
+
+       fll->ref_src = source;
+       fll->ref_freq = Fref;
 
-       fll->fref = Fref;
+       if (fll->fout && Fref > 0) {
+               arizona_enable_fll(fll, &ref, &sync);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(arizona_set_fll_refclk);
+
+int arizona_set_fll(struct arizona_fll *fll, int source,
+                   unsigned int Fref, unsigned int Fout)
+{
+       struct arizona_fll_cfg ref, sync;
+       int ret;
+
+       if (fll->sync_src == source &&
+           fll->sync_freq == Fref && fll->fout == Fout)
+               return 0;
+
+       if (Fout) {
+               if (fll->ref_src >= 0) {
+                       ret = arizona_calc_fll(fll, &ref, fll->ref_freq,
+                                              Fout);
+                       if (ret != 0)
+                               return ret;
+               }
+
+               ret = arizona_calc_fll(fll, &sync, Fref, Fout);
+               if (ret != 0)
+                       return ret;
+       }
+
+       fll->sync_src = source;
+       fll->sync_freq = Fref;
        fll->fout = Fout;
 
+       if (Fout) {
+               arizona_enable_fll(fll, &ref, &sync);
+       } else {
+               arizona_disable_fll(fll);
+       }
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(arizona_set_fll);
@@ -1178,12 +1556,26 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq,
                     int ok_irq, struct arizona_fll *fll)
 {
        int ret;
+       unsigned int val;
 
        init_completion(&fll->ok);
 
        fll->id = id;
        fll->base = base;
        fll->arizona = arizona;
+       fll->sync_src = ARIZONA_FLL_SRC_NONE;
+
+       /* Configure default refclk to 32kHz if we have one */
+       regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val);
+       switch (val & ARIZONA_CLK_32K_SRC_MASK) {
+       case ARIZONA_CLK_SRC_MCLK1:
+       case ARIZONA_CLK_SRC_MCLK2:
+               fll->ref_src = val & ARIZONA_CLK_32K_SRC_MASK;
+               break;
+       default:
+               fll->ref_src = ARIZONA_FLL_SRC_NONE;
+       }
+       fll->ref_freq = 32768;
 
        snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id);
        snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name),
index 116372c..af39f10 100644 (file)
@@ -32,6 +32,7 @@
 #define ARIZONA_CLK_SRC_AIF2BCLK 0x9
 #define ARIZONA_CLK_SRC_AIF3BCLK 0xa
 
+#define ARIZONA_FLL_SRC_NONE      -1
 #define ARIZONA_FLL_SRC_MCLK1      0
 #define ARIZONA_FLL_SRC_MCLK2      1
 #define ARIZONA_FLL_SRC_SLIMCLK    3
 #define ARIZONA_MIXER_VOL_SHIFT                 1
 #define ARIZONA_MIXER_VOL_WIDTH                 7
 
+#define ARIZONA_CLK_6MHZ   0
+#define ARIZONA_CLK_12MHZ  1
+#define ARIZONA_CLK_24MHZ  2
+#define ARIZONA_CLK_49MHZ  3
+#define ARIZONA_CLK_73MHZ  4
+#define ARIZONA_CLK_98MHZ  5
+#define ARIZONA_CLK_147MHZ 6
+
 #define ARIZONA_MAX_DAI  4
 #define ARIZONA_MAX_ADSP 4
 
@@ -64,6 +73,12 @@ struct arizona_priv {
        int sysclk;
        int asyncclk;
        struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
+
+       int num_inputs;
+       unsigned int in_pending;
+
+       unsigned int spk_ena:2;
+       unsigned int spk_ena_pending:1;
 };
 
 #define ARIZONA_NUM_MIXER_INPUTS 99
@@ -165,6 +180,12 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS];
        ARIZONA_MIXER_ROUTES(name, name "L"), \
        ARIZONA_MIXER_ROUTES(name, name "R")
 
+#define ARIZONA_RATE_ENUM_SIZE 4
+extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE];
+extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE];
+
+extern const struct soc_enum arizona_isrc_fsl[];
+
 extern const struct soc_enum arizona_in_vi_ramp;
 extern const struct soc_enum arizona_in_vd_ramp;
 
@@ -184,6 +205,9 @@ extern int arizona_in_ev(struct snd_soc_dapm_widget *w,
 extern int arizona_out_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event);
+extern int arizona_hp_ev(struct snd_soc_dapm_widget *w,
+                        struct snd_kcontrol *kcontrol,
+                        int event);
 
 extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                              int source, unsigned int freq, int dir);
@@ -198,8 +222,12 @@ struct arizona_fll {
        unsigned int base;
        unsigned int vco_mult;
        struct completion ok;
-       unsigned int fref;
+
        unsigned int fout;
+       int sync_src;
+       unsigned int sync_freq;
+       int ref_src;
+       unsigned int ref_freq;
 
        char lock_name[ARIZONA_FLL_NAME_LEN];
        char clock_ok_name[ARIZONA_FLL_NAME_LEN];
@@ -207,9 +235,13 @@ struct arizona_fll {
 
 extern int arizona_init_fll(struct arizona *arizona, int id, int base,
                            int lock_irq, int ok_irq, struct arizona_fll *fll);
+extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source,
+                                 unsigned int Fref, unsigned int Fout);
 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_dai(struct arizona_priv *priv, int dai);
 
 int arizona_set_output_mode(struct snd_soc_codec *codec, int output,
index 2415a41..03036b3 100644 (file)
 
 /*
  * CS4271 registers
- * High byte represents SPI chip address (0x10) + write command (0)
- * Low byte - codec register address
  */
-#define CS4271_MODE1   0x2001  /* Mode Control 1 */
-#define CS4271_DACCTL  0x2002  /* DAC Control */
-#define CS4271_DACVOL  0x2003  /* DAC Volume & Mixing Control */
-#define CS4271_VOLA    0x2004  /* DAC Channel A Volume Control */
-#define CS4271_VOLB    0x2005  /* DAC Channel B Volume Control */
-#define CS4271_ADCCTL  0x2006  /* ADC Control */
-#define CS4271_MODE2   0x2007  /* Mode Control 2 */
-#define CS4271_CHIPID  0x2008  /* Chip ID */
+#define CS4271_MODE1   0x01    /* Mode Control 1 */
+#define CS4271_DACCTL  0x02    /* DAC Control */
+#define CS4271_DACVOL  0x03    /* DAC Volume & Mixing Control */
+#define CS4271_VOLA    0x04    /* DAC Channel A Volume Control */
+#define CS4271_VOLB    0x05    /* DAC Channel B Volume Control */
+#define CS4271_ADCCTL  0x06    /* ADC Control */
+#define CS4271_MODE2   0x07    /* Mode Control 2 */
+#define CS4271_CHIPID  0x08    /* Chip ID */
 
 #define CS4271_FIRSTREG        CS4271_MODE1
 #define CS4271_LASTREG CS4271_MODE2
  * Array do not include Chip ID, as codec driver does not use
  * registers read operations at all
  */
-static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = {
-       0,
-       0,
-       CS4271_DACCTL_AMUTE,
-       CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR,
-       0,
-       0,
-       0,
-       0,
+static const struct reg_default cs4271_reg_defaults[] = {
+       { CS4271_MODE1,         0, },
+       { CS4271_DACCTL,        CS4271_DACCTL_AMUTE, },
+       { CS4271_DACVOL,        CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, },
+       { CS4271_VOLA,          0, },
+       { CS4271_VOLB,          0, },
+       { CS4271_ADCCTL,        0, },
+       { CS4271_MODE2,         0, },
 };
 
+static bool cs4271_volatile_reg(struct device *dev, unsigned int reg)
+{
+       return reg == CS4271_CHIPID;
+}
+
 struct cs4271_private {
        /* SND_SOC_I2C or SND_SOC_SPI */
-       enum snd_soc_control_type       bus_type;
        unsigned int                    mclk;
        bool                            master;
        bool                            deemph;
+       struct regmap                   *regmap;
        /* Current sample rate for de-emphasis control */
        int                             rate;
        /* GPIO driving Reset pin, if any */
@@ -210,14 +212,14 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
        switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_LEFT_J:
                val |= CS4271_MODE1_DAC_DIF_LJ;
-               ret = snd_soc_update_bits(codec, CS4271_ADCCTL,
+               ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
                        CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ);
                if (ret < 0)
                        return ret;
                break;
        case SND_SOC_DAIFMT_I2S:
                val |= CS4271_MODE1_DAC_DIF_I2S;
-               ret = snd_soc_update_bits(codec, CS4271_ADCCTL,
+               ret = regmap_update_bits(cs4271->regmap, CS4271_ADCCTL,
                        CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S);
                if (ret < 0)
                        return ret;
@@ -227,7 +229,7 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       ret = snd_soc_update_bits(codec, CS4271_MODE1,
+       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
                CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val);
        if (ret < 0)
                return ret;
@@ -252,7 +254,7 @@ static int cs4271_set_deemph(struct snd_soc_codec *codec)
                val <<= 4;
        }
 
-       ret = snd_soc_update_bits(codec, CS4271_DACCTL,
+       ret = regmap_update_bits(cs4271->regmap, CS4271_DACCTL,
                CS4271_DACCTL_DEM_MASK, val);
        if (ret < 0)
                return ret;
@@ -341,14 +343,14 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
                     !dai->capture_active) ||
                    (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
                     !dai->playback_active)) {
-                       ret = snd_soc_update_bits(codec, CS4271_MODE2,
-                                                 CS4271_MODE2_PDN,
-                                                 CS4271_MODE2_PDN);
+                       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                                CS4271_MODE2_PDN,
+                                                CS4271_MODE2_PDN);
                        if (ret < 0)
                                return ret;
 
-                       ret = snd_soc_update_bits(codec, CS4271_MODE2,
-                                                 CS4271_MODE2_PDN, 0);
+                       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                                CS4271_MODE2_PDN, 0);
                        if (ret < 0)
                                return ret;
                }
@@ -378,7 +380,7 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
 
        val |= cs4271_clk_tab[i].ratio_mask;
 
-       ret = snd_soc_update_bits(codec, CS4271_MODE1,
+       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE1,
                CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val);
        if (ret < 0)
                return ret;
@@ -386,22 +388,29 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
        return cs4271_set_deemph(codec);
 }
 
-static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute)
+static int cs4271_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
        struct snd_soc_codec *codec = dai->codec;
+       struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
        int ret;
        int val_a = 0;
        int val_b = 0;
 
+       if (stream != SNDRV_PCM_STREAM_PLAYBACK)
+               return 0;
+
        if (mute) {
                val_a = CS4271_VOLA_MUTE;
                val_b = CS4271_VOLB_MUTE;
        }
 
-       ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a);
+       ret = regmap_update_bits(cs4271->regmap, CS4271_VOLA,
+                                CS4271_VOLA_MUTE, val_a);
        if (ret < 0)
                return ret;
-       ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b);
+
+       ret = regmap_update_bits(cs4271->regmap, CS4271_VOLB,
+                                CS4271_VOLB_MUTE, val_b);
        if (ret < 0)
                return ret;
 
@@ -436,7 +445,7 @@ static const struct snd_soc_dai_ops cs4271_dai_ops = {
        .hw_params      = cs4271_hw_params,
        .set_sysclk     = cs4271_set_dai_sysclk,
        .set_fmt        = cs4271_set_dai_fmt,
-       .digital_mute   = cs4271_digital_mute,
+       .mute_stream    = cs4271_mute_stream,
 };
 
 static struct snd_soc_dai_driver cs4271_dai = {
@@ -463,25 +472,33 @@ static struct snd_soc_dai_driver cs4271_dai = {
 static int cs4271_soc_suspend(struct snd_soc_codec *codec)
 {
        int ret;
+       struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
        /* Set power-down bit */
-       ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN,
-                                 CS4271_MODE2_PDN);
+       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                CS4271_MODE2_PDN, CS4271_MODE2_PDN);
        if (ret < 0)
                return ret;
+
        return 0;
 }
 
 static int cs4271_soc_resume(struct snd_soc_codec *codec)
 {
        int ret;
+       struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
+
        /* Restore codec state */
-       ret = snd_soc_cache_sync(codec);
+       ret = regcache_sync(cs4271->regmap);
        if (ret < 0)
                return ret;
+
        /* then disable the power-down bit */
-       ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
+       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                CS4271_MODE2_PDN, 0);
        if (ret < 0)
                return ret;
+
        return 0;
 }
 #else
@@ -542,40 +559,22 @@ static int cs4271_probe(struct snd_soc_codec *codec)
 
        cs4271->gpio_nreset = gpio_nreset;
 
-       /*
-        * In case of I2C, chip address specified in board data.
-        * So cache IO operations use 8 bit codec register address.
-        * In case of SPI, chip address and register address
-        * passed together as 16 bit value.
-        * Anyway, register address is masked with 0xFF inside
-        * soc-cache code.
-        */
-       if (cs4271->bus_type == SND_SOC_SPI)
-               ret = snd_soc_codec_set_cache_io(codec, 16, 8,
-                       cs4271->bus_type);
-       else
-               ret = snd_soc_codec_set_cache_io(codec, 8, 8,
-                       cs4271->bus_type);
-       if (ret) {
-               dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-               return ret;
-       }
-
-       ret = snd_soc_update_bits(codec, CS4271_MODE2,
-                                 CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
-                                 CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
+       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                CS4271_MODE2_PDN | CS4271_MODE2_CPEN,
+                                CS4271_MODE2_PDN | CS4271_MODE2_CPEN);
        if (ret < 0)
                return ret;
-       ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0);
+       ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                CS4271_MODE2_PDN, 0);
        if (ret < 0)
                return ret;
        /* Power-up sequence requires 85 uS */
        udelay(85);
 
        if (amutec_eq_bmutec)
-               snd_soc_update_bits(codec, CS4271_MODE2,
-                                   CS4271_MODE2_MUTECAEQUB,
-                                   CS4271_MODE2_MUTECAEQUB);
+               regmap_update_bits(cs4271->regmap, CS4271_MODE2,
+                                  CS4271_MODE2_MUTECAEQUB,
+                                  CS4271_MODE2_MUTECAEQUB);
 
        return snd_soc_add_codec_controls(codec, cs4271_snd_controls,
                ARRAY_SIZE(cs4271_snd_controls));
@@ -597,13 +596,24 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
        .remove                 = cs4271_remove,
        .suspend                = cs4271_soc_suspend,
        .resume                 = cs4271_soc_resume,
-       .reg_cache_default      = cs4271_dflt_reg,
-       .reg_cache_size         = ARRAY_SIZE(cs4271_dflt_reg),
-       .reg_word_size          = sizeof(cs4271_dflt_reg[0]),
-       .compress_type          = SND_SOC_FLAT_COMPRESSION,
 };
 
 #if defined(CONFIG_SPI_MASTER)
+
+static const struct regmap_config cs4271_spi_regmap = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .max_register = CS4271_LASTREG,
+       .read_flag_mask = 0x21,
+       .write_flag_mask = 0x20,
+
+       .reg_defaults = cs4271_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = cs4271_volatile_reg,
+};
+
 static int cs4271_spi_probe(struct spi_device *spi)
 {
        struct cs4271_private *cs4271;
@@ -613,7 +623,9 @@ static int cs4271_spi_probe(struct spi_device *spi)
                return -ENOMEM;
 
        spi_set_drvdata(spi, cs4271);
-       cs4271->bus_type = SND_SOC_SPI;
+       cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
+       if (IS_ERR(cs4271->regmap))
+               return PTR_ERR(cs4271->regmap);
 
        return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
                &cs4271_dai, 1);
@@ -643,6 +655,18 @@ static const struct i2c_device_id cs4271_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
 
+static const struct regmap_config cs4271_i2c_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = CS4271_LASTREG,
+
+       .reg_defaults = cs4271_reg_defaults,
+       .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
+       .cache_type = REGCACHE_RBTREE,
+
+       .volatile_reg = cs4271_volatile_reg,
+};
+
 static int cs4271_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
@@ -653,7 +677,9 @@ static int cs4271_i2c_probe(struct i2c_client *client,
                return -ENOMEM;
 
        i2c_set_clientdata(client, cs4271);
-       cs4271->bus_type = SND_SOC_I2C;
+       cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
+       if (IS_ERR(cs4271->regmap))
+               return PTR_ERR(cs4271->regmap);
 
        return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
                &cs4271_dai, 1);
index 6361dab..3b20c86 100644 (file)
@@ -1180,7 +1180,11 @@ static int cs42l73_pcm_hw_params(struct snd_pcm_substream *substream,
                priv->config[id].mmcc &= 0xC0;
                priv->config[id].mmcc |= cs42l73_mclk_coeffs[mclk_coeff].mmcc;
                priv->config[id].spc &= 0xFC;
-               priv->config[id].spc |= MCK_SCLK_MCLK;
+               /* Use SCLK=64*Fs if internal MCLK >= 6.4MHz */
+               if (priv->mclk >= 6400000)
+                       priv->config[id].spc |= MCK_SCLK_64FS;
+               else
+                       priv->config[id].spc |= MCK_SCLK_MCLK;
        } else {
                /* CS42L73 Slave */
                priv->config[id].spc &= 0xFC;
index a4c16fd..3a7b7fd 100644 (file)
@@ -739,14 +739,32 @@ static const unsigned int max98088_micboost_tlv[] = {
        2, 2, TLV_DB_SCALE_ITEM(3000, 0, 0),
 };
 
+static const unsigned int max98088_hp_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 6, TLV_DB_SCALE_ITEM(-6700, 400, 0),
+       7, 14, TLV_DB_SCALE_ITEM(-4000, 300, 0),
+       15, 21, TLV_DB_SCALE_ITEM(-1700, 200, 0),
+       22, 27, TLV_DB_SCALE_ITEM(-400, 100, 0),
+       28, 31, TLV_DB_SCALE_ITEM(150, 50, 0),
+};
+
+static const unsigned int max98088_spk_tlv[] = {
+       TLV_DB_RANGE_HEAD(5),
+       0, 6, TLV_DB_SCALE_ITEM(-6200, 400, 0),
+       7, 14, TLV_DB_SCALE_ITEM(-3500, 300, 0),
+       15, 21, TLV_DB_SCALE_ITEM(-1200, 200, 0),
+       22, 27, TLV_DB_SCALE_ITEM(100, 100, 0),
+       28, 31, TLV_DB_SCALE_ITEM(650, 50, 0),
+};
+
 static const struct snd_kcontrol_new max98088_snd_controls[] = {
 
-       SOC_DOUBLE_R("Headphone Volume", M98088_REG_39_LVL_HP_L,
-               M98088_REG_3A_LVL_HP_R, 0, 31, 0),
-       SOC_DOUBLE_R("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
-               M98088_REG_3E_LVL_SPK_R, 0, 31, 0),
-       SOC_DOUBLE_R("Receiver Volume", M98088_REG_3B_LVL_REC_L,
-               M98088_REG_3C_LVL_REC_R, 0, 31, 0),
+       SOC_DOUBLE_R_TLV("Headphone Volume", M98088_REG_39_LVL_HP_L,
+                        M98088_REG_3A_LVL_HP_R, 0, 31, 0, max98088_hp_tlv),
+       SOC_DOUBLE_R_TLV("Speaker Volume", M98088_REG_3D_LVL_SPK_L,
+                        M98088_REG_3E_LVL_SPK_R, 0, 31, 0, max98088_spk_tlv),
+       SOC_DOUBLE_R_TLV("Receiver Volume", M98088_REG_3B_LVL_REC_L,
+                        M98088_REG_3C_LVL_REC_R, 0, 31, 0, max98088_spk_tlv),
 
        SOC_DOUBLE_R("Headphone Switch", M98088_REG_39_LVL_HP_L,
                M98088_REG_3A_LVL_HP_R, 7, 1, 1),
index fc17604..ce0d364 100644 (file)
@@ -23,8 +23,6 @@
 #include <sound/max98090.h>
 #include "max98090.h"
 
-#include <linux/version.h>
-
 #define DEBUG
 #define EXTMIC_METHOD
 #define EXTMIC_METHOD_TEST
@@ -509,16 +507,16 @@ static int max98090_put_enab_tlv(struct snd_kcontrol *kcontrol,
        return 0;
 }
 
-static const char * max98090_perf_pwr_text[] =
+static const char *max98090_perf_pwr_text[] =
        { "High Performance", "Low Power" };
-static const char * max98090_pwr_perf_text[] =
+static const char *max98090_pwr_perf_text[] =
        { "Low Power", "High Performance" };
 
 static const struct soc_enum max98090_vcmbandgap_enum =
        SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT,
                ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text);
 
-static const char * max98090_osr128_text[] = { "64*fs", "128*fs" };
+static const char *max98090_osr128_text[] = { "64*fs", "128*fs" };
 
 static const struct soc_enum max98090_osr128_enum =
        SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT,
@@ -535,28 +533,28 @@ static const struct soc_enum max98090_filter_dmic34mode_enum =
                M98090_FLT_DMIC34MODE_SHIFT,
                ARRAY_SIZE(max98090_mode_text), max98090_mode_text);
 
-static const char * max98090_drcatk_text[] =
+static const char *max98090_drcatk_text[] =
        { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" };
 
 static const struct soc_enum max98090_drcatk_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT,
                ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text);
 
-static const char * max98090_drcrls_text[] =
+static const char *max98090_drcrls_text[] =
        { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" };
 
 static const struct soc_enum max98090_drcrls_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT,
                ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text);
 
-static const char * max98090_alccmp_text[] =
+static const char *max98090_alccmp_text[] =
        { "1:1", "1:1.5", "1:2", "1:4", "1:INF" };
 
 static const struct soc_enum max98090_alccmp_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT,
                ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text);
 
-static const char * max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
+static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" };
 
 static const struct soc_enum max98090_drcexp_enum =
        SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT,
@@ -859,7 +857,7 @@ static const struct soc_enum mic2_mux_enum =
 static const struct snd_kcontrol_new max98090_mic2_mux =
        SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum);
 
-static const char * max98090_micpre_text[] = { "Off", "On" };
+static const char *max98090_micpre_text[] = { "Off", "On" };
 
 static const struct soc_enum max98090_pa1en_enum =
        SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT,
@@ -1703,9 +1701,8 @@ static int max98090_dai_set_fmt(struct snd_soc_dai *codec_dai,
                 * seen for the case of TDM mode. The remaining cases have
                 * normal logic.
                 */
-               if (max98090->tdm_slots > 1) {
+               if (max98090->tdm_slots > 1)
                        regval ^= M98090_BCI_MASK;
-               }
 
                snd_soc_write(codec,
                        M98090_REG_INTERFACE_FORMAT, regval);
@@ -2059,17 +2056,14 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
        if (!active)
                return IRQ_NONE;
 
-       if (active & M98090_CLD_MASK) {
+       if (active & M98090_CLD_MASK)
                dev_err(codec->dev, "M98090_CLD_MASK\n");
-       }
 
-       if (active & M98090_SLD_MASK) {
+       if (active & M98090_SLD_MASK)
                dev_dbg(codec->dev, "M98090_SLD_MASK\n");
-       }
 
-       if (active & M98090_ULK_MASK) {
+       if (active & M98090_ULK_MASK)
                dev_err(codec->dev, "M98090_ULK_MASK\n");
-       }
 
        if (active & M98090_JDET_MASK) {
                dev_dbg(codec->dev, "M98090_JDET_MASK\n");
@@ -2080,13 +2074,11 @@ static irqreturn_t max98090_interrupt(int irq, void *data)
                        msecs_to_jiffies(100));
        }
 
-       if (active & M98090_DRCACT_MASK) {
+       if (active & M98090_DRCACT_MASK)
                dev_dbg(codec->dev, "M98090_DRCACT_MASK\n");
-       }
 
-       if (active & M98090_DRCCLP_MASK) {
+       if (active & M98090_DRCCLP_MASK)
                dev_err(codec->dev, "M98090_DRCCLP_MASK\n");
-       }
 
        return IRQ_HANDLED;
 }
@@ -2324,7 +2316,7 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
        max98090->pdata = i2c->dev.platform_data;
        max98090->irq = i2c->irq;
 
-       max98090->regmap = regmap_init_i2c(i2c, &max98090_regmap);
+       max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
        if (IS_ERR(max98090->regmap)) {
                ret = PTR_ERR(max98090->regmap);
                dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret);
@@ -2334,18 +2326,13 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
        ret = snd_soc_register_codec(&i2c->dev,
                        &soc_codec_dev_max98090, max98090_dai,
                        ARRAY_SIZE(max98090_dai));
-       if (ret < 0)
-               regmap_exit(max98090->regmap);
-
 err_enable:
        return ret;
 }
 
 static int max98090_i2c_remove(struct i2c_client *client)
 {
-       struct max98090_priv *max98090 = dev_get_drvdata(&client->dev);
        snd_soc_unregister_codec(&client->dev);
-       regmap_exit(max98090->regmap);
        return 0;
 }
 
@@ -2369,7 +2356,7 @@ static int max98090_runtime_suspend(struct device *dev)
        return 0;
 }
 
-static struct dev_pm_ops max98090_pm = {
+static const struct dev_pm_ops max98090_pm = {
        SET_RUNTIME_PM_OPS(max98090_runtime_suspend,
                max98090_runtime_resume, NULL)
 };
index 566ea32..721587c 100644 (file)
@@ -1,3 +1,22 @@
+/*
+ * sound/soc/codecs/si476x.c -- Codec driver for SI476X chips
+ *
+ * Copyright (C) 2012 Innovative Converged Devices(ICD)
+ * Copyright (C) 2013 Andrey Smirnov
+ *
+ * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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 <sound/pcm.h>
@@ -45,13 +64,23 @@ static unsigned int si476x_codec_read(struct snd_soc_codec *codec,
                                      unsigned int reg)
 {
        int err;
+       unsigned int val;
        struct si476x_core *core = codec->control_data;
 
        si476x_core_lock(core);
-       err = si476x_core_cmd_get_property(core, reg);
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, true);
+
+       err = regmap_read(core->regmap, reg, &val);
+
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, false);
        si476x_core_unlock(core);
 
-       return err;
+       if (err < 0)
+               return err;
+
+       return val;
 }
 
 static int si476x_codec_write(struct snd_soc_codec *codec,
@@ -61,7 +90,13 @@ static int si476x_codec_write(struct snd_soc_codec *codec,
        struct si476x_core *core = codec->control_data;
 
        si476x_core_lock(core);
-       err = si476x_core_cmd_set_property(core, reg, val);
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, true);
+
+       err = regmap_write(core->regmap, reg, val);
+
+       if (!si476x_core_is_powered_up(core))
+               regcache_cache_only(core->regmap, false);
        si476x_core_unlock(core);
 
        return err;
@@ -140,7 +175,7 @@ static int si476x_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
                dev_err(codec_dai->codec->dev, "Failed to set output format\n");
                return err;
        }
-       
+
        return 0;
 }
 
@@ -182,7 +217,7 @@ static int si476x_codec_hw_params(struct snd_pcm_substream *substream,
 
        err = snd_soc_update_bits(dai->codec, SI476X_DIGITAL_IO_OUTPUT_FORMAT,
                                  SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK,
-                                 (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | 
+                                 (width << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) |
                                  (width << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT));
        if (err < 0) {
                dev_err(dai->codec->dev, "Failed to set output width\n");
@@ -251,6 +286,6 @@ static struct platform_driver si476x_platform_driver = {
 };
 module_platform_driver(si476x_platform_driver);
 
-MODULE_AUTHOR("Andrey Smirnov <andrey.smirnov@convergeddevices.net>");
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
 MODULE_DESCRIPTION("ASoC Si4761/64 codec driver");
 MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c
new file mode 100644 (file)
index 0000000..d447c4a
--- /dev/null
@@ -0,0 +1,591 @@
+/*
+ * TAS5086 ASoC codec driver
+ *
+ * Copyright (c) 2013 Daniel Mack <zonque@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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.
+ *
+ * TODO:
+ *  - implement DAPM and input muxing
+ *  - implement modulation limit
+ *  - implement non-default PWM start
+ *
+ * Note that this chip has a very unusual register layout, specifically
+ * because the registers are of unequal size, and multi-byte registers
+ * require bulk writes to take effect. Regmap does not support that kind
+ * of devices.
+ *
+ * Currently, the driver does not touch any of the registers >= 0x20, so
+ * it doesn't matter because the entire map can be accessed as 8-bit
+ * array. In case more features will be added in the future
+ * that require access to higher registers, the entire regmap H/W I/O
+ * routines have to be open-coded.
+ */
+
+#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/spi/spi.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>
+#include <sound/tas5086.h>
+
+#define TAS5086_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  |                \
+                            SNDRV_PCM_FMTBIT_S20_3LE |         \
+                            SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define TAS5086_PCM_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)
+
+/*
+ * TAS5086 registers
+ */
+#define TAS5086_CLOCK_CONTROL          0x00    /* Clock control register  */
+#define TAS5086_CLOCK_RATE(val)                (val << 5)
+#define TAS5086_CLOCK_RATE_MASK                (0x7 << 5)
+#define TAS5086_CLOCK_RATIO(val)       (val << 2)
+#define TAS5086_CLOCK_RATIO_MASK       (0x7 << 2)
+#define TAS5086_CLOCK_SCLK_RATIO_48    (1 << 1)
+#define TAS5086_CLOCK_VALID            (1 << 0)
+
+#define TAS5086_DEEMPH_MASK            0x03
+#define TAS5086_SOFT_MUTE_ALL          0x3f
+
+#define TAS5086_DEV_ID                 0x01    /* Device ID register */
+#define TAS5086_ERROR_STATUS           0x02    /* Error status register */
+#define TAS5086_SYS_CONTROL_1          0x03    /* System control register 1 */
+#define TAS5086_SERIAL_DATA_IF         0x04    /* Serial data interface register  */
+#define TAS5086_SYS_CONTROL_2          0x05    /* System control register 2 */
+#define TAS5086_SOFT_MUTE              0x06    /* Soft mute register */
+#define TAS5086_MASTER_VOL             0x07    /* Master volume  */
+#define TAS5086_CHANNEL_VOL(X)         (0x08 + (X))    /* Channel 1-6 volume */
+#define TAS5086_VOLUME_CONTROL         0x09    /* Volume control register */
+#define TAS5086_MOD_LIMIT              0x10    /* Modulation limit register */
+#define TAS5086_PWM_START              0x18    /* PWM start register */
+#define TAS5086_SURROUND               0x19    /* Surround register */
+#define TAS5086_SPLIT_CAP_CHARGE       0x1a    /* Split cap charge period register */
+#define TAS5086_OSC_TRIM               0x1b    /* Oscillator trim register */
+#define TAS5086_BKNDERR                0x1c
+
+/*
+ * Default TAS5086 power-up configuration
+ */
+static const struct reg_default tas5086_reg_defaults[] = {
+       { 0x00, 0x6c },
+       { 0x01, 0x03 },
+       { 0x02, 0x00 },
+       { 0x03, 0xa0 },
+       { 0x04, 0x05 },
+       { 0x05, 0x60 },
+       { 0x06, 0x00 },
+       { 0x07, 0xff },
+       { 0x08, 0x30 },
+       { 0x09, 0x30 },
+       { 0x0a, 0x30 },
+       { 0x0b, 0x30 },
+       { 0x0c, 0x30 },
+       { 0x0d, 0x30 },
+       { 0x0e, 0xb1 },
+       { 0x0f, 0x00 },
+       { 0x10, 0x02 },
+       { 0x11, 0x00 },
+       { 0x12, 0x00 },
+       { 0x13, 0x00 },
+       { 0x14, 0x00 },
+       { 0x15, 0x00 },
+       { 0x16, 0x00 },
+       { 0x17, 0x00 },
+       { 0x18, 0x3f },
+       { 0x19, 0x00 },
+       { 0x1a, 0x18 },
+       { 0x1b, 0x82 },
+       { 0x1c, 0x05 },
+};
+
+static bool tas5086_accessible_reg(struct device *dev, unsigned int reg)
+{
+       return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17));
+}
+
+static bool tas5086_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TAS5086_DEV_ID:
+       case TAS5086_ERROR_STATUS:
+               return true;
+       }
+
+       return false;
+}
+
+static bool tas5086_writeable_reg(struct device *dev, unsigned int reg)
+{
+       return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID);
+}
+
+struct tas5086_private {
+       struct regmap   *regmap;
+       unsigned int    mclk, sclk;
+       unsigned int    format;
+       bool            deemph;
+       /* Current sample rate for de-emphasis control */
+       int             rate;
+       /* GPIO driving Reset pin, if any */
+       int             gpio_nreset;
+};
+
+static int tas5086_deemph[] = { 0, 32000, 44100, 48000 };
+
+static int tas5086_set_deemph(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       int i, val = 0;
+
+       if (priv->deemph)
+               for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++)
+                       if (tas5086_deemph[i] == priv->rate)
+                               val = i;
+
+       return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1,
+                                 TAS5086_DEEMPH_MASK, val);
+}
+
+static int tas5086_get_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       ucontrol->value.enumerated.item[0] = priv->deemph;
+
+       return 0;
+}
+
+static int tas5086_put_deemph(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       priv->deemph = ucontrol->value.enumerated.item[0];
+
+       return tas5086_set_deemph(codec);
+}
+
+
+static int tas5086_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+                                 int clk_id, unsigned int freq, int dir)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       switch (clk_id) {
+       case TAS5086_CLK_IDX_MCLK:
+               priv->mclk = freq;
+               break;
+       case TAS5086_CLK_IDX_SCLK:
+               priv->sclk = freq;
+               break;
+       }
+
+       return 0;
+}
+
+static int tas5086_set_dai_fmt(struct snd_soc_dai *codec_dai,
+                              unsigned int format)
+{
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       /* The TAS5086 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;
+       }
+
+       /* we need to refer to the data format from hw_params() */
+       priv->format = format;
+
+       return 0;
+}
+
+static const int tas5086_sample_rates[] = {
+       32000, 38000, 44100, 48000, 88200, 96000, 176400, 192000
+};
+
+static const int tas5086_ratios[] = {
+       64, 128, 192, 256, 384, 512
+};
+
+static int index_in_array(const int *array, int len, int needle)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (array[i] == needle)
+                       return i;
+
+       return -ENOENT;
+}
+
+static int tas5086_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 tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       int val;
+       int ret;
+
+       priv->rate = params_rate(params);
+
+       /* Look up the sample rate and refer to the offset in the list */
+       val = index_in_array(tas5086_sample_rates,
+                            ARRAY_SIZE(tas5086_sample_rates), priv->rate);
+
+       if (val < 0) {
+               dev_err(codec->dev, "Invalid sample rate\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_RATE_MASK,
+                                TAS5086_CLOCK_RATE(val));
+       if (ret < 0)
+               return ret;
+
+       /* MCLK / Fs ratio */
+       val = index_in_array(tas5086_ratios, ARRAY_SIZE(tas5086_ratios),
+                            priv->mclk / priv->rate);
+       if (val < 0) {
+               dev_err(codec->dev, "Inavlid MCLK / Fs ratio\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_RATIO_MASK,
+                                TAS5086_CLOCK_RATIO(val));
+       if (ret < 0)
+               return ret;
+
+
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_SCLK_RATIO_48,
+                                (priv->sclk == 48 * priv->rate) ? 
+                                       TAS5086_CLOCK_SCLK_RATIO_48 : 0);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The chip has a very unituitive register mapping and muxes information
+        * about data format and sample depth into the same register, but not on
+        * a logical bit-boundary. Hence, we have to refer to the format passed
+        * in the set_dai_fmt() callback and set up everything from here.
+        *
+        * First, determine the 'base' value, using the format ...
+        */
+       switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) {
+       case SND_SOC_DAIFMT_RIGHT_J:
+               val = 0x00;
+               break;
+       case SND_SOC_DAIFMT_I2S:
+               val = 0x03;
+               break;
+       case SND_SOC_DAIFMT_LEFT_J:
+               val = 0x06;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid DAI format\n");
+               return -EINVAL;
+       }
+
+       /* ... then add the offset for the sample bit depth. */
+       switch (params_format(params)) {
+        case SNDRV_PCM_FORMAT_S16_LE:
+               val += 0;
+                break;
+       case SNDRV_PCM_FORMAT_S20_3LE:
+               val += 1;
+               break;
+       case SNDRV_PCM_FORMAT_S24_3LE:
+               val += 2;
+               break;
+       default:
+               dev_err(codec->dev, "Invalid bit width\n");
+               return -EINVAL;
+       };
+
+       ret = regmap_write(priv->regmap, TAS5086_SERIAL_DATA_IF, val);
+       if (ret < 0)
+               return ret;
+
+       /* clock is considered valid now */
+       ret = regmap_update_bits(priv->regmap, TAS5086_CLOCK_CONTROL,
+                                TAS5086_CLOCK_VALID, TAS5086_CLOCK_VALID);
+       if (ret < 0)
+               return ret;
+
+       return tas5086_set_deemph(codec);
+}
+
+static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int val = 0;
+
+       if (mute)
+               val = TAS5086_SOFT_MUTE_ALL;
+
+       return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val);
+}
+
+/* TAS5086 controls */
+static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1);
+
+static const struct snd_kcontrol_new tas5086_controls[] = {
+       SOC_SINGLE_TLV("Master Playback Volume", TAS5086_MASTER_VOL,
+                      0, 0xff, 1, tas5086_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 1/2 Playback Volume",
+                        TAS5086_CHANNEL_VOL(0), TAS5086_CHANNEL_VOL(1),
+                        0, 0xff, 1, tas5086_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 3/4 Playback Volume",
+                        TAS5086_CHANNEL_VOL(2), TAS5086_CHANNEL_VOL(3),
+                        0, 0xff, 1, tas5086_dac_tlv),
+       SOC_DOUBLE_R_TLV("Channel 5/6 Playback Volume",
+                        TAS5086_CHANNEL_VOL(4), TAS5086_CHANNEL_VOL(5),
+                        0, 0xff, 1, tas5086_dac_tlv),
+       SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0,
+                           tas5086_get_deemph, tas5086_put_deemph),
+};
+
+static const struct snd_soc_dai_ops tas5086_dai_ops = {
+       .hw_params      = tas5086_hw_params,
+       .set_sysclk     = tas5086_set_dai_sysclk,
+       .set_fmt        = tas5086_set_dai_fmt,
+       .mute_stream    = tas5086_mute_stream,
+};
+
+static struct snd_soc_dai_driver tas5086_dai = {
+       .name = "tas5086-hifi",
+       .playback = {
+               .stream_name    = "Playback",
+               .channels_min   = 2,
+               .channels_max   = 6,
+               .rates          = TAS5086_PCM_RATES,
+               .formats        = TAS5086_PCM_FORMATS,
+       },
+       .ops = &tas5086_dai_ops,
+};
+
+#ifdef CONFIG_PM
+static int tas5086_soc_resume(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       /* Restore codec state */
+       return regcache_sync(priv->regmap);
+}
+#else
+#define tas5086_soc_resume     NULL
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_OF
+static const struct of_device_id tas5086_dt_ids[] = {
+       { .compatible = "ti,tas5086", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tas5086_dt_ids);
+#endif
+
+/* charge period values in microseconds */
+static const int tas5086_charge_period[] = {
+         13000,  16900,   23400,   31200,   41600,   54600,   72800,   96200,
+        130000, 156000,  234000,  312000,  416000,  546000,  728000,  962000,
+       1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000,
+};
+
+static int tas5086_probe(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+       int charge_period = 1300000; /* hardware default is 1300 ms */
+       int i, ret;
+
+       if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) {
+               struct device_node *of_node = codec->dev->of_node;
+               of_property_read_u32(of_node, "ti,charge-period", &charge_period);
+       }
+
+       /* lookup and set split-capacitor charge period */
+       if (charge_period == 0) {
+               regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0);
+       } else {
+               i = index_in_array(tas5086_charge_period,
+                                  ARRAY_SIZE(tas5086_charge_period),
+                                  charge_period);
+               if (i >= 0)
+                       regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE,
+                                    i + 0x08);
+               else
+                       dev_warn(codec->dev,
+                                "Invalid split-cap charge period of %d ns.\n",
+                                charge_period);
+       }
+
+       /* enable factory trim */
+       ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00);
+       if (ret < 0)
+               return ret;
+
+       /* start all channels */
+       ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20);
+       if (ret < 0)
+               return ret;
+
+       /* set master volume to 0 dB */
+       ret = regmap_write(priv->regmap, TAS5086_MASTER_VOL, 0x30);
+       if (ret < 0)
+               return ret;
+
+       /* mute all channels for now */
+       ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE,
+                          TAS5086_SOFT_MUTE_ALL);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int tas5086_remove(struct snd_soc_codec *codec)
+{
+       struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec);
+
+       if (gpio_is_valid(priv->gpio_nreset))
+               /* Set codec to the reset state */
+               gpio_set_value(priv->gpio_nreset, 0);
+
+       return 0;
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_tas5086 = {
+       .probe                  = tas5086_probe,
+       .remove                 = tas5086_remove,
+       .resume                 = tas5086_soc_resume,
+       .controls               = tas5086_controls,
+       .num_controls           = ARRAY_SIZE(tas5086_controls),
+};
+
+static const struct i2c_device_id tas5086_i2c_id[] = {
+       { "tas5086", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tas5086_i2c_id);
+
+static const struct regmap_config tas5086_regmap = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register           = ARRAY_SIZE(tas5086_reg_defaults),
+       .reg_defaults           = tas5086_reg_defaults,
+       .num_reg_defaults       = ARRAY_SIZE(tas5086_reg_defaults),
+       .cache_type             = REGCACHE_RBTREE,
+       .volatile_reg           = tas5086_volatile_reg,
+       .writeable_reg          = tas5086_writeable_reg,
+       .readable_reg           = tas5086_accessible_reg,
+};
+
+static int tas5086_i2c_probe(struct i2c_client *i2c,
+                            const struct i2c_device_id *id)
+{
+       struct tas5086_private *priv;
+       struct device *dev = &i2c->dev;
+       int gpio_nreset = -EINVAL;
+       int i, ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = devm_regmap_init_i2c(i2c, &tas5086_regmap);
+       if (IS_ERR(priv->regmap)) {
+               ret = PTR_ERR(priv->regmap);
+               dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(i2c, priv);
+
+       if (of_match_device(of_match_ptr(tas5086_dt_ids), dev)) {
+               struct device_node *of_node = dev->of_node;
+               gpio_nreset = of_get_named_gpio(of_node, "reset-gpio", 0);
+       }
+
+       if (gpio_is_valid(gpio_nreset))
+               if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset"))
+                       gpio_nreset = -EINVAL;
+
+       if (gpio_is_valid(gpio_nreset)) {
+               /* Reset codec - minimum assertion time is 400ns */
+               gpio_direction_output(gpio_nreset, 0);
+               udelay(1);
+               gpio_set_value(gpio_nreset, 1);
+
+               /* Codec needs ~15ms to wake up */
+               msleep(15);
+       }
+
+       priv->gpio_nreset = gpio_nreset;
+
+       /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */
+       ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i);
+       if (ret < 0)
+               return ret;
+
+       if (i != 0x3) {
+               dev_err(dev,
+                       "Failed to identify TAS5086 codec (got %02x)\n", i);
+               return -ENODEV;
+       }
+
+       return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_tas5086,
+               &tas5086_dai, 1);
+}
+
+static int tas5086_i2c_remove(struct i2c_client *i2c)
+{
+       snd_soc_unregister_codec(&i2c->dev);
+       return 0;
+}
+
+static struct i2c_driver tas5086_i2c_driver = {
+       .driver = {
+               .name   = "tas5086",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(tas5086_dt_ids),
+       },
+       .id_table       = tas5086_i2c_id,
+       .probe          = tas5086_i2c_probe,
+       .remove         = tas5086_i2c_remove,
+};
+
+module_i2c_driver(tas5086_i2c_driver);
+
+MODULE_AUTHOR("Daniel Mack <zonque@gmail.com>");
+MODULE_DESCRIPTION("Texas Instruments TAS5086 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
index ad2fee4..8df2b6e 100644 (file)
@@ -342,7 +342,7 @@ static void byte_swap_64(u64 *data_in, u64 *data_out, u32 len)
                data_out[i] = cpu_to_be64(le64_to_cpu(data_in[i]));
 }
 
-static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
+static int wm0010_firmware_load(const char *name, struct snd_soc_codec *codec)
 {
        struct spi_device *spi = to_spi_device(codec->dev);
        struct wm0010_priv *wm0010 = snd_soc_codec_get_drvdata(codec);
@@ -361,8 +361,8 @@ static int wm0010_firmware_load(char *name, struct snd_soc_codec *codec)
 
        ret = request_firmware(&fw, name, codec->dev);
        if (ret != 0) {
-               dev_err(codec->dev, "Failed to request application: %d\n",
-                       ret);
+               dev_err(codec->dev, "Failed to request application(%s): %d\n",
+                       name, ret);
                return ret;
        }
 
index f2ac38b..7fefd76 100644 (file)
@@ -761,6 +761,8 @@ static bool wm2000_readable_reg(struct device *dev, unsigned int reg)
        case WM2000_REG_SYS_CTL2:
        case WM2000_REG_ANC_STAT:
        case WM2000_REG_IF_CTL:
+       case WM2000_REG_ANA_MIC_CTL:
+       case WM2000_REG_SPK_CTL:
                return true;
        default:
                return false;
@@ -771,7 +773,7 @@ static const struct regmap_config wm2000_regmap = {
        .reg_bits = 16,
        .val_bits = 8,
 
-       .max_register = WM2000_REG_IF_CTL,
+       .max_register = WM2000_REG_SPK_CTL,
        .readable_reg = wm2000_readable_reg,
 };
 
index fb812cd..3870c0e 100644 (file)
@@ -30,6 +30,8 @@
 #define WM2000_REG_SYS_CTL2         0xf004
 #define WM2000_REG_ANC_STAT         0xf005
 #define WM2000_REG_IF_CTL           0xf006
+#define WM2000_REG_ANA_MIC_CTL      0xf028
+#define WM2000_REG_SPK_CTL          0xf034
 
 /* SPEECH_CLARITY */
 #define WM2000_SPEECH_CLARITY   0x01
index ddc98f0..57ba315 100644 (file)
@@ -1565,7 +1565,7 @@ static int wm2200_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 2);
+       ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
        if (ret != 0)
                return ret;
 
index b82bbf5..e895d39 100644 (file)
@@ -36,9 +36,6 @@
 struct wm5102_priv {
        struct arizona_priv core;
        struct arizona_fll fll[2];
-
-       unsigned int spk_ena:2;
-       unsigned int spk_ena_pending:1;
 };
 
 static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0);
@@ -584,7 +581,7 @@ static int wm5102_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);
+       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;
@@ -615,6 +612,26 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+static const char *wm5102_osr_text[] = {
+       "Low power", "Normal", "High performance",
+};
+
+static const unsigned int wm5102_osr_val[] = {
+       0x0, 0x3, 0x5,
+};
+
+static const struct soc_enum wm5102_hpout_osr[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L,
+                             ARIZONA_OUT1_OSR_SHIFT, 0x7, 3,
+                             wm5102_osr_text, wm5102_osr_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L,
+                             ARIZONA_OUT2_OSR_SHIFT, 0x7, 3,
+                             wm5102_osr_text, wm5102_osr_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L,
+                             ARIZONA_OUT3_OSR_SHIFT, 0x7, 3,
+                             wm5102_osr_text, wm5102_osr_val),
+};
+
 #define WM5102_NG_SRC(name, base) \
        SOC_SINGLE(name " NG HPOUT1L Switch",  base, 0, 1, 0), \
        SOC_SINGLE(name " NG HPOUT1R Switch",  base, 1, 1, 0), \
@@ -745,6 +762,9 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode),
 SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode),
 SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode),
 
+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),
 
@@ -761,6 +781,8 @@ ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_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),
 
@@ -790,6 +812,10 @@ 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", wm5102_hpout_osr[0]),
+SOC_VALUE_ENUM("HPOUT2 OSR", wm5102_hpout_osr[1]),
+SOC_VALUE_ENUM("HPOUT3 OSR", wm5102_hpout_osr[2]),
+
 SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp),
 SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp),
 
@@ -828,47 +854,6 @@ ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE),
 ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE),
 };
 
-static int wm5102_spk_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 wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec);
-
-       if (arizona->rev < 1)
-               return 0;
-
-       switch (event) {
-       case SND_SOC_DAPM_PRE_PMU:
-               if (!wm5102->spk_ena) {
-                       snd_soc_write(codec, 0x4f5, 0x25a);
-                       wm5102->spk_ena_pending = true;
-               }
-               break;
-       case SND_SOC_DAPM_POST_PMU:
-               if (wm5102->spk_ena_pending) {
-                       msleep(75);
-                       snd_soc_write(codec, 0x4f5, 0xda);
-                       wm5102->spk_ena_pending = false;
-                       wm5102->spk_ena++;
-               }
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               wm5102->spk_ena--;
-               if (!wm5102->spk_ena)
-                       snd_soc_write(codec, 0x4f5, 0x25a);
-               break;
-       case SND_SOC_DAPM_POST_PMD:
-               if (!wm5102->spk_ena)
-                       snd_soc_write(codec, 0x4f5, 0x0da);
-               break;
-       }
-
-       return 0;
-}
-
-
 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);
@@ -984,22 +969,28 @@ SND_SOC_DAPM_INPUT("IN3R"),
 
 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_PMU),
+                  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_PMU),
+                  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_PMU),
+                  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_PMU),
+                  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("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  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("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  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),
@@ -1131,11 +1122,11 @@ ARIZONA_DSP_WIDGETS(DSP1, "DSP1"),
 SND_SOC_DAPM_VALUE_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
                       ARIZONA_AEC_LOOPBACK_ENA, 0, &wm5102_aec_loopback_mux),
 
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
@@ -1146,12 +1137,6 @@ SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
 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("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, wm5102_spk_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, wm5102_spk_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),
@@ -1494,6 +1479,12 @@ static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout);
        case WM5102_FLL2:
                return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout);
+       case WM5102_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&wm5102->fll[0], source, Fref,
+                                             Fout);
+       case WM5102_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&wm5102->fll[1], source, Fref,
+                                             Fout);
        default:
                return -EINVAL;
        }
@@ -1581,10 +1572,12 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
        if (ret != 0)
                return ret;
 
-       ret = snd_soc_add_codec_controls(codec, wm_adsp_fw_controls, 1);
+       ret = snd_soc_add_codec_controls(codec, wm_adsp2_fw_controls, 2);
        if (ret != 0)
                return ret;
 
+       arizona_init_spk(codec);
+
        snd_soc_dapm_disable_pin(&codec->dapm, "HAPTICS");
 
        priv->core.arizona->dapm = &codec->dapm;
@@ -1604,13 +1597,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec)
 #define WM5102_DIG_VU 0x0200
 
 static unsigned int wm5102_digital_vu[] = {
-       ARIZONA_ADC_DIGITAL_VOLUME_1L,
-       ARIZONA_ADC_DIGITAL_VOLUME_1R,
-       ARIZONA_ADC_DIGITAL_VOLUME_2L,
-       ARIZONA_ADC_DIGITAL_VOLUME_2R,
-       ARIZONA_ADC_DIGITAL_VOLUME_3L,
-       ARIZONA_ADC_DIGITAL_VOLUME_3R,
-
        ARIZONA_DAC_DIGITAL_VOLUME_1L,
        ARIZONA_DAC_DIGITAL_VOLUME_1R,
        ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -1653,6 +1639,7 @@ static int wm5102_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, wm5102);
 
        wm5102->core.arizona = arizona;
+       wm5102->core.num_inputs = 6;
 
        wm5102->core.adsp[0].part = "wm5102";
        wm5102->core.adsp[0].num = 1;
@@ -1677,6 +1664,12 @@ static int wm5102_probe(struct platform_device *pdev)
                         ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK,
                         &wm5102->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(wm5102_dai); i++)
                arizona_init_dai(&wm5102->core, i);
 
index d30477f..adb3804 100644 (file)
@@ -15,7 +15,9 @@
 
 #include "arizona.h"
 
-#define WM5102_FLL1 1
-#define WM5102_FLL2 2
+#define WM5102_FLL1        1
+#define WM5102_FLL2        2
+#define WM5102_FLL1_REFCLK 3
+#define WM5102_FLL2_REFCLK 4
 
 #endif
index cdeb301..731884e 100644 (file)
@@ -416,28 +416,36 @@ SND_SOC_DAPM_INPUT("IN4R"),
 
 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_PMU),
+                  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_PMU),
+                  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_PMU),
+                  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_PMU),
+                  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("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  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("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  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("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  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("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT,
                   0, NULL, 0, arizona_in_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  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),
@@ -551,11 +559,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0,
 SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
                    ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0),
 
-SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
+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("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
@@ -569,12 +577,6 @@ SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
 SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
-SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1,
-                  ARIZONA_OUT4R_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),
@@ -880,6 +882,12 @@ static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
                return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout);
        case WM5110_FLL2:
                return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout);
+       case WM5110_FLL1_REFCLK:
+               return arizona_set_fll_refclk(&wm5110->fll[0], source, Fref,
+                                             Fout);
+       case WM5110_FLL2_REFCLK:
+               return arizona_set_fll_refclk(&wm5110->fll[1], source, Fref,
+                                             Fout);
        default:
                return -EINVAL;
        }
@@ -987,15 +995,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec)
 #define WM5110_DIG_VU 0x0200
 
 static unsigned int wm5110_digital_vu[] = {
-       ARIZONA_ADC_DIGITAL_VOLUME_1L,
-       ARIZONA_ADC_DIGITAL_VOLUME_1R,
-       ARIZONA_ADC_DIGITAL_VOLUME_2L,
-       ARIZONA_ADC_DIGITAL_VOLUME_2R,
-       ARIZONA_ADC_DIGITAL_VOLUME_3L,
-       ARIZONA_ADC_DIGITAL_VOLUME_3R,
-       ARIZONA_ADC_DIGITAL_VOLUME_4L,
-       ARIZONA_ADC_DIGITAL_VOLUME_4R,
-
        ARIZONA_DAC_DIGITAL_VOLUME_1L,
        ARIZONA_DAC_DIGITAL_VOLUME_1R,
        ARIZONA_DAC_DIGITAL_VOLUME_2L,
@@ -1040,6 +1039,7 @@ static int wm5110_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, wm5110);
 
        wm5110->core.arizona = arizona;
+       wm5110->core.num_inputs = 8;
 
        for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++)
                wm5110->fll[i].vco_mult = 3;
index 75e9351..e6c0cd4 100644 (file)
@@ -15,7 +15,9 @@
 
 #include "arizona.h"
 
-#define WM5110_FLL1 1
-#define WM5110_FLL2 2
+#define WM5110_FLL1        1
+#define WM5110_FLL2        2
+#define WM5110_FLL1_REFCLK 3
+#define WM5110_FLL2_REFCLK 4
 
 #endif
index 134e41c..9d88437 100644 (file)
@@ -478,6 +478,8 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
 /* ALSA can only do steps of .01dB */
 static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1);
 
+static const DECLARE_TLV_DB_SCALE(dac_boost_tlv, 0, 600, 0);
+
 static const DECLARE_TLV_DB_SCALE(digital_sidetone_tlv, -3600, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
 
@@ -698,6 +700,8 @@ SOC_ENUM("DAC Mute Mode", mute_mode),
 SOC_SINGLE("DAC Mono Switch", WM8903_DAC_DIGITAL_1, 12, 1, 0),
 SOC_ENUM("DAC Companding Mode", dac_companding),
 SOC_SINGLE("DAC Companding Switch", WM8903_AUDIO_INTERFACE_0, 1, 1, 0),
+SOC_SINGLE_TLV("DAC Boost Volume", WM8903_AUDIO_INTERFACE_0, 9, 3, 0,
+              dac_boost_tlv),
 SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
                    wm8903_get_deemph, wm8903_put_deemph),
 
@@ -1083,6 +1087,8 @@ static const struct snd_soc_dapm_route wm8903_intercon[] = {
        { "ROP", NULL, "Right Speaker PGA" },
        { "RON", NULL, "Right Speaker PGA" },
 
+       { "Charge Pump", NULL, "CLK_DSP" },
+
        { "Left Headphone Output PGA", NULL, "Charge Pump" },
        { "Right Headphone Output PGA", NULL, "Charge Pump" },
        { "Left Line Output PGA", NULL, "Charge Pump" },
index a64b934..0a4ffdd 100644 (file)
@@ -204,6 +204,7 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0);
 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1);
 static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0);
 static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
+static const DECLARE_TLV_DB_SCALE(boost_tlv, -1200, 300, 1);
 
 static const struct snd_kcontrol_new wm8960_snd_controls[] = {
 SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
@@ -213,6 +214,15 @@ SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
 SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
        7, 1, 0),
 
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
+              WM8960_INBMIX1, 4, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT2 Volume",
+              WM8960_INBMIX1, 1, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT3 Volume",
+              WM8960_INBMIX2, 4, 7, 0, boost_tlv),
+SOC_SINGLE_TLV("Left Input Boost Mixer LINPUT2 Volume",
+              WM8960_INBMIX2, 1, 7, 0, boost_tlv),
+
 SOC_DOUBLE_R_TLV("Playback Volume", WM8960_LDAC, WM8960_RDAC,
                 0, 255, 0, dac_tlv),
 
index c9bd445..14094f5 100644 (file)
@@ -2209,7 +2209,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                vmid_reference(codec);
                                break;
                        case WM8958:
-                               if (wm8994->revision < 1)
+                               if (control->revision < 1)
                                        vmid_reference(codec);
                                break;
                        default:
@@ -2244,7 +2244,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                                vmid_dereference(codec);
                                break;
                        case WM8958:
-                               if (wm8994->revision < 1)
+                               if (control->revision < 1)
                                        vmid_dereference(codec);
                                break;
                        default:
@@ -2268,10 +2268,26 @@ out:
         */
        if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
                dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+
+               wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+               wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+
                snd_soc_update_bits(codec, WM8994_AIF1_RATE,
                                    WM8994_AIF1CLK_RATE_MASK, 0x1);
                snd_soc_update_bits(codec, WM8994_AIF2_RATE,
                                    WM8994_AIF2CLK_RATE_MASK, 0x1);
+       } else if (wm8994->aifdiv[0]) {
+               snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+                                   WM8994_AIF1CLK_RATE_MASK,
+                                   wm8994->aifdiv[0]);
+               snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+                                   WM8994_AIF2CLK_RATE_MASK,
+                                   wm8994->aifdiv[1]);
+
+               wm8994->aifdiv[0] = 0;
+               wm8994->aifdiv[1] = 0;
        }
 
        return 0;
@@ -2368,10 +2384,26 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
         */
        if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
                dev_dbg(codec->dev, "Configuring AIFs for 128fs\n");
+
+               wm8994->aifdiv[0] = snd_soc_read(codec, WM8994_AIF1_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+               wm8994->aifdiv[1] = snd_soc_read(codec, WM8994_AIF2_RATE)
+                       & WM8994_AIF1CLK_RATE_MASK;
+
                snd_soc_update_bits(codec, WM8994_AIF1_RATE,
                                    WM8994_AIF1CLK_RATE_MASK, 0x1);
                snd_soc_update_bits(codec, WM8994_AIF2_RATE,
                                    WM8994_AIF2CLK_RATE_MASK, 0x1);
+       } else if (wm8994->aifdiv[0]) {
+               snd_soc_update_bits(codec, WM8994_AIF1_RATE,
+                                   WM8994_AIF1CLK_RATE_MASK,
+                                   wm8994->aifdiv[0]);
+               snd_soc_update_bits(codec, WM8994_AIF2_RATE,
+                                   WM8994_AIF2CLK_RATE_MASK,
+                                   wm8994->aifdiv[1]);
+
+               wm8994->aifdiv[0] = 0;
+               wm8994->aifdiv[1] = 0;
        }
 
        return 0;
@@ -2411,7 +2443,7 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
                if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
                        switch (control->type) {
                        case WM8958:
-                               if (wm8994->revision == 0) {
+                               if (control->revision == 0) {
                                        /* Optimise performance for rev A */
                                        snd_soc_update_bits(codec,
                                                            WM8958_CHARGE_PUMP_2,
@@ -2656,6 +2688,8 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
+       struct wm8994 *control = wm8994->wm8994;
+       struct wm8994_pdata *pdata = &control->pdata;
        int aif1_reg;
        int aif2_reg;
        int bclk_reg;
@@ -2723,7 +2757,14 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        }
 
        wm8994->channels[id] = params_channels(params);
-       switch (params_channels(params)) {
+       if (pdata->max_channels_clocked[id] &&
+           wm8994->channels[id] > pdata->max_channels_clocked[id]) {
+               dev_dbg(dai->dev, "Constraining channels to %d from %d\n",
+                       pdata->max_channels_clocked[id], wm8994->channels[id]);
+               wm8994->channels[id] = pdata->max_channels_clocked[id];
+       }
+
+       switch (wm8994->channels[id]) {
        case 1:
        case 2:
                bclk_rate *= 2;
@@ -2745,7 +2786,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
        dev_dbg(dai->dev, "AIF%dCLK is %dHz, target BCLK %dHz\n",
                dai->id, wm8994->aifclk[id], bclk_rate);
 
-       if (params_channels(params) == 1 &&
+       if (wm8994->channels[id] == 1 &&
            (snd_soc_read(codec, aif1_reg) & 0x18) == 0x18)
                aif2 |= WM8994_AIF1_MONO;
 
@@ -3053,7 +3094,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
        int i, ret;
        unsigned int val, mask;
 
-       if (wm8994->revision < 4) {
+       if (control->revision < 4) {
                /* force a HW read */
                ret = regmap_read(control->regmap,
                                  WM8994_POWER_MANAGEMENT_5, &val);
@@ -3870,7 +3911,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        codec->dapm.idle_bias_off = 1;
 
        /* Set revision-specific configuration */
-       wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION);
        switch (control->type) {
        case WM8994:
                /* Single ended line outputs should have VMID on. */
@@ -3878,7 +3918,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                    !control->pdata.lineout2_diff)
                        codec->dapm.idle_bias_off = 0;
 
-               switch (wm8994->revision) {
+               switch (control->revision) {
                case 2:
                case 3:
                        wm8994->hubs.dcs_codes_l = -5;
@@ -3897,7 +3937,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                wm8994->hubs.dcs_readback_mode = 1;
                wm8994->hubs.hp_startup_mode = 1;
 
-               switch (wm8994->revision) {
+               switch (control->revision) {
                case 0:
                        break;
                default:
@@ -4000,7 +4040,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
 
        switch (control->type) {
        case WM1811:
-               if (control->cust_id > 1 || wm8994->revision > 1) {
+               if (control->cust_id > 1 || control->revision > 1) {
                        ret = wm8994_request_irq(wm8994->wm8994,
                                                 WM8994_IRQ_GPIO(6),
                                                 wm1811_jackdet_irq, "JACKDET",
@@ -4114,7 +4154,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        case WM8994:
                snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets,
                                          ARRAY_SIZE(wm8994_specific_dapm_widgets));
-               if (wm8994->revision < 4) {
+               if (control->revision < 4) {
                        snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
                                                  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
                        snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
@@ -4135,7 +4175,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                                     ARRAY_SIZE(wm8958_snd_controls));
                snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
                                          ARRAY_SIZE(wm8958_dapm_widgets));
-               if (wm8994->revision < 1) {
+               if (control->revision < 1) {
                        snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets,
                                                  ARRAY_SIZE(wm8994_lateclk_revd_widgets));
                        snd_soc_dapm_new_controls(dapm, wm8994_adc_revd_widgets,
@@ -4174,7 +4214,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                        ARRAY_SIZE(wm8994_intercon));
 
-               if (wm8994->revision < 4) {
+               if (control->revision < 4) {
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
                                                ARRAY_SIZE(wm8994_revd_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
@@ -4185,7 +4225,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                }
                break;
        case WM8958:
-               if (wm8994->revision < 1) {
+               if (control->revision < 1) {
                        snd_soc_dapm_add_routes(dapm, wm8994_intercon,
                                                ARRAY_SIZE(wm8994_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
index 45f1927..55ddf4d 100644 (file)
@@ -79,6 +79,7 @@ struct wm8994_priv {
        int sysclk_rate[2];
        int mclk[2];
        int aifclk[2];
+       int aifdiv[2];
        int channels[2];
        struct wm8994_fll_config fll[2], fll_suspend[2];
        struct completion fll_locked[2];
@@ -146,8 +147,6 @@ struct wm8994_priv {
        wm1811_mic_id_cb mic_id_cb;
        void *mic_id_cb_data;
 
-       int revision;
-
        unsigned int aif1clk_enable:1;
        unsigned int aif2clk_enable:1;
 
index 9af1bdd..3470b64 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <linux/mfd/arizona/registers.h>
 
+#include "arizona.h"
 #include "wm_adsp.h"
 
 #define adsp_crit(_dsp, fmt, ...) \
@@ -193,17 +194,25 @@ static void wm_adsp_buf_free(struct list_head *list)
 
 #define WM_ADSP_NUM_FW 4
 
+#define WM_ADSP_FW_MBC_VSS 0
+#define WM_ADSP_FW_TX      1
+#define WM_ADSP_FW_TX_SPK  2
+#define WM_ADSP_FW_RX_ANC  3
+
 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = {
-       "MBC/VSS", "Tx", "Tx Speaker", "Rx ANC"
+       [WM_ADSP_FW_MBC_VSS] = "MBC/VSS",
+       [WM_ADSP_FW_TX] =      "Tx",
+       [WM_ADSP_FW_TX_SPK] =  "Tx Speaker",
+       [WM_ADSP_FW_RX_ANC] =  "Rx ANC",
 };
 
 static struct {
        const char *file;
 } wm_adsp_fw[WM_ADSP_NUM_FW] = {
-       { .file = "mbc-vss" },
-       { .file = "tx" },
-       { .file = "tx-spk" },
-       { .file = "rx-anc" },
+       [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" },
+       [WM_ADSP_FW_TX] =      { .file = "tx" },
+       [WM_ADSP_FW_TX_SPK] =  { .file = "tx-spk" },
+       [WM_ADSP_FW_RX_ANC] =  { .file = "rx-anc" },
 };
 
 static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol,
@@ -246,17 +255,52 @@ static const struct soc_enum wm_adsp_fw_enum[] = {
        SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text),
 };
 
-const struct snd_kcontrol_new wm_adsp_fw_controls[] = {
+const struct snd_kcontrol_new wm_adsp1_fw_controls[] = {
+       SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
+                    wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
+                    wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
+                    wm_adsp_fw_get, wm_adsp_fw_put),
+};
+EXPORT_SYMBOL_GPL(wm_adsp1_fw_controls);
+
+#if IS_ENABLED(CONFIG_SND_SOC_ARIZONA)
+static const struct soc_enum wm_adsp2_rate_enum[] = {
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP1_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP2_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+       SOC_VALUE_ENUM_SINGLE(ARIZONA_DSP3_CONTROL_1,
+                             ARIZONA_DSP1_RATE_SHIFT, 0xf,
+                             ARIZONA_RATE_ENUM_SIZE,
+                             arizona_rate_text, arizona_rate_val),
+};
+
+const struct snd_kcontrol_new wm_adsp2_fw_controls[] = {
        SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP1 Rate", wm_adsp2_rate_enum[0]),
        SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP2 Rate", wm_adsp2_rate_enum[1]),
        SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP3 Rate", wm_adsp2_rate_enum[2]),
        SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3],
                     wm_adsp_fw_get, wm_adsp_fw_put),
+       SOC_ENUM("DSP4 Rate", wm_adsp2_rate_enum[3]),
 };
-EXPORT_SYMBOL_GPL(wm_adsp_fw_controls);
+EXPORT_SYMBOL_GPL(wm_adsp2_fw_controls);
+#endif
 
 static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp,
                                                        int type)
@@ -549,13 +593,30 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                buf_size = sizeof(adsp1_id);
 
                algs = be32_to_cpu(adsp1_id.algs);
+               dsp->fw_id = be32_to_cpu(adsp1_id.fw.id);
                adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-                         be32_to_cpu(adsp1_id.fw.id),
+                         dsp->fw_id,
                          (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16,
                          (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8,
                          be32_to_cpu(adsp1_id.fw.ver) & 0xff,
                          algs);
 
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP1_ZM;
+               region->alg = be32_to_cpu(adsp1_id.fw.id);
+               region->base = be32_to_cpu(adsp1_id.zm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP1_DM;
+               region->alg = be32_to_cpu(adsp1_id.fw.id);
+               region->base = be32_to_cpu(adsp1_id.dm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
                pos = sizeof(adsp1_id) / 2;
                term = pos + ((sizeof(*adsp1_alg) * algs) / 2);
                break;
@@ -573,13 +634,38 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
                buf_size = sizeof(adsp2_id);
 
                algs = be32_to_cpu(adsp2_id.algs);
+               dsp->fw_id = be32_to_cpu(adsp2_id.fw.id);
                adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n",
-                         be32_to_cpu(adsp2_id.fw.id),
+                         dsp->fw_id,
                          (be32_to_cpu(adsp2_id.fw.ver) & 0xff0000) >> 16,
                          (be32_to_cpu(adsp2_id.fw.ver) & 0xff00) >> 8,
                          be32_to_cpu(adsp2_id.fw.ver) & 0xff,
                          algs);
 
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP2_XM;
+               region->alg = be32_to_cpu(adsp2_id.fw.id);
+               region->base = be32_to_cpu(adsp2_id.xm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP2_YM;
+               region->alg = be32_to_cpu(adsp2_id.fw.id);
+               region->base = be32_to_cpu(adsp2_id.ym);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
+               region = kzalloc(sizeof(*region), GFP_KERNEL);
+               if (!region)
+                       return -ENOMEM;
+               region->type = WMFW_ADSP2_ZM;
+               region->alg = be32_to_cpu(adsp2_id.fw.id);
+               region->base = be32_to_cpu(adsp2_id.zm);
+               list_add_tail(&region->list, &dsp->alg_regions);
+
                pos = sizeof(adsp2_id) / 2;
                term = pos + ((sizeof(*adsp2_alg) * algs) / 2);
                break;
@@ -781,8 +867,24 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp)
                case (WMFW_INFO_TEXT << 8):
                        break;
                case (WMFW_ABSOLUTE << 8):
-                       region_name = "register";
-                       reg = offset;
+                       /*
+                        * Old files may use this for global
+                        * coefficients.
+                        */
+                       if (le32_to_cpu(blk->id) == dsp->fw_id &&
+                           offset == 0) {
+                               region_name = "global coefficients";
+                               mem = wm_adsp_find_region(dsp, type);
+                               if (!mem) {
+                                       adsp_err(dsp, "No ZM\n");
+                                       break;
+                               }
+                               reg = wm_adsp_region_to_reg(mem, 0);
+
+                       } else {
+                               region_name = "register";
+                               reg = offset;
+                       }
                        break;
 
                case WMFW_ADSP1_DM:
index cb8871a..fea5146 100644 (file)
@@ -46,6 +46,8 @@ struct wm_adsp {
 
        struct list_head alg_regions;
 
+       int fw_id;
+
        const struct wm_adsp_region *mem;
        int num_mems;
 
@@ -65,7 +67,8 @@ struct wm_adsp {
        .shift = num, .event = wm_adsp2_event, \
        .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD }
 
-extern const struct snd_kcontrol_new wm_adsp_fw_controls[];
+extern const struct snd_kcontrol_new wm_adsp1_fw_controls[];
+extern const struct snd_kcontrol_new wm_adsp2_fw_controls[];
 
 int wm_adsp1_init(struct wm_adsp *adsp);
 int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs);
index 867ae97..f5d81b9 100644 (file)
@@ -199,11 +199,12 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
        list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
-static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+static int wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
                                  u16 *reg_l, u16 *reg_r)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        u16 dcs_reg, reg;
+       int ret = 0;
 
        switch (hubs->dcs_readback_mode) {
        case 2:
@@ -236,8 +237,9 @@ static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
                break;
        default:
                WARN(1, "Unknown DCS readback method\n");
-               return;
+               ret = -1;
        }
+       return ret;
 }
 
 /*
@@ -286,7 +288,8 @@ static void enable_dc_servo(struct snd_soc_codec *codec)
                                  WM8993_DCS_TRIG_STARTUP_1);
        }
 
-       wm_hubs_read_dc_servo(codec, &reg_l, &reg_r);
+       if (wm_hubs_read_dc_servo(codec, &reg_l, &reg_r) < 0)
+               return;
 
        dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
index 8218312..ebe8294 100644 (file)
@@ -645,6 +645,10 @@ static struct snd_soc_dai_driver davinci_i2s_dai = {
 
 };
 
+static const struct snd_soc_component_driver davinci_i2s_component = {
+       .name           = "davinci-i2s",
+};
+
 static int davinci_i2s_probe(struct platform_device *pdev)
 {
        struct snd_platform_data *pdata = pdev->dev.platform_data;
@@ -727,20 +731,21 @@ static int davinci_i2s_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, dev);
 
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_i2s_component,
+                                        &davinci_i2s_dai, 1);
        if (ret != 0)
                goto err_release_clk;
 
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
        clk_disable(dev->clk);
        clk_put(dev->clk);
@@ -751,7 +756,7 @@ static int davinci_i2s_remove(struct platform_device *pdev)
 {
        struct davinci_mcbsp_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        clk_disable(dev->clk);
index 9321e5c..aeb3a66 100644 (file)
 #define DISMOD         (val)(val<<2)
 #define TXSTATE                BIT(4)
 #define RXSTATE                BIT(5)
+#define SRMOD_MASK     3
+#define SRMOD_INACTIVE 0
 
 /*
  * DAVINCI_MCASP_LBCTL_REG - Loop Back Control Register Bits
@@ -643,26 +645,33 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev,
        /* mapping of the XSSZ bit-field as described in the datasheet */
        fmt = (word_length >> 1) - 1;
 
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
-                                       RXSSZ(fmt), RXSSZ(0x0F));
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
-                                       TXSSZ(fmt), TXSSZ(0x0F));
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate),
-                                                       TXROT(7));
-       mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate),
-                                                       RXROT(7));
+       if (dev->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+                               RXSSZ(fmt), RXSSZ(0x0F));
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+                               TXSSZ(fmt), TXSSZ(0x0F));
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
+                               TXROT(rotate), TXROT(7));
+               mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG,
+                               RXROT(rotate), RXROT(7));
+               mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG,
+                               mask);
+       }
+
        mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask);
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask);
 
        return 0;
 }
 
-static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
+static int davinci_hw_common_param(struct davinci_audio_dev *dev, int stream,
+                                   int channels)
 {
        int i;
        u8 tx_ser = 0;
        u8 rx_ser = 0;
-
+       u8 ser;
+       u8 slots = dev->tdm_slots;
+       u8 max_active_serializers = (channels + slots - 1) / slots;
        /* Default configuration */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
 
@@ -682,17 +691,33 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
        for (i = 0; i < dev->num_serializer; i++) {
                mcasp_set_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
                                        dev->serial_dir[i]);
-               if (dev->serial_dir[i] == TX_MODE) {
+               if (dev->serial_dir[i] == TX_MODE &&
+                                       tx_ser < max_active_serializers) {
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        tx_ser++;
-               } else if (dev->serial_dir[i] == RX_MODE) {
+               } else if (dev->serial_dir[i] == RX_MODE &&
+                                       rx_ser < max_active_serializers) {
                        mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG,
                                        AXR(i));
                        rx_ser++;
+               } else {
+                       mcasp_mod_bits(dev->base + DAVINCI_MCASP_XRSRCTL_REG(i),
+                                       SRMOD_INACTIVE, SRMOD_MASK);
                }
        }
 
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ser = tx_ser;
+       else
+               ser = rx_ser;
+
+       if (ser < max_active_serializers) {
+               dev_warn(dev->dev, "stream has more channels (%d) than are "
+                       "enabled in mcasp (%d)\n", channels, ser * slots);
+               return -EINVAL;
+       }
+
        if (dev->txnumevt && stream == SNDRV_PCM_STREAM_PLAYBACK) {
                if (dev->txnumevt * tx_ser > 64)
                        dev->txnumevt = 1;
@@ -729,6 +754,8 @@ static void davinci_hw_common_param(struct davinci_audio_dev *dev, int stream)
                                ((dev->rxnumevt * rx_ser) << 8), NUMEVT_MASK);
                }
        }
+
+       return 0;
 }
 
 static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
@@ -772,12 +799,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream)
 /* S/PDIF */
 static void davinci_hw_dit_param(struct davinci_audio_dev *dev)
 {
-       /* Set the PDIR for Serialiser as output */
-       mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AFSX);
-
-       /* TXMASK for 24 bits */
-       mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0x00FFFFFF);
-
        /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
           and LSB first */
        mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG,
@@ -812,8 +833,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                                        &dev->dma_params[substream->stream];
        int word_length;
        u8 fifo_level;
+       u8 slots = dev->tdm_slots;
+       int channels;
+       struct snd_interval *pcm_channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+       channels = pcm_channels->min;
 
-       davinci_hw_common_param(dev, substream->stream);
+       if (davinci_hw_common_param(dev, substream->stream, channels) == -EINVAL)
+               return -EINVAL;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                fifo_level = dev->txnumevt;
        else
@@ -862,6 +889,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
                dma_params->acnt = dma_params->data_type;
 
        dma_params->fifo_level = fifo_level;
+       dma_params->active_serializers = (channels + slots - 1) / slots;
        davinci_config_channel_size(dev, word_length);
 
        return 0;
@@ -936,13 +964,13 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
                .name           = "davinci-mcasp.0",
                .playback       = {
                        .channels_min   = 2,
-                       .channels_max   = 2,
+                       .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
                .capture        = {
                        .channels_min   = 2,
-                       .channels_max   = 2,
+                       .channels_max   = 32 * 16,
                        .rates          = DAVINCI_MCASP_RATES,
                        .formats        = DAVINCI_MCASP_PCM_FMTS,
                },
@@ -962,6 +990,10 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
 
 };
 
+static const struct snd_soc_component_driver davinci_mcasp_component = {
+       .name           = "davinci-mcasp",
+};
+
 static const struct of_device_id mcasp_dt_ids[] = {
        {
                .compatible = "ti,dm646x-mcasp-audio",
@@ -1015,8 +1047,16 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of(
                pdata->op_mode = val;
 
        ret = of_property_read_u32(np, "tdm-slots", &val);
-       if (ret >= 0)
+       if (ret >= 0) {
+               if (val < 2 || val > 32) {
+                       dev_err(&pdev->dev,
+                               "tdm-slots must be in rage [2-32]\n");
+                       ret = -EINVAL;
+                       goto nodata;
+               }
+
                pdata->tdm_slots = val;
+       }
 
        ret = of_property_read_u32(np, "num-serializer", &val);
        if (ret >= 0)
@@ -1170,7 +1210,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        dma_data->channel = res->start;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component,
+                                        &davinci_mcasp_dai[pdata->op_mode], 1);
 
        if (ret != 0)
                goto err_release_clk;
@@ -1178,13 +1219,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_release_clk:
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
@@ -1194,7 +1235,7 @@ err_release_clk:
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        pm_runtime_put_sync(&pdev->dev);
index afab81f..078031d 100644 (file)
@@ -181,6 +181,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        unsigned short acnt;
        unsigned int count;
        unsigned int fifo_level;
+       unsigned char serializers = prtd->params->active_serializers;
 
        period_size = snd_pcm_lib_period_bytes(substream);
        dma_offset = prtd->period * period_size;
@@ -194,14 +195,14 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
        data_type = prtd->params->data_type;
        count = period_size / data_type;
        if (fifo_level)
-               count /= fifo_level;
+               count /= fifo_level * serializers;
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                src = dma_pos;
                dst = prtd->params->dma_addr;
                src_bidx = data_type;
-               dst_bidx = 0;
-               src_cidx = data_type * fifo_level;
+               dst_bidx = 4;
+               src_cidx = data_type * fifo_level * serializers;
                dst_cidx = 0;
        } else {
                src = prtd->params->dma_addr;
@@ -209,7 +210,7 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
                src_bidx = 0;
                dst_bidx = data_type;
                src_cidx = 0;
-               dst_cidx = data_type * fifo_level;
+               dst_cidx = data_type * fifo_level * serializers;
        }
 
        acnt = prtd->params->acnt;
@@ -223,9 +224,10 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream)
                edma_set_transfer_params(prtd->asp_link[0], acnt, count, 1, 0,
                                                        ASYNC);
        else
-               edma_set_transfer_params(prtd->asp_link[0], acnt, fifo_level,
-                                                       count, fifo_level,
-                                                       ABSYNC);
+               edma_set_transfer_params(prtd->asp_link[0], acnt,
+                                               fifo_level * serializers,
+                                               count, fifo_level * serializers,
+                                               ABSYNC);
 }
 
 static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data)
index b6ef703..32d7634 100644 (file)
@@ -27,6 +27,7 @@ struct davinci_pcm_dma_params {
        unsigned char data_type;        /* xfer data type */
        unsigned char convert_mono_stereo;
        unsigned int fifo_level;
+       unsigned char active_serializers; /* num. of active audio serializers */
 };
 
 int davinci_soc_platform_register(struct device *dev);
index 07bde2e..30587c0 100644 (file)
@@ -204,6 +204,10 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
 
 };
 
+static const struct snd_soc_component_driver davinci_vcif_component = {
+       .name           = "davinci-vcif",
+};
+
 static int davinci_vcif_probe(struct platform_device *pdev)
 {
        struct davinci_vc *davinci_vc = pdev->dev.platform_data;
@@ -234,7 +238,8 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, davinci_vcif_dev);
 
-       ret = snd_soc_register_dai(&pdev->dev, &davinci_vcif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &davinci_vcif_component,
+                                        &davinci_vcif_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "could not register dai\n");
                return ret;
@@ -243,7 +248,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
        ret = davinci_soc_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "register PCM failed: %d\n", ret);
-               snd_soc_unregister_dai(&pdev->dev);
+               snd_soc_unregister_component(&pdev->dev);
                return ret;
        }
 
@@ -252,7 +257,7 @@ static int davinci_vcif_probe(struct platform_device *pdev)
 
 static int davinci_vcif_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        davinci_soc_platform_unregister(&pdev->dev);
 
        return 0;
index deb30d5..593a3ea 100644 (file)
@@ -297,6 +297,10 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = {
        .trigger        = dw_i2s_trigger,
 };
 
+static const struct snd_soc_component_driver dw_i2s_component = {
+       .name           = "dw-i2s",
+};
+
 #ifdef CONFIG_PM
 
 static int dw_i2s_suspend(struct snd_soc_dai *dai)
@@ -413,7 +417,8 @@ static int dw_i2s_probe(struct platform_device *pdev)
 
        dev->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
+                                        dw_i2s_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "not able to register dai\n");
                goto err_set_drvdata;
@@ -434,7 +439,7 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
        struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
        clk_put(dev->clk);
index 7decbd9..42366d7 100644 (file)
@@ -27,6 +27,7 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "fsl_ssi.h"
 #include "imx-pcm.h"
@@ -122,8 +123,10 @@ struct fsl_ssi_private {
        bool ssi_on_imx;
        struct clk *clk;
        struct platform_device *imx_pcm_pdev;
-       struct imx_pcm_dma_params dma_params_tx;
-       struct imx_pcm_dma_params dma_params_rx;
+       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 {
                unsigned int rfrc;
@@ -574,6 +577,10 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = {
        .ops = &fsl_ssi_dai_ops,
 };
 
+static const struct snd_soc_component_driver fsl_ssi_component = {
+       .name           = "fsl-ssi",
+};
+
 /* 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.
@@ -649,6 +656,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        const uint32_t *iprop;
        struct resource res;
        char name[64];
+       bool shared;
 
        /* SSIs that are not connected on the board should have a
         *      status = "disabled"
@@ -737,14 +745,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                 * We have burstsize be "fifo_depth - 2" to match the SSI
                 * watermark setting in fsl_ssi_startup().
                 */
-               ssi_private->dma_params_tx.burstsize =
+               ssi_private->dma_params_tx.maxburst =
                        ssi_private->fifo_depth - 2;
-               ssi_private->dma_params_rx.burstsize =
+               ssi_private->dma_params_rx.maxburst =
                        ssi_private->fifo_depth - 2;
-               ssi_private->dma_params_tx.dma_addr =
+               ssi_private->dma_params_tx.addr =
                        ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
-               ssi_private->dma_params_rx.dma_addr =
+               ssi_private->dma_params_rx.addr =
                        ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
+               ssi_private->dma_params_tx.filter_data =
+                       &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.
@@ -755,14 +767,14 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "could not get dma events\n");
                        goto error_clk;
                }
-               ssi_private->dma_params_tx.dma = dma_events[0];
-               ssi_private->dma_params_rx.dma = dma_events[1];
 
-               ssi_private->dma_params_tx.shared_peripheral =
-                               of_device_is_compatible(of_get_parent(np),
-                                                       "fsl,spba-bus");
-               ssi_private->dma_params_rx.shared_peripheral =
-                               ssi_private->dma_params_tx.shared_peripheral;
+               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);
+               imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
+                       dma_events[1], shared);
        }
 
        /* Initialize the the device_attribute structure */
@@ -782,7 +794,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
        /* Register with ASoC */
        dev_set_drvdata(&pdev->dev, ssi_private);
 
-       ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
+       ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
+                                        &ssi_private->cpu_dai_drv, 1);
        if (ret) {
                dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
                goto error_dev;
@@ -835,7 +848,7 @@ done:
 error_dai:
        if (ssi_private->ssi_on_imx)
                platform_device_unregister(ssi_private->imx_pcm_pdev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
 error_dev:
        dev_set_drvdata(&pdev->dev, NULL);
@@ -873,7 +886,7 @@ static int fsl_ssi_remove(struct platform_device *pdev)
                clk_disable_unprepare(ssi_private->clk);
                clk_put(ssi_private->clk);
        }
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        device_remove_file(&pdev->dev, &ssi_private->dev_attr);
 
        free_irq(ssi_private->irq, ssi_private);
index 3f333e5..47f046a 100644 (file)
@@ -262,7 +262,7 @@ static int imx_audmux_probe(struct platform_device *pdev)
                return PTR_ERR(pinctrl);
        }
 
-       audmux_clk = clk_get(&pdev->dev, "audmux");
+       audmux_clk = devm_clk_get(&pdev->dev, "audmux");
        if (IS_ERR(audmux_clk)) {
                dev_dbg(&pdev->dev, "cannot get clock: %ld\n",
                                PTR_ERR(audmux_clk));
@@ -282,7 +282,6 @@ static int imx_audmux_remove(struct platform_device *pdev)
 {
        if (audmux_type == IMX31_AUDMUX)
                audmux_debugfs_remove();
-       clk_put(audmux_clk);
 
        return 0;
 }
index 500f8ce..ee838c8 100644 (file)
 #include <sound/soc.h>
 #include <sound/dmaengine_pcm.h>
 
-#include <linux/platform_data/dma-imx.h>
-
 #include "imx-pcm.h"
 
 static bool filter(struct dma_chan *chan, void *param)
 {
+       struct snd_dmaengine_dai_dma_data *dma_data = param;
+
        if (!imx_dma_is_general_purpose(chan))
                return false;
 
-       chan->private = param;
+       chan->private = dma_data->filter_data;
 
        return true;
 }
@@ -49,25 +49,16 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
-       struct imx_pcm_dma_params *dma_params;
        struct dma_slave_config slave_config;
        int ret;
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
        ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
        if (ret)
                return ret;
 
-       slave_config.device_fc = false;
-
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.dst_addr = dma_params->dma_addr;
-               slave_config.dst_maxburst = dma_params->burstsize;
-       } else {
-               slave_config.src_addr = dma_params->dma_addr;
-               slave_config.src_maxburst = dma_params->burstsize;
-       }
+       snd_dmaengine_pcm_set_config_from_dai_data(substream,
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+                       &slave_config);
 
        ret = dmaengine_slave_config(chan, &slave_config);
        if (ret)
@@ -100,47 +91,16 @@ static struct snd_pcm_hardware snd_imx_hardware = {
 static int snd_imx_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct imx_pcm_dma_params *dma_params;
-       struct imx_dma_data *dma_data;
-       int ret;
 
        snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
 
-       dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
-       if (!dma_data)
-               return -ENOMEM;
-
-       dma_data->peripheral_type = dma_params->shared_peripheral ?
-                                       IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
-       dma_data->priority = DMA_PRIO_HIGH;
-       dma_data->dma_request = dma_params->dma;
-
-       ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
-       if (ret) {
-               kfree(dma_data);
-               return ret;
-       }
-
-       snd_dmaengine_pcm_set_data(substream, dma_data);
-
-       return 0;
-}
-
-static int snd_imx_close(struct snd_pcm_substream *substream)
-{
-       struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-
-       snd_dmaengine_pcm_close(substream);
-       kfree(dma_data);
-
-       return 0;
+       return snd_dmaengine_pcm_open(substream, filter,
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
 }
 
 static struct snd_pcm_ops imx_pcm_ops = {
        .open           = snd_imx_open,
-       .close          = snd_imx_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = snd_imx_pcm_hw_params,
        .trigger        = snd_dmaengine_pcm_trigger,
index 920f945..670b96b 100644 (file)
@@ -34,7 +34,7 @@
 #include "imx-ssi.h"
 
 struct imx_pcm_runtime_data {
-       int period;
+       unsigned int period;
        int periods;
        unsigned long offset;
        unsigned long last_offset;
@@ -299,8 +299,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
 
        imx_ssi_fiq_base = (unsigned long)ssi->base;
 
-       ssi->dma_params_tx.burstsize = 4;
-       ssi->dma_params_rx.burstsize = 6;
+       ssi->dma_params_tx.maxburst = 4;
+       ssi->dma_params_rx.maxburst = 6;
 
        ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
        if (ret)
index 5ae13a1..be9cc64 100644 (file)
 #ifndef _IMX_PCM_H
 #define _IMX_PCM_H
 
+#include <linux/platform_data/dma-imx.h>
+
 /*
  * Do not change this as the FIQ handler depends on this size
  */
 #define IMX_SSI_DMABUF_SIZE    (64 * 1024)
 
-struct imx_pcm_dma_params {
-       int dma;
-       unsigned long dma_addr;
-       int burstsize;
-       bool shared_peripheral; /* The peripheral is on SPBA bus */
-};
+static inline void
+imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
+       int dma, bool shared)
+{
+       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;
+}
 
 int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
                     struct vm_area_struct *vma);
index 424347e..9584e78 100644 (file)
@@ -148,7 +148,7 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
        data->dai.stream_name = "HiFi";
        data->dai.codec_dai_name = "sgtl5000";
        data->dai.codec_of_node = codec_np;
-       data->dai.cpu_dai_name = dev_name(&ssi_pdev->dev);
+       data->dai.cpu_of_node = ssi_np;
        data->dai.platform_name = "imx-pcm-audio";
        data->dai.init = &imx_sgtl5000_dai_init;
        data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
index 810c7ee..4ce2d60 100644 (file)
@@ -236,7 +236,7 @@ static int imx_ssi_startup(struct snd_pcm_substream *substream,
                           struct snd_soc_dai *cpu_dai)
 {
        struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
-       struct imx_pcm_dma_params *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        /* Tx/Rx config */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -369,8 +369,8 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 
        snd_soc_dai_set_drvdata(dai, ssi);
 
-       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
-               SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
+       val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
+               SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
        writel(val, ssi->base + SSI_SFCSR);
 
        return 0;
@@ -400,7 +400,7 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
                .stream_name = "AC97 Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_48000,
+               .rates = SNDRV_PCM_RATE_8000_48000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
@@ -413,6 +413,10 @@ static struct snd_soc_dai_driver imx_ac97_dai = {
        .ops = &imx_ssi_pcm_dai_ops,
 };
 
+static const struct snd_soc_component_driver imx_component = {
+       .name           = DRV_NAME,
+};
+
 static void setup_channel_to_ac97(struct imx_ssi *imx_ssi)
 {
        void __iomem *base = imx_ssi->base;
@@ -575,23 +579,31 @@ static int imx_ssi_probe(struct platform_device *pdev)
 
        writel(0x0, ssi->base + SSI_SIER);
 
-       ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
-       ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
+       ssi->dma_params_rx.addr = res->start + SSI_SRX0;
+       ssi->dma_params_tx.addr = res->start + SSI_STX0;
 
-       ssi->dma_params_tx.burstsize = 6;
-       ssi->dma_params_rx.burstsize = 4;
+       ssi->dma_params_tx.maxburst = 6;
+       ssi->dma_params_rx.maxburst = 4;
+
+       ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
+       ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
-       if (res)
-               ssi->dma_params_tx.dma = res->start;
+       if (res) {
+               imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
+                       false);
+       }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
-       if (res)
-               ssi->dma_params_rx.dma = res->start;
+       if (res) {
+               imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
+                       false);
+       }
 
        platform_set_drvdata(pdev, ssi);
 
-       ret = snd_soc_register_dai(&pdev->dev, dai);
+       ret = snd_soc_register_component(&pdev->dev, &imx_component,
+                                        dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                goto failed_register;
@@ -632,7 +644,7 @@ failed_pdev_alloc:
 failed_pdev_fiq_add:
        platform_device_put(ssi->soc_platform_pdev_fiq);
 failed_pdev_fiq_alloc:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 failed_register:
        release_mem_region(res->start, resource_size(res));
 failed_get_resource:
@@ -650,7 +662,7 @@ static int imx_ssi_remove(struct platform_device *pdev)
        platform_device_unregister(ssi->soc_platform_pdev);
        platform_device_unregister(ssi->soc_platform_pdev_fiq);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
index dc114bd..bb6b3db 100644 (file)
 
 #include <linux/dmaengine.h>
 #include <linux/platform_data/dma-imx.h>
+#include <sound/dmaengine_pcm.h>
 #include "imx-pcm.h"
 
 struct imx_ssi {
@@ -204,8 +205,10 @@ struct imx_ssi {
        void (*ac97_reset) (struct snd_ac97 *ac97);
        void (*ac97_warm_reset)(struct snd_ac97 *ac97);
 
-       struct imx_pcm_dma_params       dma_params_rx;
-       struct imx_pcm_dma_params       dma_params_tx;
+       struct snd_dmaengine_dai_dma_data dma_params_rx;
+       struct snd_dmaengine_dai_dma_data dma_params_tx;
+       struct imx_dma_data filter_data_tx;
+       struct imx_dma_data filter_data_rx;
 
        int enabled;
 
index a4aec04..4141b35 100644 (file)
@@ -270,6 +270,9 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
        .ops = &psc_ac97_digital_ops,
 } };
 
+static const struct snd_soc_component_driver psc_ac97_component = {
+       .name           = DRV_NAME,
+};
 
 
 /* ---------------------------------------------------------------------
@@ -287,7 +290,8 @@ static int psc_ac97_of_probe(struct platform_device *op)
        if (rc != 0)
                return rc;
 
-       rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
+       rc = snd_soc_register_component(&op->dev, &psc_ac97_component,
+                                       psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
                dev_err(&op->dev, "Failed to register DAI\n");
                return rc;
@@ -313,7 +317,7 @@ static int psc_ac97_of_probe(struct platform_device *op)
 static int psc_ac97_of_remove(struct platform_device *op)
 {
        mpc5200_audio_dma_destroy(op);
-       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
+       snd_soc_unregister_component(&op->dev);
        return 0;
 }
 
index b95b966..f4efaad 100644 (file)
@@ -148,6 +148,10 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{
        .ops = &psc_i2s_dai_ops,
 } };
 
+static const struct snd_soc_component_driver psc_i2s_component = {
+       .name           = "mpc5200-i2s",
+};
+
 /* ---------------------------------------------------------------------
  * OF platform bus binding code:
  * - Probe/remove operations
@@ -163,7 +167,8 @@ static int psc_i2s_of_probe(struct platform_device *op)
        if (rc != 0)
                return rc;
 
-       rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
+       rc = snd_soc_register_component(&op->dev, &psc_i2s_component,
+                                       psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
        if (rc != 0) {
                pr_err("Failed to register DAI\n");
                return rc;
@@ -208,7 +213,7 @@ static int psc_i2s_of_probe(struct platform_device *op)
 static int psc_i2s_of_remove(struct platform_device *op)
 {
        mpc5200_audio_dma_destroy(op);
-       snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
+       snd_soc_unregister_component(&op->dev);
        return 0;
 }
 
index 6cef491..9a12644 100644 (file)
@@ -425,6 +425,10 @@ static struct snd_soc_dai_driver jz4740_i2s_dai = {
        .resume = jz4740_i2s_resume,
 };
 
+static const struct snd_soc_component_driver jz4740_i2s_component = {
+       .name           = "jz4740-i2s",
+};
+
 static int jz4740_i2s_dev_probe(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s;
@@ -469,7 +473,8 @@ static int jz4740_i2s_dev_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, i2s);
-       ret = snd_soc_register_dai(&pdev->dev, &jz4740_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &jz4740_i2s_component,
+                                        &jz4740_i2s_dai, 1);
 
        if (ret) {
                dev_err(&pdev->dev, "Failed to register DAI\n");
@@ -496,7 +501,7 @@ static int jz4740_i2s_dev_remove(struct platform_device *pdev)
 {
        struct jz4740_i2s *i2s = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(i2s->clk_i2s);
        clk_put(i2s->clk_aic);
index c74c890..befe68f 100644 (file)
@@ -451,6 +451,10 @@ static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
        .ops = &kirkwood_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver kirkwood_i2s_component = {
+       .name           = DRV_NAME,
+};
+
 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
 {
        struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
@@ -524,10 +528,11 @@ static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
                priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
        }
 
-       err = snd_soc_register_dai(&pdev->dev, soc_dai);
+       err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
+                                        soc_dai, 1);
        if (!err)
                return 0;
-       dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
+       dev_err(&pdev->dev, "snd_soc_register_component failed\n");
 
        if (!IS_ERR(priv->extclk)) {
                clk_disable_unprepare(priv->extclk);
@@ -542,7 +547,7 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 {
        struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (!IS_ERR(priv->extclk)) {
                clk_disable_unprepare(priv->extclk);
index a263cbe..392fc0b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  sst_platform.c - Intel MID Platform driver
  *
- *  Copyright (C) 2010-2012 Intel Corp
+ *  Copyright (C) 2010-2013 Intel Corp
  *  Author: Vinod Koul <vinod.koul@intel.com>
  *  Author: Harsha Priya <priya.harsha@intel.com>
  *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -165,6 +165,10 @@ static struct snd_soc_dai_driver sst_platform_dai[] = {
 },
 };
 
+static const struct snd_soc_component_driver sst_component = {
+       .name           = "sst",
+};
+
 /* helper functions */
 static inline void sst_set_stream_status(struct sst_runtime_stream *stream,
                                        int state)
@@ -652,11 +656,21 @@ static int sst_platform_compr_get_codec_caps(struct snd_compr_stream *cstream,
        return stream->compr_ops->get_codec_caps(codec);
 }
 
+static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream,
+                                       struct snd_compr_metadata *metadata)
+{
+       struct sst_runtime_stream *stream  =
+                cstream->runtime->private_data;
+
+       return stream->compr_ops->set_metadata(stream->id, metadata);
+}
+
 static struct snd_compr_ops sst_platform_compr_ops = {
 
        .open = sst_platform_compr_open,
        .free = sst_platform_compr_free,
        .set_params = sst_platform_compr_set_params,
+       .set_metadata = sst_platform_compr_set_metadata,
        .trigger = sst_platform_compr_trigger,
        .pointer = sst_platform_compr_pointer,
        .ack = sst_platform_compr_ack,
@@ -683,7 +697,7 @@ static int sst_platform_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = snd_soc_register_dais(&pdev->dev,
+       ret = snd_soc_register_component(&pdev->dev, &sst_component,
                                sst_platform_dai, ARRAY_SIZE(sst_platform_dai));
        if (ret) {
                pr_err("registering cpu dais failed\n");
@@ -695,7 +709,7 @@ static int sst_platform_probe(struct platform_device *pdev)
 static int sst_platform_remove(struct platform_device *pdev)
 {
 
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai));
+       snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
        pr_debug("sst_platform_remove success\n");
        return 0;
index d61c5d5..cacc906 100644 (file)
@@ -124,6 +124,8 @@ struct compress_sst_ops {
        int (*close) (unsigned int str_id);
        int (*get_caps) (struct snd_compr_caps *caps);
        int (*get_codec_caps) (struct snd_compr_codec_caps *codec);
+       int (*set_metadata) (unsigned int str_id,
+                       struct snd_compr_metadata *mdata);
 
 };
 
index 564b5b6..ebbef85 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/dmaengine.h>
-#include <linux/fsl/mxs-dma.h>
 
 #include <sound/core.h>
 #include <sound/initval.h>
 
 #include "mxs-pcm.h"
 
-struct mxs_pcm_dma_data {
-       struct mxs_dma_data dma_data;
-       struct mxs_pcm_dma_params *dma_params;
-};
-
 static struct snd_pcm_hardware snd_mxs_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
@@ -66,8 +60,7 @@ static struct snd_pcm_hardware snd_mxs_hardware = {
 
 static bool filter(struct dma_chan *chan, void *param)
 {
-       struct mxs_pcm_dma_data *pcm_dma_data = param;
-       struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params;
+       struct mxs_pcm_dma_params *dma_params = param;
 
        if (!mxs_dma_is_apbx(chan))
                return false;
@@ -75,7 +68,7 @@ static bool filter(struct dma_chan *chan, void *param)
        if (chan->chan_id != dma_params->chan_num)
                return false;
 
-       chan->private = &pcm_dma_data->dma_data;
+       chan->private = &dma_params->dma_data;
 
        return true;
 }
@@ -91,37 +84,11 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
 static int snd_mxs_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct mxs_pcm_dma_data *pcm_dma_data;
-       int ret;
-
-       pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
-       if (pcm_dma_data == NULL)
-               return -ENOMEM;
-
-       pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-       pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq;
-
-       ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data);
-       if (ret) {
-               kfree(pcm_dma_data);
-               return ret;
-       }
 
        snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
 
-       snd_dmaengine_pcm_set_data(substream, pcm_dma_data);
-
-       return 0;
-}
-
-static int snd_mxs_close(struct snd_pcm_substream *substream)
-{
-       struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
-
-       snd_dmaengine_pcm_close(substream);
-       kfree(pcm_dma_data);
-
-       return 0;
+       return snd_dmaengine_pcm_open(substream, filter,
+               snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
 }
 
 static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
@@ -137,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops mxs_pcm_ops = {
        .open           = snd_mxs_open,
-       .close          = snd_mxs_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = snd_mxs_pcm_hw_params,
        .trigger        = snd_dmaengine_pcm_trigger,
index 35ba2ca..3aa918f 100644 (file)
 #ifndef _MXS_PCM_H
 #define _MXS_PCM_H
 
+#include <linux/fsl/mxs-dma.h>
+
 struct mxs_pcm_dma_params {
-       int chan_irq;
+       struct mxs_dma_data dma_data;
        int chan_num;
 };
 
index 3a2aa1d..abf4ddf 100644 (file)
@@ -627,6 +627,10 @@ static struct snd_soc_dai_driver mxs_saif_dai = {
        .ops = &mxs_saif_dai_ops,
 };
 
+static const struct snd_soc_component_driver mxs_saif_component = {
+       .name           = "mxs-saif",
+};
+
 static irqreturn_t mxs_saif_irq(int irq, void *dev_id)
 {
        struct mxs_saif *saif = dev_id;
@@ -753,9 +757,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
-       if (saif->dma_param.chan_irq < 0) {
-               ret = saif->dma_param.chan_irq;
+       saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
+       if (saif->dma_param.dma_data.chan_irq < 0) {
+               ret = saif->dma_param.dma_data.chan_irq;
                dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
                        ret);
                return ret;
@@ -763,7 +767,8 @@ static int mxs_saif_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, saif);
 
-       ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &mxs_saif_component,
+                                        &mxs_saif_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                return ret;
@@ -778,7 +783,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
        return 0;
 
 failed_pdev_alloc:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return ret;
 }
@@ -786,7 +791,7 @@ failed_pdev_alloc:
 static int mxs_saif_remove(struct platform_device *pdev)
 {
        mxs_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
index 0418467..fe3285c 100644 (file)
@@ -314,6 +314,10 @@ static struct snd_soc_dai_driver nuc900_ac97_dai = {
        .ops = &nuc900_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver nuc900_ac97_component = {
+       .name           = "nuc900-ac97",
+};
+
 static int nuc900_ac97_drvprobe(struct platform_device *pdev)
 {
        struct nuc900_audio *nuc900_audio;
@@ -361,7 +365,8 @@ static int nuc900_ac97_drvprobe(struct platform_device *pdev)
 
        nuc900_ac97_data = nuc900_audio;
 
-       ret = snd_soc_register_dai(&pdev->dev, &nuc900_ac97_dai);
+       ret = snd_soc_register_component(&pdev->dev, &nuc900_ac97_component,
+                                        &nuc900_ac97_dai, 1);
        if (ret)
                goto out3;
 
@@ -384,7 +389,7 @@ out0:
 
 static int nuc900_ac97_drvremove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(nuc900_ac97_data->clk);
        iounmap(nuc900_ac97_data->mmio);
index c1900b2..994dcf3 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #include "../codecs/tlv320aic23.h"
 
index 2600447..6294464 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 #include "../codecs/cx20442.h"
 
 
index 285c836..eb68c7d 100644 (file)
@@ -1018,9 +1018,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
                return -ENODEV;
        }
        /* RX DMA request number, and port address configuration */
-       mcbsp->dma_data[1].name = "Audio Capture";
-       mcbsp->dma_data[1].dma_req = res->start;
-       mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+       mcbsp->dma_req[1] = res->start;
+       mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
+       mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
+       mcbsp->dma_data[1].maxburst = 4;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
        if (!res) {
@@ -1028,9 +1029,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
                return -ENODEV;
        }
        /* TX DMA request number, and port address configuration */
-       mcbsp->dma_data[0].name = "Audio Playback";
-       mcbsp->dma_data[0].dma_req = res->start;
-       mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
+       mcbsp->dma_req[0] = res->start;
+       mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
+       mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
+       mcbsp->dma_data[0].maxburst = 4;
 
        mcbsp->fclk = clk_get(&pdev->dev, "fck");
        if (IS_ERR(mcbsp->fclk)) {
index f93e0b0..96d1b08 100644 (file)
 #ifndef __ASOC_MCBSP_H
 #define __ASOC_MCBSP_H
 
-#include "omap-pcm.h"
-
 #ifdef CONFIG_ARCH_OMAP1
 #define mcbsp_omap1()  1
 #else
 #define mcbsp_omap1()  0
 #endif
 
+#include <sound/dmaengine_pcm.h>
+
 /* McBSP register numbers. Register address offset = num * reg_step */
 enum {
        /* Common registers */
@@ -312,7 +312,8 @@ struct omap_mcbsp {
        struct omap_mcbsp_platform_data *pdata;
        struct omap_mcbsp_st_data *st_data;
        struct omap_mcbsp_reg_cfg cfg_regs;
-       struct omap_pcm_dma_data dma_data[2];
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       unsigned int dma_req[2];
        int dma_op_mode;
        u16 max_tx_thres;
        u16 max_rx_thres;
index ee7cd53..5e8d640 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define N810_HEADSET_AMP_GPIO  10
 #define N810_SPEAKER_AMP_GPIO  101
index e7d93fa..70cd5c7 100644 (file)
@@ -34,7 +34,6 @@
 
 #include "omap-dmic.h"
 #include "omap-mcpdm.h"
-#include "omap-pcm.h"
 #include "../codecs/twl6040.h"
 
 struct abe_twl6040 {
index ba49ccd..2ad0370 100644 (file)
@@ -39,8 +39,8 @@
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
-#include "omap-pcm.h"
 #include "omap-dmic.h"
 
 struct omap_dmic {
@@ -55,13 +55,9 @@ struct omap_dmic {
        u32 ch_enabled;
        bool active;
        struct mutex mutex;
-};
 
-/*
- * Stream DMA parameters
- */
-static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
-       .name           = "DMIC capture",
+       struct snd_dmaengine_dai_dma_data dma_data;
+       unsigned int dma_req;
 };
 
 static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
@@ -118,7 +114,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
 
        mutex_unlock(&dmic->mutex);
 
-       snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
+       snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
        return ret;
 }
 
@@ -203,7 +199,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
                                    struct snd_soc_dai *dai)
 {
        struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
-       struct omap_pcm_dma_data *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
        int channels;
 
        dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
@@ -230,7 +226,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
 
        /* packet size is threshold * channels */
        dma_data = snd_soc_dai_get_dma_data(dai, substream);
-       dma_data->packet_size = dmic->threshold * channels;
+       dma_data->maxburst = dmic->threshold * channels;
 
        return 0;
 }
@@ -448,6 +444,10 @@ static struct snd_soc_dai_driver omap_dmic_dai = {
        .ops = &omap_dmic_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_dmic_component = {
+       .name           = "omap-dmic",
+};
+
 static int asoc_dmic_probe(struct platform_device *pdev)
 {
        struct omap_dmic *dmic;
@@ -476,7 +476,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
                ret = -ENODEV;
                goto err_put_clk;
        }
-       omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG;
+       dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
 
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!res) {
@@ -484,7 +484,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
                ret = -ENODEV;
                goto err_put_clk;
        }
-       omap_dmic_dai_dma_params.dma_req = res->start;
+
+       dmic->dma_req = res->start;
+       dmic->dma_data.filter_data = &dmic->dma_req;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
        if (!res) {
@@ -493,21 +495,12 @@ static int asoc_dmic_probe(struct platform_device *pdev)
                goto err_put_clk;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), pdev->name)) {
-               dev_err(dmic->dev, "memory region already claimed\n");
-               ret = -ENODEV;
-               goto err_put_clk;
-       }
-
-       dmic->io_base = devm_ioremap(&pdev->dev, res->start,
-                                    resource_size(res));
-       if (!dmic->io_base) {
-               ret = -ENOMEM;
-               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_dai(&pdev->dev, &omap_dmic_dai);
+       ret = snd_soc_register_component(&pdev->dev, &omap_dmic_component,
+                                        &omap_dmic_dai, 1);
        if (ret)
                goto err_put_clk;
 
@@ -522,7 +515,7 @@ static int asoc_dmic_remove(struct platform_device *pdev)
 {
        struct omap_dmic *dmic = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        clk_put(dmic->fclk);
 
        return 0;
index 32fa840..ced3b88 100644 (file)
 #include <sound/soc.h>
 #include <sound/asound.h>
 #include <sound/asoundef.h>
+#include <sound/dmaengine_pcm.h>
 #include <video/omapdss.h>
 
-#include "omap-pcm.h"
 #include "omap-hdmi.h"
 
 #define DRV_NAME "omap-hdmi-audio-dai"
 
 struct hdmi_priv {
-       struct omap_pcm_dma_data dma_params;
+       struct snd_dmaengine_dai_dma_data dma_data;
+       unsigned int dma_req;
        struct omap_dss_audio dss_audio;
        struct snd_aes_iec958 iec;
        struct snd_cea_861_aud_if cea;
@@ -68,7 +69,7 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
                return -ENODEV;
        }
 
-       snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params);
+       snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
 
        return 0;
 }
@@ -88,25 +89,20 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
        struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
        struct snd_aes_iec958 *iec = &priv->iec;
        struct snd_cea_861_aud_if *cea = &priv->cea;
-       struct omap_pcm_dma_data *dma_data;
        int err = 0;
 
-       dma_data = snd_soc_dai_get_dma_data(dai, substream);
-
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
-               dma_data->packet_size = 16;
+               priv->dma_data.maxburst = 16;
                break;
        case SNDRV_PCM_FORMAT_S24_LE:
-               dma_data->packet_size = 32;
+               priv->dma_data.maxburst = 32;
                break;
        default:
                dev_err(dai->dev, "format not supported!\n");
                return -EINVAL;
        }
 
-       dma_data->data_type = 32;
-
        /*
         * fill the IEC-60958 channel status word
         */
@@ -264,6 +260,10 @@ static struct snd_soc_dai_driver omap_hdmi_dai = {
        .ops = &omap_hdmi_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_hdmi_component = {
+       .name           = DRV_NAME,
+};
+
 static int omap_hdmi_probe(struct platform_device *pdev)
 {
        int ret;
@@ -283,8 +283,7 @@ static int omap_hdmi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       hdmi_data->dma_params.port_addr =  hdmi_rsrc->start
-               + OMAP_HDMI_AUDIO_DMA_PORT;
+       hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
 
        hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!hdmi_rsrc) {
@@ -292,8 +291,9 @@ static int omap_hdmi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       hdmi_data->dma_params.dma_req =  hdmi_rsrc->start;
-       hdmi_data->dma_params.name = "HDMI playback";
+       hdmi_data->dma_req = hdmi_rsrc->start;
+       hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
+       hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
        /*
         * TODO: We assume that there is only one DSS HDMI device. Future
@@ -321,7 +321,8 @@ static int omap_hdmi_probe(struct platform_device *pdev)
        }
 
        dev_set_drvdata(&pdev->dev, hdmi_data);
-       ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai);
+       ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
+                                        &omap_hdmi_dai, 1);
 
        return ret;
 }
@@ -330,7 +331,7 @@ static int omap_hdmi_remove(struct platform_device *pdev)
 {
        struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (hdmi_data == NULL) {
                dev_err(&pdev->dev, "cannot obtain HDMi data\n");
index 8d2defd..eadbfb6 100644 (file)
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 #include "mcbsp.h"
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define OMAP_MCBSP_RATES       (SNDRV_PCM_RATE_8000_96000)
 
@@ -62,24 +62,22 @@ enum {
  * Stream DMA parameters. DMA request line and port address are set runtime
  * since they are different between OMAP1 and later OMAPs
  */
-static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
+static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
+               unsigned int packet_size)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
-       struct omap_pcm_dma_data *dma_data;
        int words;
 
-       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
        /*
         * Configure McBSP threshold based on either:
         * packet_size, when the sDMA is in packet mode, or based on the
         * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
         * for mono streams.
         */
-       if (dma_data->packet_size)
-               words = dma_data->packet_size;
+       if (packet_size)
+               words = packet_size;
        else
                words = 1;
 
@@ -226,7 +224,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
 {
        struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
        struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
-       struct omap_pcm_dma_data *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
        int wlen, channels, wpf;
        int pkt_size = 0;
        unsigned int format, div, framesize, master;
@@ -245,7 +243,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
        if (mcbsp->pdata->buffer_size) {
-               dma_data->set_threshold = omap_mcbsp_set_threshold;
                if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
                        int period_words, max_thrsh;
                        int divider = 0;
@@ -276,9 +273,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
                        /* Use packet mode for non mono streams */
                        pkt_size = channels;
                }
+               omap_mcbsp_set_threshold(substream, pkt_size);
        }
 
-       dma_data->packet_size = pkt_size;
+       dma_data->maxburst = pkt_size;
 
        if (mcbsp->configured) {
                /* McBSP already configured by another stream */
@@ -586,6 +584,10 @@ static struct snd_soc_dai_driver omap_mcbsp_dai = {
        .ops = &mcbsp_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcbsp_component = {
+       .name           = "omap-mcbsp",
+};
+
 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_info *uinfo)
 {
@@ -793,7 +795,8 @@ static int asoc_mcbsp_probe(struct platform_device *pdev)
 
        ret = omap_mcbsp_init(pdev);
        if (!ret)
-               return snd_soc_register_dai(&pdev->dev, &omap_mcbsp_dai);
+               return snd_soc_register_component(&pdev->dev, &omap_mcbsp_component,
+                                                 &omap_mcbsp_dai, 1);
 
        return ret;
 }
@@ -802,7 +805,7 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
 {
        struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        if (mcbsp->pdata->ops && mcbsp->pdata->ops->free)
                mcbsp->pdata->ops->free(mcbsp->id);
index 5ca11bd..eb05c7e 100644 (file)
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "omap-mcpdm.h"
-#include "omap-pcm.h"
 
-#define OMAP44XX_MCPDM_L3_BASE         0x49032000
+struct mcpdm_link_config {
+       u32 link_mask; /* channel mask for the direction */
+       u32 threshold; /* FIFO threshold */
+};
 
 struct omap_mcpdm {
        struct device *dev;
@@ -53,29 +56,22 @@ struct omap_mcpdm {
 
        struct mutex mutex;
 
-       /* channel data */
-       u32 dn_channels;
-       u32 up_channels;
-
-       /* McPDM FIFO thresholds */
-       u32 dn_threshold;
-       u32 up_threshold;
+       /* Playback/Capture configuration */
+       struct mcpdm_link_config config[2];
 
        /* McPDM dn offsets for rx1, and 2 channels */
        u32 dn_rx_offset;
+
+       /* McPDM needs to be restarted due to runtime reconfiguration */
+       bool restart;
+
+       struct snd_dmaengine_dai_dma_data dma_data[2];
+       unsigned int dma_req[2];
 };
 
 /*
  * Stream DMA parameters
  */
-static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
-       {
-               .name = "Audio playback",
-       },
-       {
-               .name = "Audio capture",
-       },
-};
 
 static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
 {
@@ -130,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
 static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
 {
        u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+       u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
 
        ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
-       ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
+       ctrl |= link_mask;
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
        ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -148,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
 static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
 {
        u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
+       u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
 
        ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
-       ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
+       ctrl &= ~(link_mask);
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
 
        ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -188,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
                omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
        }
 
-       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
-       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
+                        mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
+       omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
+                        mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
 
        omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
                        MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
@@ -267,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
        mutex_unlock(&mcpdm->mutex);
 
        snd_soc_dai_set_dma_data(dai, substream,
-                                &omap_mcpdm_dai_dma_params[substream->stream]);
+                                &mcpdm->dma_data[substream->stream]);
 
        return 0;
 }
@@ -283,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
                if (omap_mcpdm_active(mcpdm)) {
                        omap_mcpdm_stop(mcpdm);
                        omap_mcpdm_close_streams(mcpdm);
+                       mcpdm->config[0].link_mask = 0;
+                       mcpdm->config[1].link_mask = 0;
                }
        }
 
@@ -295,7 +297,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 {
        struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
        int stream = substream->stream;
-       struct omap_pcm_dma_data *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
+       u32 threshold;
        int channels;
        int link_mask = 0;
 
@@ -325,16 +328,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
 
        dma_data = snd_soc_dai_get_dma_data(dai, substream);
 
+       threshold = mcpdm->config[stream].threshold;
        /* Configure McPDM channels, and DMA packet size */
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               mcpdm->dn_channels = link_mask << 3;
-               dma_data->packet_size =
-                       (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
+               link_mask <<= 3;
+
+               /* If capture is not running assume a stereo stream to come */
+               if (!mcpdm->config[!stream].link_mask)
+                       mcpdm->config[!stream].link_mask = 0x3;
+
+               dma_data->maxburst =
+                               (MCPDM_DN_THRES_MAX - threshold) * channels;
        } else {
-               mcpdm->up_channels = link_mask << 0;
-               dma_data->packet_size = mcpdm->up_threshold * channels;
+               /* If playback is not running assume a stereo stream to come */
+               if (!mcpdm->config[!stream].link_mask)
+                       mcpdm->config[!stream].link_mask = (0x3 << 3);
+
+               dma_data->maxburst = threshold * channels;
        }
 
+       /* Check if we need to restart McPDM with this stream */
+       if (mcpdm->config[stream].link_mask &&
+           mcpdm->config[stream].link_mask != link_mask)
+               mcpdm->restart = true;
+
+       mcpdm->config[stream].link_mask = link_mask;
+
        return 0;
 }
 
@@ -346,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
        if (!omap_mcpdm_active(mcpdm)) {
                omap_mcpdm_start(mcpdm);
                omap_mcpdm_reg_dump(mcpdm);
+       } else if (mcpdm->restart) {
+               omap_mcpdm_stop(mcpdm);
+               omap_mcpdm_start(mcpdm);
+               mcpdm->restart = false;
+               omap_mcpdm_reg_dump(mcpdm);
        }
 
        return 0;
@@ -369,7 +393,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
        pm_runtime_get_sync(mcpdm->dev);
        omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
 
-       ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
+       ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
                                0, "McPDM", (void *)mcpdm);
 
        pm_runtime_put_sync(mcpdm->dev);
@@ -380,8 +404,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
        }
 
        /* Configure McPDM threshold values */
-       mcpdm->dn_threshold = 2;
-       mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
+       mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
+       mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
+                                                       MCPDM_UP_THRES_MAX - 3;
        return ret;
 }
 
@@ -389,7 +414,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
 {
        struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
 
-       free_irq(mcpdm->irq, (void *)mcpdm);
        pm_runtime_disable(mcpdm->dev);
 
        return 0;
@@ -420,6 +444,10 @@ static struct snd_soc_dai_driver omap_mcpdm_dai = {
        .ops = &omap_mcpdm_dai_ops,
 };
 
+static const struct snd_soc_component_driver omap_mcpdm_component = {
+       .name           = "omap-mcpdm",
+};
+
 void omap_mcpdm_configure_dn_offsets(struct snd_soc_pcm_runtime *rtd,
                                    u8 rx1, u8 rx2)
 {
@@ -446,33 +474,30 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
        if (res == NULL)
                return -ENOMEM;
 
-       omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
-       omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
+       mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
+       mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
        if (!res)
                return -ENODEV;
 
-       omap_mcpdm_dai_dma_params[0].dma_req = res->start;
+       mcpdm->dma_req[0] = res->start;
+       mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
 
        res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
        if (!res)
                return -ENODEV;
 
-       omap_mcpdm_dai_dma_params[1].dma_req = res->start;
+       mcpdm->dma_req[1] = res->start;
+       mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
        if (res == NULL)
                return -ENOMEM;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), "McPDM"))
-               return -EBUSY;
-
-       mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
-                                     resource_size(res));
-       if (!mcpdm->io_base)
-               return -ENOMEM;
+       mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mcpdm->io_base))
+               return PTR_ERR(mcpdm->io_base);
 
        mcpdm->irq = platform_get_irq(pdev, 0);
        if (mcpdm->irq < 0)
@@ -480,12 +505,13 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
 
        mcpdm->dev = &pdev->dev;
 
-       return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
+       return snd_soc_register_component(&pdev->dev, &omap_mcpdm_component,
+                                         &omap_mcpdm_dai, 1);
 }
 
 static int asoc_mcpdm_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index c722c2e..c8e272f 100644 (file)
@@ -32,8 +32,6 @@
 #include <sound/dmaengine_pcm.h>
 #include <sound/soc.h>
 
-#include "omap-pcm.h"
-
 #ifdef CONFIG_ARCH_OMAP1
 #define pcm_omap1510() cpu_is_omap1510()
 #else
@@ -56,25 +54,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
        .buffer_bytes_max       = 128 * 1024,
 };
 
-static int omap_pcm_get_dma_buswidth(int num_bits)
-{
-       int buswidth;
-
-       switch (num_bits) {
-       case 16:
-               buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
-               break;
-       case 32:
-               buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
-               break;
-       default:
-               buswidth = -EINVAL;
-               break;
-       }
-       return buswidth;
-}
-
-
 /* this may get called several times by oss emulation */
 static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
                              struct snd_pcm_hw_params *params)
@@ -105,20 +84,9 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
        if (err)
                return err;
 
-       /* Override the *_dma addr_width if requested by the DAI driver */
-       if (dma_data->data_type) {
-               int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
-
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-                       config.dst_addr_width = buswidth;
-               else
-                       config.src_addr_width = buswidth;
-       }
-
-       config.src_addr = dma_data->port_addr;
-       config.dst_addr = dma_data->port_addr;
-       config.src_maxburst = dma_data->packet_size;
-       config.dst_maxburst = dma_data->packet_size;
+       snd_dmaengine_pcm_set_config_from_dai_data(substream,
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+                       &config);
 
        return dmaengine_slave_config(chan, &config);
 }
@@ -129,37 +97,6 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct omap_pcm_dma_data *dma_data;
-       int ret = 0;
-
-       dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               /* Configure McBSP internal buffer usage */
-               if (dma_data->set_threshold)
-                       dma_data->set_threshold(substream);
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       if (ret == 0)
-               ret = snd_dmaengine_pcm_trigger(substream, cmd);
-
-       return ret;
-}
-
 static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 {
        snd_pcm_uframes_t offset;
@@ -175,20 +112,14 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
 static int omap_pcm_open(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct omap_pcm_dma_data *dma_data;
+       struct snd_dmaengine_dai_dma_data *dma_data;
 
        snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
 
        dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
        return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
-                                     &dma_data->dma_req);
-}
-
-static int omap_pcm_close(struct snd_pcm_substream *substream)
-{
-       snd_dmaengine_pcm_close(substream);
-       return 0;
+                                     dma_data->filter_data);
 }
 
 static int omap_pcm_mmap(struct snd_pcm_substream *substream,
@@ -204,11 +135,11 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops omap_pcm_ops = {
        .open           = omap_pcm_open,
-       .close          = omap_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = omap_pcm_hw_params,
        .hw_free        = omap_pcm_hw_free,
-       .trigger        = omap_pcm_trigger,
+       .trigger        = snd_dmaengine_pcm_trigger,
        .pointer        = omap_pcm_pointer,
        .mmap           = omap_pcm_mmap,
 };
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
deleted file mode 100644 (file)
index cabe74c..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * omap-pcm.h
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
- *          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_PCM_H__
-#define __OMAP_PCM_H__
-
-struct snd_pcm_substream;
-
-struct omap_pcm_dma_data {
-       char            *name;          /* stream identifier */
-       int             dma_req;        /* DMA request line */
-       unsigned long   port_addr;      /* transmit/receive register */
-       void (*set_threshold)(struct snd_pcm_substream *substream);
-       int             data_type;      /* 8, 16, 32 (bits) or 0 to let omap-pcm
-                                        * to decide the sDMA data type */
-       int             packet_size;    /* packet size only in PACKET mode */
-};
-
-#endif
index fd98509..2a9324f 100644 (file)
@@ -43,7 +43,6 @@
 #include <sound/jack.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 struct omap_twl4030 {
        int jack_detect;        /* board can detect jack events */
index 805512f..cf604a2 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define OMAP3_PANDORA_DAC_POWER_GPIO   118
 #define OMAP3_PANDORA_AMP_POWER_GPIO   14
@@ -80,12 +79,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
 static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *k, int event)
 {
+       int ret;
+
        /*
         * The PCM1773 DAC datasheet requires 1ms delay between switching
         * VCC power on/off and /PD pin high/low
         */
        if (SND_SOC_DAPM_EVENT_ON(event)) {
-               regulator_enable(omap3pandora_dac_reg);
+               ret = regulator_enable(omap3pandora_dac_reg);
+               if (ret) {
+                       dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
+                       return ret;
+               }
                mdelay(1);
                gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
        } else {
index 06ef8d6..d03e57d 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/platform_data/asoc-ti-mcbsp.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 #include "../codecs/tlv320aic23.h"
 
 #define CODEC_CLOCK    12000000
index 3cd5257..249cd23 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/mach-types.h>
 
 #include "omap-mcbsp.h"
-#include "omap-pcm.h"
 
 #define RX51_TVOUT_SEL_GPIO            40
 #define RX51_JACK_DETECT_GPIO          177
index 190eb0b..6c39802 100644 (file)
@@ -118,9 +118,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct platform_device *pdev = to_platform_device(rtd->platform->dev);
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct mmp_dma_data *dma_data;
+       struct mmp_dma_data dma_data;
        struct resource *r;
-       int ret;
 
        r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
        if (!r)
@@ -128,33 +127,11 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
 
        snd_soc_set_runtime_hwparams(substream,
                                &mmp_pcm_hardware[substream->stream]);
-       dma_data = devm_kzalloc(&pdev->dev,
-                       sizeof(struct mmp_dma_data), GFP_KERNEL);
-       if (dma_data == NULL)
-               return -ENOMEM;
 
-       dma_data->dma_res = r;
-       dma_data->ssp_id = cpu_dai->id;
+       dma_data.dma_res = r;
+       dma_data.ssp_id = cpu_dai->id;
 
-       ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
-       if (ret) {
-               devm_kfree(&pdev->dev, dma_data);
-               return ret;
-       }
-
-       snd_dmaengine_pcm_set_data(substream, dma_data);
-       return 0;
-}
-
-static int mmp_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct platform_device *pdev = to_platform_device(rtd->platform->dev);
-
-       snd_dmaengine_pcm_close(substream);
-       devm_kfree(&pdev->dev, dma_data);
-       return 0;
+       return snd_dmaengine_pcm_open(substream, filter, &dma_data);
 }
 
 static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
@@ -171,7 +148,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
 
 struct snd_pcm_ops mmp_pcm_ops = {
        .open           = mmp_pcm_open,
-       .close          = mmp_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = mmp_pcm_hw_params,
        .trigger        = snd_dmaengine_pcm_trigger,
index 9140c4a..a647799 100644 (file)
@@ -405,6 +405,10 @@ struct snd_soc_dai_driver mmp_sspa_dai = {
        .ops = &mmp_sspa_dai_ops,
 };
 
+static const struct snd_soc_component_driver mmp_sspa_component = {
+       .name           = "mmp-sspa",
+};
+
 static int asoc_mmp_sspa_probe(struct platform_device *pdev)
 {
        struct sspa_priv *priv;
@@ -450,7 +454,8 @@ static int asoc_mmp_sspa_probe(struct platform_device *pdev)
        priv->dai_fmt = (unsigned int) -1;
        platform_set_drvdata(pdev, priv);
 
-       return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai);
+       return snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
+                                         &mmp_sspa_dai, 1);
 }
 
 static int asoc_mmp_sspa_remove(struct platform_device *pdev)
@@ -460,7 +465,7 @@ static int asoc_mmp_sspa_remove(struct platform_device *pdev)
        clk_disable(priv->audio_clk);
        clk_put(priv->audio_clk);
        clk_put(priv->sysclk);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index d3eb0c2..6f4dd75 100644 (file)
@@ -794,14 +794,19 @@ static struct snd_soc_dai_driver pxa_ssp_dai = {
                .ops = &pxa_ssp_dai_ops,
 };
 
+static const struct snd_soc_component_driver pxa_ssp_component = {
+       .name           = "pxa-ssp",
+};
+
 static int asoc_ssp_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &pxa_ssp_dai);
+       return snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
+                                         &pxa_ssp_dai, 1);
 }
 
 static int asoc_ssp_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 4b0a009..57ea8e6 100644 (file)
@@ -47,6 +47,7 @@ struct snd_ac97_bus_ops soc_ac97_ops = {
        .warm_reset     = pxa2xx_ac97_warm_reset,
        .reset  = pxa2xx_ac97_cold_reset,
 };
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
 
 static struct pxa2xx_pcm_dma_params pxa2xx_ac97_pcm_stereo_out = {
        .name                   = "AC97 PCM Stereo out",
@@ -232,7 +233,9 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
 },
 };
 
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
+static const struct snd_soc_component_driver pxa_ac97_component = {
+       .name           = "pxa-ac97",
+};
 
 static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
 {
@@ -245,13 +248,13 @@ static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
         * driver to do interesting things with the clocking to get us up
         * and running.
         */
-       return snd_soc_register_dais(&pdev->dev, pxa_ac97_dai_driver,
-                       ARRAY_SIZE(pxa_ac97_dai_driver));
+       return snd_soc_register_component(&pdev->dev, &pxa_ac97_component,
+                                         pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver));
 }
 
 static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(pxa_ac97_dai_driver));
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 6b1a06f..f7ca716 100644 (file)
@@ -360,14 +360,19 @@ static struct snd_soc_dai_driver pxa_i2s_dai = {
        .symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver pxa_i2s_component = {
+       .name           = "pxa-i2s",
+};
+
 static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dai(&pdev->dev, &pxa_i2s_dai);
+       return snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
+                                         &pxa_i2s_dai, 1);
 }
 
 static int pxa2xx_i2s_drv_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index fee4d47..73bb99f 100644 (file)
@@ -436,6 +436,10 @@ static struct snd_soc_dai_driver s6000_i2s_dai = {
        .ops = &s6000_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s6000_i2s_component = {
+       .name           = "s6000-i2s",
+};
+
 static int s6000_i2s_probe(struct platform_device *pdev)
 {
        struct s6000_i2s_dev *dev;
@@ -543,7 +547,8 @@ static int s6000_i2s_probe(struct platform_device *pdev)
                         S6_I2S_INT_UNDERRUN |
                         S6_I2S_INT_OVERRUN);
 
-       ret = snd_soc_register_dai(&pdev->dev, &s6000_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &s6000_i2s_component,
+                                        &s6000_i2s_dai, 1);
        if (ret)
                goto err_release_dev;
 
@@ -572,7 +577,7 @@ static void s6000_i2s_remove(struct platform_device *pdev)
        struct resource *region;
        void __iomem *mmio = dev->scbbase;
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        s6000_i2s_stop_channel(dev, 0);
        s6000_i2s_stop_channel(dev, 1);
index 90e7e66..475fb0d 100644 (file)
@@ -35,11 +35,10 @@ config SND_SAMSUNG_I2S
        tristate
 
 config SND_SOC_SAMSUNG_NEO1973_WM8753
-       tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)"
-       depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02)
+       tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)"
+       depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02
        select SND_S3C24XX_I2S
        select SND_SOC_WM8753
-       select SND_SOC_LM4857 if MACH_NEO1973_GTA01
        select SND_SOC_DFBMCS320
        help
          Say Y here to enable audio support for the Openmoko Neo1973
index 0df3c56..cb88ead 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/soc.h>
 
 #include <mach/dma.h>
-#include <plat/regs-ac97.h>
+#include "regs-ac97.h"
 #include <linux/platform_data/asoc-s3c.h>
 
 #include "dma.h"
@@ -370,6 +370,10 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
        },
 };
 
+static const struct snd_soc_component_driver s3c_ac97_component = {
+       .name           = "s3c-ac97",
+};
+
 static int s3c_ac97_probe(struct platform_device *pdev)
 {
        struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res;
@@ -457,8 +461,8 @@ static int s3c_ac97_probe(struct platform_device *pdev)
                goto err4;
        }
 
-       ret = snd_soc_register_dais(&pdev->dev, s3c_ac97_dai,
-                       ARRAY_SIZE(s3c_ac97_dai));
+       ret = snd_soc_register_component(&pdev->dev, &s3c_ac97_component,
+                                        s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai));
        if (ret)
                goto err5;
 
@@ -470,7 +474,7 @@ static int s3c_ac97_probe(struct platform_device *pdev)
 
        return 0;
 err6:
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+       snd_soc_unregister_component(&pdev->dev);
 err5:
        free_irq(irq_res->start, NULL);
 err4:
@@ -490,7 +494,7 @@ static int s3c_ac97_remove(struct platform_device *pdev)
        struct resource *mem_res, *irq_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(s3c_ac97_dai));
+       snd_soc_unregister_component(&pdev->dev);
 
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq_res)
index d37ede5..415ad81 100644 (file)
@@ -218,6 +218,10 @@ static struct snd_soc_dai_driver voice_dai = {
                .formats = SNDRV_PCM_FMTBIT_S16_LE,},
 };
 
+static const struct snd_soc_component_driver voice_component = {
+       .name           = "goni-voice",
+};
+
 static struct snd_soc_ops goni_voice_ops = {
        .hw_params = goni_voice_hw_params,
 };
@@ -270,7 +274,8 @@ static int __init goni_init(void)
                return -ENOMEM;
 
        /* register voice DAI here */
-       ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
+       ret = snd_soc_register_component(&goni_snd_device->dev, &voice_component,
+                                        &voice_dai, 1);
        if (ret) {
                platform_device_put(goni_snd_device);
                return ret;
@@ -280,7 +285,7 @@ static int __init goni_init(void)
        ret = platform_device_add(goni_snd_device);
 
        if (ret) {
-               snd_soc_unregister_dai(&goni_snd_device->dev);
+               snd_soc_unregister_component(&goni_snd_device->dev);
                platform_device_put(goni_snd_device);
        }
 
@@ -289,7 +294,7 @@ static int __init goni_init(void)
 
 static void __exit goni_exit(void)
 {
-       snd_soc_unregister_dai(&goni_snd_device->dev);
+       snd_soc_unregister_component(&goni_snd_device->dev);
        platform_device_unregister(goni_snd_device);
 }
 
index 15a3817..fa91376 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 #include <asm/mach-types.h>
 
 #include "s3c24xx-i2s.h"
index d7231e3..82ebb1a 100644 (file)
@@ -963,6 +963,10 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
        .delay = i2s_delay,
 };
 
+static const struct snd_soc_component_driver samsung_i2s_component = {
+       .name           = "samsung-i2s",
+};
+
 #define SAMSUNG_I2S_RATES      SNDRV_PCM_RATE_8000_96000
 
 #define SAMSUNG_I2S_FMTS       (SNDRV_PCM_FMTBIT_S8 | \
@@ -972,6 +976,7 @@ static const struct snd_soc_dai_ops samsung_i2s_dai_ops = {
 static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
 {
        struct i2s_dai *i2s;
+       int ret;
 
        i2s = devm_kzalloc(&pdev->dev, sizeof(struct i2s_dai), GFP_KERNEL);
        if (i2s == NULL)
@@ -996,15 +1001,17 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec)
                i2s->i2s_dai_drv.capture.channels_max = 2;
                i2s->i2s_dai_drv.capture.rates = SAMSUNG_I2S_RATES;
                i2s->i2s_dai_drv.capture.formats = SAMSUNG_I2S_FMTS;
+               dev_set_drvdata(&i2s->pdev->dev, i2s);
        } else {        /* Create a new platform_device for Secondary */
-               i2s->pdev = platform_device_register_resndata(NULL,
-                               "samsung-i2s-sec", -1, NULL, 0, NULL, 0);
+               i2s->pdev = platform_device_alloc("samsung-i2s-sec", -1);
                if (IS_ERR(i2s->pdev))
                        return NULL;
-       }
 
-       /* Pre-assign snd_soc_dai_set_drvdata */
-       dev_set_drvdata(&i2s->pdev->dev, i2s);
+               platform_set_drvdata(i2s->pdev, i2s);
+               ret = platform_device_add(i2s->pdev);
+               if (ret < 0)
+                       return NULL;
+       }
 
        return i2s;
 }
@@ -1107,8 +1114,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        if (samsung_dai_type == TYPE_SEC) {
                sec_dai = dev_get_drvdata(&pdev->dev);
-               snd_soc_register_dai(&sec_dai->pdev->dev,
-                       &sec_dai->i2s_dai_drv);
+               if (!sec_dai) {
+                       dev_err(&pdev->dev, "Unable to get drvdata\n");
+                       return -EFAULT;
+               }
+               snd_soc_register_component(&sec_dai->pdev->dev,
+                                          &samsung_i2s_component,
+                                          &sec_dai->i2s_dai_drv, 1);
                asoc_dma_platform_register(&pdev->dev);
                return 0;
        }
@@ -1237,7 +1249,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                }
        }
 
-       snd_soc_register_dai(&pri_dai->pdev->dev, &pri_dai->i2s_dai_drv);
+       snd_soc_register_component(&pri_dai->pdev->dev, &samsung_i2s_component,
+                                  &pri_dai->i2s_dai_drv, 1);
 
        pm_runtime_enable(&pdev->dev);
 
@@ -1276,7 +1289,7 @@ static int samsung_i2s_remove(struct platform_device *pdev)
        i2s->sec_dai = NULL;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        return 0;
 }
@@ -1291,7 +1304,7 @@ static struct platform_device_id samsung_i2s_driver_ids[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(platform, samsung-i2s-driver-ids);
+MODULE_DEVICE_TABLE(platform, samsung_i2s_driver_ids);
 
 #ifdef CONFIG_OF
 static struct samsung_i2s_dai_data samsung_i2s_dai_data_array[] = {
index a07950b..6e5fed3 100644 (file)
@@ -68,6 +68,8 @@ static struct idma_info {
        dma_addr_t      lp_tx_addr;
 } idma;
 
+static int idma_irq;
+
 static void idma_getpos(dma_addr_t *src)
 {
        *src = idma.lp_tx_addr +
@@ -305,7 +307,7 @@ static int idma_open(struct snd_pcm_substream *substream)
        if (prtd == NULL)
                return -ENOMEM;
 
-       ret = request_irq(IRQ_I2S0, iis_irq, 0, "i2s", prtd);
+       ret = request_irq(idma_irq, iis_irq, 0, "i2s", prtd);
        if (ret < 0) {
                pr_err("fail to claim i2s irq , ret = %d\n", ret);
                kfree(prtd);
@@ -324,7 +326,7 @@ static int idma_close(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct idma_ctrl *prtd = runtime->private_data;
 
-       free_irq(IRQ_I2S0, prtd);
+       free_irq(idma_irq, prtd);
 
        if (!prtd)
                pr_err("idma_close called with prtd == NULL\n");
@@ -409,6 +411,7 @@ void idma_reg_addr_init(void __iomem *regs, dma_addr_t addr)
        idma.regs = regs;
        idma.lp_tx_addr = addr;
 }
+EXPORT_SYMBOL_GPL(idma_reg_addr_init);
 
 static struct snd_soc_platform_driver asoc_idma_platform = {
        .ops = &idma_ops,
@@ -418,6 +421,10 @@ static struct snd_soc_platform_driver asoc_idma_platform = {
 
 static int asoc_idma_platform_probe(struct platform_device *pdev)
 {
+       idma_irq = platform_get_irq(pdev, 0);
+       if (idma_irq < 0)
+               return idma_irq;
+
        return snd_soc_register_platform(&pdev->dev, &asoc_idma_platform);
 }
 
index a301d8c..e591c38 100644 (file)
@@ -21,8 +21,7 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <plat/regs-iis.h>
-#include <mach/gta02.h>
+#include "regs-iis.h"
 
 #include "../codecs/wm8753.h"
 #include "s3c24xx-i2s.h"
index 13bab79..1566afe 100644 (file)
@@ -490,6 +490,10 @@ static struct snd_soc_dai_driver s3c_pcm_dai[] = {
        },
 };
 
+static const struct snd_soc_component_driver s3c_pcm_component = {
+       .name           = "s3c-pcm",
+};
+
 static int s3c_pcm_dev_probe(struct platform_device *pdev)
 {
        struct s3c_pcm_info *pcm;
@@ -583,7 +587,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       ret = snd_soc_register_dai(&pdev->dev, &s3c_pcm_dai[pdev->id]);
+       ret = snd_soc_register_component(&pdev->dev, &s3c_pcm_component,
+                                        &s3c_pcm_dai[pdev->id], 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret);
                goto err5;
@@ -598,7 +603,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev)
        return 0;
 
 err6:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 err5:
        clk_disable_unprepare(pcm->pclk);
        clk_put(pcm->pclk);
@@ -619,7 +624,7 @@ static int s3c_pcm_dev_remove(struct platform_device *pdev)
        struct resource *mem_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
 
index a5826ea..704460a 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 #include <asm/mach-types.h>
 
 #include "s3c24xx-i2s.h"
index 7a73380..20e98d1 100644 (file)
@@ -731,8 +731,9 @@ static int s3c2412_i2s_resume(struct snd_soc_dai *dai)
 #define s3c2412_i2s_resume  NULL
 #endif
 
-int s3c_i2sv2_register_dai(struct device *dev, int id,
-               struct snd_soc_dai_driver *drv)
+int s3c_i2sv2_register_component(struct device *dev, int id,
+                          struct snd_soc_component_driver *cmp_drv,
+                          struct snd_soc_dai_driver *dai_drv)
 {
        struct snd_soc_dai_ops *ops = drv->ops;
 
@@ -750,8 +751,8 @@ int s3c_i2sv2_register_dai(struct device *dev, int id,
        drv->suspend = s3c2412_i2s_suspend;
        drv->resume = s3c2412_i2s_resume;
 
-       return snd_soc_register_dai(dev, drv);
+       return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
 }
-EXPORT_SYMBOL_GPL(s3c_i2sv2_register_dai);
+EXPORT_SYMBOL_GPL(s3c_i2sv2_register_component);
 
 MODULE_LICENSE("GPL");
index f8297d9..90abab3 100644 (file)
@@ -92,7 +92,7 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
                           unsigned long base);
 
 /**
- * s3c_i2sv2_register_dai - register dai with soc core
+ * s3c_i2sv2_register_component - register component and dai with soc core
  * @dev: DAI device
  * @id: DAI ID
  * @drv: The driver structure to register
@@ -100,7 +100,8 @@ extern int s3c_i2sv2_probe(struct snd_soc_dai *dai,
  * Fill in any missing fields and then register the given dai with the
  * soc core.
  */
-extern int s3c_i2sv2_register_dai(struct device *dev, int id,
-               struct snd_soc_dai_driver *drv);
+extern int s3c_i2sv2_register_component(struct device *dev, int id,
+                                       struct snd_soc_component_driver *cmp_drv,
+                                       struct snd_soc_dai_driver *dai_drv);
 
 #endif /* __SND_SOC_S3C24XX_S3C_I2SV2_I2S_H */
index 2213377..47e2386 100644 (file)
@@ -160,11 +160,17 @@ static struct snd_soc_dai_driver s3c2412_i2s_dai = {
        .ops = &s3c2412_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s3c2412_i2s_component = {
+       .name           = "s3c2412-i2s",
+};
+
 static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
 
-       ret = s3c_i2sv2_register_dai(&pdev->dev, -1, &s3c2412_i2s_dai);
+       ret = s3c_i2sv2_register_component(&pdev->dev, -1,
+                                          &s3c2412_i2s_component,
+                                          &s3c2412_i2s_dai);
        if (ret) {
                pr_err("failed to register the dai\n");
                return ret;
@@ -178,14 +184,14 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return ret;
 }
 
 static int s3c2412_iis_dev_remove(struct platform_device *pdev)
 {
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 13f6dd1..8b34145 100644 (file)
@@ -24,7 +24,7 @@
 #include <sound/pcm_params.h>
 
 #include <mach/dma.h>
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 
 #include "dma.h"
 #include "s3c24xx-i2s.h"
@@ -465,11 +465,16 @@ static struct snd_soc_dai_driver s3c24xx_i2s_dai = {
        .ops = &s3c24xx_i2s_dai_ops,
 };
 
+static const struct snd_soc_component_driver s3c24xx_i2s_component = {
+       .name           = "s3c24xx-i2s",
+};
+
 static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 {
        int ret = 0;
 
-       ret = snd_soc_register_dai(&pdev->dev, &s3c24xx_i2s_dai);
+       ret = snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component,
+                                        &s3c24xx_i2s_dai, 1);
        if (ret) {
                pr_err("failed to register the dai\n");
                return ret;
@@ -483,14 +488,14 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return ret;
 }
 
 static int s3c24xx_iis_dev_remove(struct platform_device *pdev)
 {
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 333e1b7..1b7b52b 100644 (file)
@@ -18,7 +18,7 @@
 #include <sound/soc.h>
 #include <sound/s3c24xx_uda134x.h>
 
-#include <plat/regs-iis.h>
+#include "regs-iis.h"
 
 #include "s3c24xx-i2s.h"
 
index 5008e5b..2e5ebb2 100644 (file)
@@ -357,6 +357,10 @@ static struct snd_soc_dai_driver samsung_spdif_dai = {
        .resume = spdif_resume,
 };
 
+static const struct snd_soc_component_driver samsung_spdif_component = {
+       .name           = "samsung-spdif",
+};
+
 static int spdif_probe(struct platform_device *pdev)
 {
        struct s3c_audio_pdata *spdif_pdata;
@@ -424,7 +428,8 @@ static int spdif_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, spdif);
 
-       ret = snd_soc_register_dai(&pdev->dev, &samsung_spdif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &samsung_spdif_component,
+                                        &samsung_spdif_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "fail to register dai\n");
                goto err4;
@@ -445,7 +450,7 @@ static int spdif_probe(struct platform_device *pdev)
 
        return 0;
 err5:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 err4:
        iounmap(spdif->regs);
 err3:
@@ -466,7 +471,7 @@ static int spdif_remove(struct platform_device *pdev)
        struct resource *mem_res;
 
        asoc_dma_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        iounmap(spdif->regs);
 
index c724026..f830c41 100644 (file)
@@ -296,7 +296,6 @@ struct fsi_core {
 
 struct fsi_master {
        void __iomem *base;
-       int irq;
        struct fsi_priv fsia;
        struct fsi_priv fsib;
        const struct fsi_core *core;
@@ -1886,6 +1885,10 @@ static struct snd_soc_platform_driver fsi_soc_platform = {
        .pcm_free       = fsi_pcm_free,
 };
 
+static const struct snd_soc_component_driver fsi_soc_component = {
+       .name           = "fsi",
+};
+
 /*
  *             platform function
  */
@@ -2002,7 +2005,6 @@ static int fsi_probe(struct platform_device *pdev)
        }
 
        /* master setting */
-       master->irq             = irq;
        master->core            = core;
        spin_lock_init(&master->lock);
 
@@ -2046,10 +2048,10 @@ static int fsi_probe(struct platform_device *pdev)
                goto exit_fsib;
        }
 
-       ret = snd_soc_register_dais(&pdev->dev, fsi_soc_dai,
-                                   ARRAY_SIZE(fsi_soc_dai));
+       ret = snd_soc_register_component(&pdev->dev, &fsi_soc_component,
+                                   fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai));
        if (ret < 0) {
-               dev_err(&pdev->dev, "cannot snd dai register\n");
+               dev_err(&pdev->dev, "cannot snd component register\n");
                goto exit_snd_soc;
        }
 
@@ -2074,7 +2076,7 @@ static int fsi_remove(struct platform_device *pdev)
 
        pm_runtime_disable(&pdev->dev);
 
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(fsi_soc_dai));
+       snd_soc_unregister_component(&pdev->dev);
        snd_soc_unregister_platform(&pdev->dev);
 
        fsi_stream_remove(&master->fsia);
index 4cc2d64..af19f77 100644 (file)
@@ -310,15 +310,19 @@ static struct snd_soc_dai_driver sh4_hac_dai[] = {
 #endif
 };
 
+static const struct snd_soc_component_driver sh4_hac_component = {
+       .name           = "sh4-hac",
+};
+
 static int hac_soc_platform_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dais(&pdev->dev, sh4_hac_dai,
-                       ARRAY_SIZE(sh4_hac_dai));
+       return snd_soc_register_component(&pdev->dev, &sh4_hac_component,
+                                         sh4_hac_dai, ARRAY_SIZE(sh4_hac_dai));
 }
 
 static int hac_soc_platform_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_hac_dai));
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 8526e1e..5014a88 100644 (file)
@@ -153,7 +153,7 @@ static int migor_dai_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link migor_dai = {
        .name = "wm8978",
        .stream_name = "WM8978",
-       .cpu_dai_name = "siu-i2s-dai",
+       .cpu_dai_name = "siu-pcm-audio",
        .codec_dai_name = "wm8978-hifi",
        .platform_name = "siu-pcm-audio",
        .codec_name = "wm8978.0-001a",
index 34facdc..9dc24ff 100644 (file)
@@ -726,6 +726,10 @@ static struct snd_soc_dai_driver siu_i2s_dai = {
        .ops = &siu_dai_ops,
 };
 
+static const struct snd_soc_component_driver siu_i2s_component = {
+       .name           = "siu-i2s",
+};
+
 static int siu_probe(struct platform_device *pdev)
 {
        const struct firmware *fw_entry;
@@ -783,7 +787,8 @@ static int siu_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, info);
 
        /* register using ARRAY version so we can keep dai name */
-       ret = snd_soc_register_dais(&pdev->dev, &siu_i2s_dai, 1);
+       ret = snd_soc_register_component(&pdev->dev, &siu_i2s_component,
+                                        &siu_i2s_dai, 1);
        if (ret < 0)
                goto edaiinit;
 
@@ -796,7 +801,7 @@ static int siu_probe(struct platform_device *pdev)
        return ret;
 
 esocregp:
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 edaiinit:
        iounmap(info->reg);
 emapreg:
@@ -823,7 +828,7 @@ static int siu_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 
        snd_soc_unregister_platform(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        iounmap(info->reg);
        iounmap(info->yram);
index c8e73a7..e889405 100644 (file)
@@ -379,15 +379,19 @@ static struct snd_soc_dai_driver sh4_ssi_dai[] = {
 #endif
 };
 
+static const struct snd_soc_component_driver sh4_ssi_component = {
+       .name           = "sh4-ssi",
+};
+
 static int sh4_soc_dai_probe(struct platform_device *pdev)
 {
-       return snd_soc_register_dais(&pdev->dev, sh4_ssi_dai,
-                       ARRAY_SIZE(sh4_ssi_dai));
+       return snd_soc_register_component(&pdev->dev, &sh4_ssi_component,
+                                         sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai));
 }
 
 static int sh4_soc_dai_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sh4_ssi_dai));
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index b5b3db7..29093a3 100644 (file)
@@ -211,19 +211,27 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream,
        if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) {
                ret = platform->driver->compr_ops->set_params(cstream, params);
                if (ret < 0)
-                       goto out;
+                       goto err;
        }
 
        if (rtd->dai_link->compr_ops && rtd->dai_link->compr_ops->set_params) {
                ret = rtd->dai_link->compr_ops->set_params(cstream);
                if (ret < 0)
-                       goto out;
+                       goto err;
        }
 
        snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK,
                                SND_SOC_DAPM_STREAM_START);
 
-out:
+       /* cancel any delayed stream shutdown that is pending */
+       rtd->pop_wait = 0;
+       mutex_unlock(&rtd->pcm_mutex);
+
+       cancel_delayed_work_sync(&rtd->delayed_work);
+
+       return ret;
+
+err:
        mutex_unlock(&rtd->pcm_mutex);
        return ret;
 }
@@ -322,11 +330,38 @@ static int soc_compr_copy(struct snd_compr_stream *cstream,
        return ret;
 }
 
+static int sst_compr_set_metadata(struct snd_compr_stream *cstream,
+                               struct snd_compr_metadata *metadata)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata)
+               ret = platform->driver->compr_ops->set_metadata(cstream, metadata);
+
+       return ret;
+}
+
+static int sst_compr_get_metadata(struct snd_compr_stream *cstream,
+                               struct snd_compr_metadata *metadata)
+{
+       struct snd_soc_pcm_runtime *rtd = cstream->private_data;
+       struct snd_soc_platform *platform = rtd->platform;
+       int ret = 0;
+
+       if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata)
+               ret = platform->driver->compr_ops->get_metadata(cstream, metadata);
+
+       return ret;
+}
 /* ASoC Compress operations */
 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,
        .get_params     = soc_compr_get_params,
        .trigger        = soc_compr_trigger,
        .pointer        = soc_compr_pointer,
index 507d251..7bf21a1 100644 (file)
@@ -58,6 +58,7 @@ static DEFINE_MUTEX(client_mutex);
 static LIST_HEAD(dai_list);
 static LIST_HEAD(platform_list);
 static LIST_HEAD(codec_list);
+static LIST_HEAD(component_list);
 
 /*
  * This is a timeout to do a DAPM powerdown after a stream is closed().
@@ -2963,7 +2964,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
        val = val << shift;
 
        ret = snd_soc_update_bits_locked(codec, reg, val_mask, val);
-       if (ret != 0)
+       if (ret < 0)
                return ret;
 
        if (snd_soc_volsw_is_stereo(mc)) {
@@ -3740,7 +3741,7 @@ static inline char *fmt_multiple_name(struct device *dev,
  *
  * @dai: DAI to register
  */
-int snd_soc_register_dai(struct device *dev,
+static int snd_soc_register_dai(struct device *dev,
                struct snd_soc_dai_driver *dai_drv)
 {
        struct snd_soc_codec *codec;
@@ -3787,14 +3788,13 @@ int snd_soc_register_dai(struct device *dev,
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_dai);
 
 /**
  * snd_soc_unregister_dai - Unregister a DAI from the ASoC core
  *
  * @dai: DAI to unregister
  */
-void snd_soc_unregister_dai(struct device *dev)
+static void snd_soc_unregister_dai(struct device *dev)
 {
        struct snd_soc_dai *dai;
 
@@ -3813,7 +3813,6 @@ found:
        kfree(dai->name);
        kfree(dai);
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
 
 /**
  * snd_soc_register_dais - Register multiple DAIs with the ASoC core
@@ -3821,7 +3820,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  * @dai: Array of DAIs to register
  * @count: Number of DAIs
  */
-int snd_soc_register_dais(struct device *dev,
+static int snd_soc_register_dais(struct device *dev,
                struct snd_soc_dai_driver *dai_drv, size_t count)
 {
        struct snd_soc_codec *codec;
@@ -3885,7 +3884,6 @@ err:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(snd_soc_register_dais);
 
 /**
  * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core
@@ -3893,14 +3891,13 @@ EXPORT_SYMBOL_GPL(snd_soc_register_dais);
  * @dai: Array of DAIs to unregister
  * @count: Number of DAIs
  */
-void snd_soc_unregister_dais(struct device *dev, size_t count)
+static void snd_soc_unregister_dais(struct device *dev, size_t count)
 {
        int i;
 
        for (i = 0; i < count; i++)
                snd_soc_unregister_dai(dev);
 }
-EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
 
 /**
  * snd_soc_register_platform - Register a platform with the ASoC core
@@ -3908,7 +3905,7 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
  * @platform: platform to register
  */
 int snd_soc_register_platform(struct device *dev,
-               struct snd_soc_platform_driver *platform_drv)
+               const struct snd_soc_platform_driver *platform_drv)
 {
        struct snd_soc_platform *platform;
 
@@ -4024,8 +4021,8 @@ int snd_soc_register_codec(struct device *dev,
        /* create CODEC component name */
        codec->name = fmt_single_name(dev, &codec->id);
        if (codec->name == NULL) {
-               kfree(codec);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto fail_codec;
        }
 
        if (codec_drv->compress_type)
@@ -4064,7 +4061,7 @@ int snd_soc_register_codec(struct device *dev,
                                                      reg_size, GFP_KERNEL);
                        if (!codec->reg_def_copy) {
                                ret = -ENOMEM;
-                               goto fail;
+                               goto fail_codec_name;
                        }
                }
        }
@@ -4088,18 +4085,22 @@ int snd_soc_register_codec(struct device *dev,
        mutex_unlock(&client_mutex);
 
        /* register any DAIs */
-       if (num_dai) {
-               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
-               if (ret < 0)
-                       dev_err(codec->dev, "ASoC: Failed to regster"
-                               " DAIs: %d\n", ret);
+       ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+       if (ret < 0) {
+               dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+               goto fail_codec_name;
        }
 
        dev_dbg(codec->dev, "ASoC: Registered codec '%s'\n", codec->name);
        return 0;
 
-fail:
+fail_codec_name:
+       mutex_lock(&client_mutex);
+       list_del(&codec->list);
+       mutex_unlock(&client_mutex);
+
        kfree(codec->name);
+fail_codec:
        kfree(codec);
        return ret;
 }
@@ -4113,7 +4114,6 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec);
 void snd_soc_unregister_codec(struct device *dev)
 {
        struct snd_soc_codec *codec;
-       int i;
 
        list_for_each_entry(codec, &codec_list, list) {
                if (dev == codec->dev)
@@ -4122,9 +4122,7 @@ void snd_soc_unregister_codec(struct device *dev)
        return;
 
 found:
-       if (codec->num_dai)
-               for (i = 0; i < codec->num_dai; i++)
-                       snd_soc_unregister_dai(dev);
+       snd_soc_unregister_dais(dev, codec->num_dai);
 
        mutex_lock(&client_mutex);
        list_del(&codec->list);
@@ -4139,6 +4137,92 @@ found:
 }
 EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
 
+
+/**
+ * snd_soc_register_component - Register a component with the ASoC core
+ *
+ */
+int snd_soc_register_component(struct device *dev,
+                        const struct snd_soc_component_driver *cmpnt_drv,
+                        struct snd_soc_dai_driver *dai_drv,
+                        int num_dai)
+{
+       struct snd_soc_component *cmpnt;
+       int ret;
+
+       dev_dbg(dev, "component register %s\n", dev_name(dev));
+
+       cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL);
+       if (!cmpnt) {
+               dev_err(dev, "ASoC: Failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       cmpnt->name = fmt_single_name(dev, &cmpnt->id);
+       if (!cmpnt->name) {
+               dev_err(dev, "ASoC: Failed to simplifying name\n");
+               return -ENOMEM;
+       }
+
+       cmpnt->dev      = dev;
+       cmpnt->driver   = cmpnt_drv;
+       cmpnt->num_dai  = num_dai;
+
+       /*
+        * snd_soc_register_dai()  uses fmt_single_name(), and
+        * snd_soc_register_dais() uses fmt_multiple_name()
+        * for dai->name which is used for name based matching
+        */
+       if (1 == num_dai)
+               ret = snd_soc_register_dai(dev, dai_drv);
+       else
+               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+       if (ret < 0) {
+               dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret);
+               goto error_component_name;
+       }
+
+       mutex_lock(&client_mutex);
+       list_add(&cmpnt->list, &component_list);
+       mutex_unlock(&client_mutex);
+
+       dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name);
+
+       return ret;
+
+error_component_name:
+       kfree(cmpnt->name);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_register_component);
+
+/**
+ * snd_soc_unregister_component - Unregister a component from the ASoC core
+ *
+ */
+void snd_soc_unregister_component(struct device *dev)
+{
+       struct snd_soc_component *cmpnt;
+
+       list_for_each_entry(cmpnt, &component_list, list) {
+               if (dev == cmpnt->dev)
+                       goto found;
+       }
+       return;
+
+found:
+       snd_soc_unregister_dais(dev, cmpnt->num_dai);
+
+       mutex_lock(&client_mutex);
+       list_del(&cmpnt->list);
+       mutex_unlock(&client_mutex);
+
+       dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name);
+       kfree(cmpnt->name);
+}
+EXPORT_SYMBOL_GPL(snd_soc_unregister_component);
+
 /* Retrieve a card's name from device tree */
 int snd_soc_of_parse_card_name(struct snd_soc_card *card,
                               const char *propname)
index d6d9ba2..21779a6 100644 (file)
@@ -504,17 +504,27 @@ static int dapm_is_shared_kcontrol(struct snd_soc_dapm_context *dapm,
        return 0;
 }
 
-/* create new dapm mixer control */
-static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+/*
+ * 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)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
-       int i, ret = 0;
-       size_t name_len, prefix_len;
-       struct snd_soc_dapm_path *path;
        struct snd_card *card = dapm->card->snd_card;
        const char *prefix;
+       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;
+       size_t name_len;
+       char *long_name;
+       const char *name;
+       int ret;
 
        if (dapm->codec)
                prefix = dapm->codec->name_prefix;
@@ -526,103 +536,141 @@ static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
        else
                prefix_len = 0;
 
-       /* add kcontrol */
-       for (i = 0; i < w->num_kcontrols; i++) {
+       shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[kci],
+                                        &kcontrol);
 
-               /* match name */
-               list_for_each_entry(path, &w->sources, list_sink) {
+       if (kcontrol) {
+               wlist = kcontrol->private_data;
+               wlistentries = wlist->num_widgets + 1;
+       } else {
+               wlist = NULL;
+               wlistentries = 1;
+       }
 
-                       /* mixer/mux paths name must match control name */
-                       if (path->name != (char *)w->kcontrol_news[i].name)
-                               continue;
+       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 (w->kcontrols[i]) {
-                               path->kcontrol = w->kcontrols[i];
-                               continue;
+       if (!kcontrol) {
+               if (shared) {
+                       wname_in_long_name = false;
+                       kcname_in_long_name = true;
+               } else {
+                       switch (w->id) {
+                       case snd_soc_dapm_switch:
+                       case snd_soc_dapm_mixer:
+                               wname_in_long_name = true;
+                               kcname_in_long_name = true;
+                               break;
+                       case snd_soc_dapm_mixer_named_ctl:
+                               wname_in_long_name = false;
+                               kcname_in_long_name = true;
+                               break;
+                       case snd_soc_dapm_mux:
+                       case snd_soc_dapm_virt_mux:
+                       case snd_soc_dapm_value_mux:
+                               wname_in_long_name = true;
+                               kcname_in_long_name = false;
+                               break;
+                       default:
+                               kfree(wlist);
+                               return -EINVAL;
                        }
+               }
+
+               if (wname_in_long_name && kcname_in_long_name) {
+                       name_len = strlen(w->name) - prefix_len + 1 +
+                                  strlen(w->kcontrol_news[kci].name) + 1;
 
-                       wlistsize = sizeof(struct snd_soc_dapm_widget_list) +
-                                   sizeof(struct snd_soc_dapm_widget *),
-                       wlist = kzalloc(wlistsize, GFP_KERNEL);
-                       if (wlist == NULL) {
-                               dev_err(dapm->dev,
-                                       "ASoC: can't allocate widget list for %s\n",
-                                       w->name);
+                       long_name = kmalloc(name_len, GFP_KERNEL);
+                       if (long_name == NULL) {
+                               kfree(wlist);
                                return -ENOMEM;
                        }
-                       wlist->num_widgets = 1;
-                       wlist->widgets[0] = w;
-
-                       /* add dapm control with long name.
-                        * for dapm_mixer this is the concatenation of the
-                        * mixer and kcontrol name.
-                        * for dapm_mixer_named_ctl this is simply the
-                        * kcontrol name.
+
+                       /*
+                        * The control will get a prefix from the control
+                        * creation process but we're also using the same
+                        * prefix for widgets so cut the prefix off the
+                        * front of the widget name.
                         */
-                       name_len = strlen(w->kcontrol_news[i].name) + 1;
-                       if (w->id != snd_soc_dapm_mixer_named_ctl)
-                               name_len += 1 + strlen(w->name);
+                       snprintf(long_name, name_len, "%s %s",
+                                w->name + prefix_len,
+                                w->kcontrol_news[kci].name);
+                       long_name[name_len - 1] = '\0';
+
+                       name = long_name;
+               } else if (wname_in_long_name) {
+                       long_name = NULL;
+                       name = w->name + prefix_len;
+               } else {
+                       long_name = NULL;
+                       name = w->kcontrol_news[kci].name;
+               }
 
-                       path->long_name = kmalloc(name_len, GFP_KERNEL);
+               kcontrol = snd_soc_cnew(&w->kcontrol_news[kci], wlist, name,
+                                       prefix);
+               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);
+                       kfree(long_name);
+                       return ret;
+               }
 
-                       if (path->long_name == NULL) {
-                               kfree(wlist);
-                               return -ENOMEM;
-                       }
+               path->long_name = long_name;
+       }
 
-                       switch (w->id) {
-                       default:
-                               /* The control will get a prefix from
-                                * the control creation process but
-                                * we're also using the same prefix
-                                * for widgets so cut the prefix off
-                                * the front of the widget name.
-                                */
-                               snprintf((char *)path->long_name, name_len,
-                                        "%s %s", w->name + prefix_len,
-                                        w->kcontrol_news[i].name);
-                               break;
-                       case snd_soc_dapm_mixer_named_ctl:
-                               snprintf((char *)path->long_name, name_len,
-                                        "%s", w->kcontrol_news[i].name);
-                               break;
-                       }
+       kcontrol->private_data = wlist;
+       w->kcontrols[kci] = kcontrol;
+       path->kcontrol = kcontrol;
 
-                       ((char *)path->long_name)[name_len - 1] = '\0';
+       return 0;
+}
 
-                       path->kcontrol = snd_soc_cnew(&w->kcontrol_news[i],
-                                                     wlist, path->long_name,
-                                                     prefix);
-                       ret = snd_ctl_add(card, path->kcontrol);
-                       if (ret < 0) {
-                               dev_err(dapm->dev, "ASoC: failed to add widget"
-                                       " %s dapm kcontrol %s: %d\n",
-                                       w->name, path->long_name, ret);
-                               kfree(wlist);
-                               kfree(path->long_name);
-                               path->long_name = NULL;
-                               return ret;
+/* create new dapm mixer control */
+static int dapm_new_mixer(struct snd_soc_dapm_widget *w)
+{
+       int i, ret;
+       struct snd_soc_dapm_path *path;
+
+       /* add kcontrol */
+       for (i = 0; i < w->num_kcontrols; i++) {
+               /* match name */
+               list_for_each_entry(path, &w->sources, list_sink) {
+                       /* mixer/mux paths name must match control name */
+                       if (path->name != (char *)w->kcontrol_news[i].name)
+                               continue;
+
+                       if (w->kcontrols[i]) {
+                               path->kcontrol = w->kcontrols[i];
+                               continue;
                        }
-                       w->kcontrols[i] = path->kcontrol;
+
+                       ret = dapm_create_or_share_mixmux_kcontrol(w, i, path);
+                       if (ret < 0)
+                               return ret;
                }
        }
-       return ret;
+
+       return 0;
 }
 
 /* create new dapm mux control */
 static int dapm_new_mux(struct snd_soc_dapm_widget *w)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
-       struct snd_soc_dapm_path *path = NULL;
-       struct snd_kcontrol *kcontrol;
-       struct snd_card *card = dapm->card->snd_card;
-       const char *prefix;
-       size_t prefix_len;
+       struct snd_soc_dapm_path *path;
        int ret;
-       struct snd_soc_dapm_widget_list *wlist;
-       int shared, wlistentries;
-       size_t wlistsize;
-       const char *name;
 
        if (w->num_kcontrols != 1) {
                dev_err(dapm->dev,
@@ -631,65 +679,19 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
                return -EINVAL;
        }
 
-       shared = dapm_is_shared_kcontrol(dapm, w, &w->kcontrol_news[0],
-                                        &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 (dapm->codec)
-                       prefix = dapm->codec->name_prefix;
-               else
-                       prefix = NULL;
-
-               if (shared) {
-                       name = w->kcontrol_news[0].name;
-                       prefix_len = 0;
-               } else {
-                       name = w->name;
-                       if (prefix)
-                               prefix_len = strlen(prefix) + 1;
-                       else
-                               prefix_len = 0;
-               }
-
-               /*
-                * The control will get a prefix from the control creation
-                * process but we're also using the same prefix for widgets so
-                * cut the prefix off the front of the widget name.
-                */
-               kcontrol = snd_soc_cnew(&w->kcontrol_news[0], wlist,
-                                       name + prefix_len, prefix);
-               ret = snd_ctl_add(card, kcontrol);
-               if (ret < 0) {
-                       dev_err(dapm->dev, "ASoC: failed to add kcontrol %s: %d\n",
-                               w->name, ret);
-                       kfree(wlist);
-                       return ret;
-               }
+       path = list_first_entry(&w->sources, struct snd_soc_dapm_path,
+                               list_sink);
+       if (!path) {
+               dev_err(dapm->dev, "ASoC: mux %s has no paths\n", w->name);
+               return -EINVAL;
        }
 
-       kcontrol->private_data = wlist;
-
-       w->kcontrols[0] = kcontrol;
+       ret = dapm_create_or_share_mixmux_kcontrol(w, 0, path);
+       if (ret < 0)
+               return ret;
 
        list_for_each_entry(path, &w->sources, list_sink)
-               path->kcontrol = kcontrol;
+               path->kcontrol = w->kcontrols[0];
 
        return 0;
 }
@@ -705,14 +707,33 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
 }
 
 /* reset 'walked' bit for each dapm path */
-static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm)
+static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
+                                  struct list_head *sink)
 {
        struct snd_soc_dapm_path *p;
 
-       list_for_each_entry(p, &dapm->card->paths, list)
-               p->walked = 0;
+       list_for_each_entry(p, sink, list_source) {
+               if (p->walked) {
+                       p->walked = 0;
+                       dapm_clear_walk_output(dapm, &p->sink->sinks);
+               }
+       }
 }
 
+static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
+                                 struct list_head *source)
+{
+       struct snd_soc_dapm_path *p;
+
+       list_for_each_entry(p, source, list_sink) {
+               if (p->walked) {
+                       p->walked = 0;
+                       dapm_clear_walk_input(dapm, &p->source->sources);
+               }
+       }
+}
+
+
 /* We implement power down on suspend by checking the power state of
  * the ALSA card - when we are suspending the ALSA state for the card
  * is set to D3.
@@ -995,13 +1016,17 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
        mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
        dapm_reset(card);
 
-       if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
                paths = is_connected_output_ep(dai->playback_widget, list);
-       else
+               dapm_clear_walk_output(&card->dapm,
+                                      &dai->playback_widget->sinks);
+       } else {
                paths = is_connected_input_ep(dai->capture_widget, list);
+               dapm_clear_walk_input(&card->dapm,
+                                     &dai->capture_widget->sources);
+       }
 
        trace_snd_soc_dapm_connected(paths, stream);
-       dapm_clear_walk(&card->dapm);
        mutex_unlock(&card->dapm_mutex);
 
        return paths;
@@ -1104,9 +1129,9 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
        DAPM_UPDATE_STAT(w, power_checks);
 
        in = is_connected_input_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_input(w->dapm, &w->sources);
        out = is_connected_output_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_output(w->dapm, &w->sinks);
        return out != 0 && in != 0;
 }
 
@@ -1129,7 +1154,7 @@ static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
 
        if (w->active) {
                in = is_connected_input_ep(w, NULL);
-               dapm_clear_walk(w->dapm);
+               dapm_clear_walk_input(w->dapm, &w->sources);
                return in != 0;
        } else {
                return dapm_generic_check_power(w);
@@ -1145,7 +1170,7 @@ static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
 
        if (w->active) {
                out = is_connected_output_ep(w, NULL);
-               dapm_clear_walk(w->dapm);
+               dapm_clear_walk_output(w->dapm, &w->sinks);
                return out != 0;
        } else {
                return dapm_generic_check_power(w);
@@ -1177,8 +1202,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
                        return 1;
        }
 
-       dapm_clear_walk(w->dapm);
-
        return 0;
 }
 
@@ -1759,9 +1782,9 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
                return -ENOMEM;
 
        in = is_connected_input_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_input(w->dapm, &w->sources);
        out = is_connected_output_ep(w, NULL);
-       dapm_clear_walk(w->dapm);
+       dapm_clear_walk_output(w->dapm, &w->sinks);
 
        ret = snprintf(buf, PAGE_SIZE, "%s: %s%s  in %d out %d",
                       w->name, w->power ? "On" : "Off",
@@ -3137,7 +3160,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
                break;
        }
 
-       dapm->n_widgets++;
        w->dapm = dapm;
        w->codec = dapm->codec;
        w->platform = dapm->platform;
index 111b7d9..a9a300a 100644 (file)
@@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data {
        dma_cookie_t cookie;
 
        unsigned int pos;
-
-       void *data;
 };
 
 static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
@@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
        return substream->runtime->private_data;
 }
 
-/**
- * snd_dmaengine_pcm_set_data - Set dmaengine substream private data
- * @substream: PCM substream
- * @data: Data to set
- */
-void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
-{
-       struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-
-       prtd->data = data;
-}
-EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data);
-
-/**
- * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
- * @substream: PCM substream
- *
- * Returns the data previously set with snd_dmaengine_pcm_set_data
- */
-void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
-{
-       struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
-
-       return prtd->data;
-}
-EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data);
-
 struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
 {
        struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
@@ -118,10 +89,49 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
                slave_config->src_addr_width = buswidth;
        }
 
+       slave_config->device_fc = false;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
 
+/**
+ * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
+ *  using DAI DMA data.
+ * @substream: PCM substream
+ * @dma_data: DAI DMA data
+ * @slave_config: DMA slave configuration
+ *
+ * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
+ * slave_id fields of the DMA slave config from the same fields of the DAI DMA
+ * data struct. The src and dst fields will be initialized depending on the
+ * direction of the substream. If the substream is a playback stream the dst
+ * fields will be initialized, if it is a capture stream the src fields will be
+ * initialized. The {dst,src}_addr_width field will only be initialized if the
+ * addr_width field of the DAI DMA data struct is not equal to
+ * DMA_SLAVE_BUSWIDTH_UNDEFINED.
+ */
+void snd_dmaengine_pcm_set_config_from_dai_data(
+       const struct snd_pcm_substream *substream,
+       const struct snd_dmaengine_dai_dma_data *dma_data,
+       struct dma_slave_config *slave_config)
+{
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               slave_config->dst_addr = dma_data->addr;
+               slave_config->dst_maxburst = dma_data->maxburst;
+               if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+                       slave_config->dst_addr_width = dma_data->addr_width;
+       } else {
+               slave_config->src_addr = dma_data->addr;
+               slave_config->src_maxburst = dma_data->maxburst;
+               if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
+                       slave_config->src_addr_width = dma_data->addr_width;
+       }
+
+       slave_config->slave_id = dma_data->slave_id;
+}
+EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
+
 static void dmaengine_pcm_dma_complete(void *arg)
 {
        struct snd_pcm_substream *substream = arg;
index 29183ef..8ca9ecc 100644 (file)
@@ -158,10 +158,7 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
                return -EINVAL;
        }
 
-       if (IS_ERR(codec->control_data))
-               return PTR_ERR(codec->control_data);
-
-       return 0;
+       return PTR_RET(codec->control_data);
 }
 EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io);
 #else
index c7c4b20..14d57e8 100644 (file)
@@ -170,6 +170,10 @@ struct snd_soc_dai_driver spdif_in_dai = {
        .ops = &spdif_in_dai_ops,
 };
 
+static const struct snd_soc_component_driver spdif_in_component = {
+       .name           = "spdif-in",
+};
+
 static irqreturn_t spdif_in_irq(int irq, void *arg)
 {
        struct spdif_in_dev *host = (struct spdif_in_dev *)arg;
@@ -258,7 +262,8 @@ static int spdif_in_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai);
+       ret = snd_soc_register_component(&pdev->dev, &spdif_in_component,
+                                        &spdif_in_dai, 1);
        if (ret != 0) {
                clk_put(host->clk);
                return ret;
@@ -271,7 +276,7 @@ static int spdif_in_remove(struct platform_device *pdev)
 {
        struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
        clk_put(host->clk);
index 5eac4cd..1e3c3dd 100644 (file)
@@ -270,6 +270,10 @@ static struct snd_soc_dai_driver spdif_out_dai = {
        .ops = &spdif_out_dai_ops,
 };
 
+static const struct snd_soc_component_driver spdif_out_component = {
+       .name           = "spdif-out",
+};
+
 static int spdif_out_probe(struct platform_device *pdev)
 {
        struct spdif_out_dev *host;
@@ -314,7 +318,8 @@ static int spdif_out_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, host);
 
-       ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai);
+       ret = snd_soc_register_component(&pdev->dev, &spdif_out_component,
+                                        &spdif_out_dai, 1);
        if (ret != 0) {
                clk_put(host->clk);
                return ret;
@@ -327,7 +332,7 @@ static int spdif_out_remove(struct platform_device *pdev)
 {
        struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        dev_set_drvdata(&pdev->dev, NULL);
 
        clk_put(host->clk);
index 5e7aebe..bfbcc1f 100644 (file)
@@ -25,7 +25,7 @@
 #include <sound/soc.h>
 #include <sound/spear_dma.h>
 
-struct snd_pcm_hardware spear_pcm_hardware = {
+static struct snd_pcm_hardware spear_pcm_hardware = {
        .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
                 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
                 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
@@ -64,21 +64,7 @@ static int spear_pcm_open(struct snd_pcm_substream *substream)
        if (ret)
                return ret;
 
-       ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data);
-       if (ret)
-               return ret;
-
-       snd_dmaengine_pcm_set_data(substream, dma_data);
-
-       return 0;
-}
-
-static int spear_pcm_close(struct snd_pcm_substream *substream)
-{
-
-       snd_dmaengine_pcm_close(substream);
-
-       return 0;
+       return snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data)
 }
 
 static int spear_pcm_mmap(struct snd_pcm_substream *substream,
@@ -93,7 +79,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops spear_pcm_ops = {
        .open           = spear_pcm_open,
-       .close          = spear_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = spear_pcm_hw_params,
        .hw_free        = spear_pcm_hw_free,
@@ -178,7 +164,7 @@ static int spear_pcm_new(struct snd_soc_pcm_runtime *rtd)
        return 0;
 }
 
-struct snd_soc_platform_driver spear_soc_platform = {
+static struct snd_soc_platform_driver spear_soc_platform = {
        .ops            =       &spear_pcm_ops,
        .pcm_new        =       spear_pcm_new,
        .pcm_free       =       spear_pcm_free,
index 336dcdd..2f70ea7 100644 (file)
@@ -35,6 +35,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra_asoc_utils.h"
 #include "tegra20_ac97.h"
@@ -248,6 +249,10 @@ static struct snd_soc_dai_driver tegra20_ac97_dai = {
        .ops = &tegra20_ac97_dai_ops,
 };
 
+static const struct snd_soc_component_driver tegra20_ac97_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra20_ac97_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -389,16 +394,17 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        }
 
        ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
-       ac97->capture_dma_data.wrap = 4;
-       ac97->capture_dma_data.width = 32;
-       ac97->capture_dma_data.req_sel = of_dma[1];
+       ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       ac97->capture_dma_data.maxburst = 4;
+       ac97->capture_dma_data.slave_id = of_dma[1];
 
        ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
-       ac97->playback_dma_data.wrap = 4;
-       ac97->playback_dma_data.width = 32;
-       ac97->playback_dma_data.req_sel = of_dma[1];
+       ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       ac97->capture_dma_data.maxburst = 4;
+       ac97->capture_dma_data.slave_id = of_dma[0];
 
-       ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1);
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_ac97_component,
+                                        &tegra20_ac97_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -408,7 +414,7 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev);
@@ -434,8 +440,8 @@ err_asoc_utils_fini:
        tegra_asoc_utils_fini(&ac97->util_data);
 err_unregister_pcm:
        tegra_pcm_platform_unregister(&pdev->dev);
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_clk_put:
        clk_put(ac97->clk_ac97);
 err:
@@ -447,7 +453,7 @@ static int tegra20_ac97_platform_remove(struct platform_device *pdev)
        struct tegra20_ac97 *ac97 = dev_get_drvdata(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        tegra_asoc_utils_fini(&ac97->util_data);
 
index dddc682..4acb3aa 100644 (file)
@@ -85,8 +85,8 @@
 
 struct tegra20_ac97 {
        struct clk *clk_ac97;
-       struct tegra_pcm_dma_params capture_dma_data;
-       struct tegra_pcm_dma_params playback_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
        struct regmap *regmap;
        int reset_gpio;
        int sync_gpio;
index caa772d..52af7f6 100644 (file)
@@ -41,6 +41,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra20_i2s.h"
 
@@ -276,6 +277,10 @@ static const struct snd_soc_dai_driver tegra20_i2s_dai_template = {
        .symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver tegra20_i2s_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra20_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -403,14 +408,14 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
        }
 
        i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
-       i2s->capture_dma_data.wrap = 4;
-       i2s->capture_dma_data.width = 32;
-       i2s->capture_dma_data.req_sel = dma_ch;
+       i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       i2s->capture_dma_data.maxburst = 4;
+       i2s->capture_dma_data.slave_id = dma_ch;
 
        i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
-       i2s->playback_dma_data.wrap = 4;
-       i2s->playback_dma_data.width = 32;
-       i2s->playback_dma_data.req_sel = dma_ch;
+       i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       i2s->playback_dma_data.maxburst = 4;
+       i2s->playback_dma_data.slave_id = dma_ch;
 
        pm_runtime_enable(&pdev->dev);
        if (!pm_runtime_enabled(&pdev->dev)) {
@@ -419,7 +424,8 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_i2s_component,
+                                        &i2s->dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -429,13 +435,13 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_suspend:
        if (!pm_runtime_status_suspended(&pdev->dev))
                tegra20_i2s_runtime_suspend(&pdev->dev);
@@ -456,7 +462,7 @@ static int tegra20_i2s_platform_remove(struct platform_device *pdev)
                tegra20_i2s_runtime_suspend(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(i2s->clk_i2s);
 
index 7299587..fa6c29c 100644 (file)
 struct tegra20_i2s {
        struct snd_soc_dai_driver dai;
        struct clk *clk_i2s;
-       struct tegra_pcm_dma_params capture_dma_data;
-       struct tegra_pcm_dma_params playback_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
        struct regmap *regmap;
 };
 
index 04771d1..5eaa12c 100644 (file)
@@ -32,6 +32,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra20_spdif.h"
 
@@ -182,6 +183,10 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = {
        .ops = &tegra20_spdif_dai_ops,
 };
 
+static const struct snd_soc_component_driver tegra20_spdif_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra20_spdif_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -318,9 +323,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
        }
 
        spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
-       spdif->playback_dma_data.wrap = 4;
-       spdif->playback_dma_data.width = 32;
-       spdif->playback_dma_data.req_sel = dmareq->start;
+       spdif->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       spdif->capture_dma_data.maxburst = 4;
+       spdif->playback_dma_data.slave_id = dmareq->start;
 
        pm_runtime_enable(&pdev->dev);
        if (!pm_runtime_enabled(&pdev->dev)) {
@@ -329,7 +334,8 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &tegra20_spdif_dai);
+       ret = snd_soc_register_component(&pdev->dev, &tegra20_spdif_component,
+                                  &tegra20_spdif_dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -339,13 +345,13 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_suspend:
        if (!pm_runtime_status_suspended(&pdev->dev))
                tegra20_spdif_runtime_suspend(&pdev->dev);
@@ -366,7 +372,7 @@ static int tegra20_spdif_platform_remove(struct platform_device *pdev)
                tegra20_spdif_runtime_suspend(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(spdif->clk_spdif_out);
 
index b48d699..85a9aef 100644 (file)
 
 struct tegra20_spdif {
        struct clk *clk_spdif_out;
-       struct tegra_pcm_dma_params capture_dma_data;
-       struct tegra_pcm_dma_params playback_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
        struct regmap *regmap;
 };
 
index e5cfb4a..23e592f 100644 (file)
@@ -95,8 +95,8 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
 }
 
 int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
-                                 unsigned long *fiforeg,
-                                 unsigned long *reqsel)
+                                 dma_addr_t *fiforeg,
+                                 unsigned int *reqsel)
 {
        int channel;
        u32 reg, val;
@@ -178,8 +178,8 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
 EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
 
 int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
-                                 unsigned long *fiforeg,
-                                 unsigned long *reqsel)
+                                 dma_addr_t *fiforeg,
+                                 unsigned int *reqsel)
 {
        int channel;
        u32 reg, val;
@@ -287,16 +287,27 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif)
 }
 EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source);
 
-static const char * const configlink_clocks[] = {
-       "i2s0",
-       "i2s1",
-       "i2s2",
-       "i2s3",
-       "i2s4",
-       "dam0",
-       "dam1",
-       "dam2",
-       "spdif_in",
+#define CLK_LIST_MASK_TEGRA30  BIT(0)
+#define CLK_LIST_MASK_TEGRA114 BIT(1)
+
+#define CLK_LIST_MASK_TEGRA30_OR_LATER \
+               (CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114)
+
+static const struct {
+       const char *clk_name;
+       u32 clk_list_mask;
+} configlink_clocks[] = {
+       { "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER },
+       { "amx", CLK_LIST_MASK_TEGRA114 },
+       { "adx", CLK_LIST_MASK_TEGRA114 },
 };
 
 #define LAST_REG(name) \
@@ -424,8 +435,24 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+static struct tegra30_ahub_soc_data soc_data_tegra30 = {
+       .clk_list_mask = CLK_LIST_MASK_TEGRA30,
+};
+
+static struct tegra30_ahub_soc_data soc_data_tegra114 = {
+       .clk_list_mask = CLK_LIST_MASK_TEGRA114,
+};
+
+static const struct of_device_id tegra30_ahub_of_match[] = {
+       { .compatible = "nvidia,tegra114-ahub", .data = &soc_data_tegra114 },
+       { .compatible = "nvidia,tegra30-ahub",  .data = &soc_data_tegra30 },
+       {},
+};
+
 static int tegra30_ahub_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *match;
+       const struct tegra30_ahub_soc_data *soc_data;
        struct clk *clk;
        int i;
        struct resource *res0, *res1, *region;
@@ -436,16 +463,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
        if (ahub)
                return -ENODEV;
 
+       match = of_match_device(tegra30_ahub_of_match, &pdev->dev);
+       if (!match)
+               return -EINVAL;
+       soc_data = match->data;
+
        /*
         * The AHUB hosts a register bus: the "configlink". For this to
         * operate correctly, all devices on this bus must be out of reset.
         * Ensure that here.
         */
        for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) {
-               clk = clk_get(&pdev->dev, configlink_clocks[i]);
+               if (!(configlink_clocks[i].clk_list_mask &
+                                       soc_data->clk_list_mask))
+                       continue;
+               clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name);
                if (IS_ERR(clk)) {
                        dev_err(&pdev->dev, "Can't get clock %s\n",
-                               configlink_clocks[i]);
+                               configlink_clocks[i].clk_name);
                        ret = PTR_ERR(clk);
                        goto err;
                }
@@ -592,11 +627,6 @@ static int tegra30_ahub_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct of_device_id tegra30_ahub_of_match[] = {
-       { .compatible = "nvidia,tegra30-ahub", },
-       {},
-};
-
 static const struct dev_pm_ops tegra30_ahub_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend,
                           tegra30_ahub_runtime_resume, NULL)
index e690e2e..09766cd 100644 (file)
@@ -451,15 +451,15 @@ enum tegra30_ahub_rxcif {
 };
 
 extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
-                                        unsigned long *fiforeg,
-                                        unsigned long *reqsel);
+                                        dma_addr_t *fiforeg,
+                                        unsigned int *reqsel);
 extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
 extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
 extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
 
 extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
-                                        unsigned long *fiforeg,
-                                        unsigned long *reqsel);
+                                        dma_addr_t *fiforeg,
+                                        unsigned int *reqsel);
 extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
@@ -468,7 +468,23 @@ extern int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif,
                                          enum tegra30_ahub_txcif txcif);
 extern int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif);
 
+struct tegra30_ahub_soc_data {
+       u32 clk_list_mask;
+       /*
+        * FIXME: There are many more differences in HW, such as:
+        * - More APBIF channels.
+        * - Extra separate chunks of register address space to represent
+        *   the extra APBIF channels.
+        * - More units connected to the AHUB, so that tegra30_ahub_[rt]xcif
+        *   need expansion, coupled with there being more defined bits in
+        *   the AHUB routing registers.
+        * However, the driver doesn't support those new features yet, so we
+        * don't represent them here yet.
+        */
+};
+
 struct tegra30_ahub {
+       const struct tegra30_ahub_soc_data *soc_data;
        struct device *dev;
        struct clk *clk_d_audio;
        struct clk *clk_apbif;
index f4e1ce8..31d092d 100644 (file)
@@ -38,6 +38,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 #include "tegra30_ahub.h"
 #include "tegra30_i2s.h"
@@ -80,17 +81,17 @@ static int tegra30_i2s_startup(struct snd_pcm_substream *substream,
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
                                        &i2s->playback_dma_data.addr,
-                                       &i2s->playback_dma_data.req_sel);
-               i2s->playback_dma_data.wrap = 4;
-               i2s->playback_dma_data.width = 32;
+                                       &i2s->playback_dma_data.slave_id);
+               i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               i2s->playback_dma_data.maxburst = 4;
                tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
                                               i2s->playback_fifo_cif);
        } else {
                ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
                                        &i2s->capture_dma_data.addr,
-                                       &i2s->capture_dma_data.req_sel);
-               i2s->capture_dma_data.wrap = 4;
-               i2s->capture_dma_data.width = 32;
+                                       &i2s->capture_dma_data.slave_id);
+               i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               i2s->capture_dma_data.maxburst = 4;
                tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
                                               i2s->capture_i2s_cif);
        }
@@ -336,6 +337,10 @@ static const struct snd_soc_dai_driver tegra30_i2s_dai_template = {
        .symmetric_rates = 1,
 };
 
+static const struct snd_soc_component_driver tegra30_i2s_component = {
+       .name           = DRV_NAME,
+};
+
 static bool tegra30_i2s_wr_rd_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -464,7 +469,8 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
                        goto err_pm_disable;
        }
 
-       ret = snd_soc_register_dai(&pdev->dev, &i2s->dai);
+       ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component,
+                                  &i2s->dai, 1);
        if (ret) {
                dev_err(&pdev->dev, "Could not register DAI: %d\n", ret);
                ret = -ENOMEM;
@@ -474,13 +480,13 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev)
        ret = tegra_pcm_platform_register(&pdev->dev);
        if (ret) {
                dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
-               goto err_unregister_dai;
+               goto err_unregister_component;
        }
 
        return 0;
 
-err_unregister_dai:
-       snd_soc_unregister_dai(&pdev->dev);
+err_unregister_component:
+       snd_soc_unregister_component(&pdev->dev);
 err_suspend:
        if (!pm_runtime_status_suspended(&pdev->dev))
                tegra30_i2s_runtime_suspend(&pdev->dev);
@@ -501,7 +507,7 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev)
                tegra30_i2s_runtime_suspend(&pdev->dev);
 
        tegra_pcm_platform_unregister(&pdev->dev);
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
 
        clk_put(i2s->clk_i2s);
 
index a294d94..bea23af 100644 (file)
@@ -231,10 +231,10 @@ struct tegra30_i2s {
        struct clk *clk_i2s;
        enum tegra30_ahub_txcif capture_i2s_cif;
        enum tegra30_ahub_rxcif capture_fifo_cif;
-       struct tegra_pcm_dma_params capture_dma_data;
+       struct snd_dmaengine_dai_dma_data capture_dma_data;
        enum tegra30_ahub_rxcif playback_i2s_cif;
        enum tegra30_ahub_txcif playback_fifo_cif;
-       struct tegra_pcm_dma_params playback_dma_data;
+       struct snd_dmaengine_dai_dma_data playback_dma_data;
        struct regmap *regmap;
 };
 
index c80adb9..48d05d9 100644 (file)
@@ -161,20 +161,13 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
                        sizeof(struct tegra_alc5632), GFP_KERNEL);
        if (!alc5632) {
                dev_err(&pdev->dev, "Can't allocate tegra_alc5632\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, alc5632);
 
-       if (!(pdev->dev.of_node)) {
-               dev_err(&pdev->dev, "Must be instantiated using device tree\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
        alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
        if (alc5632->gpio_hp_det == -EPROBE_DEFER)
                return -EPROBE_DEFER;
@@ -197,11 +190,11 @@ static int tegra_alc5632_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_alc5632_dai.cpu_of_node = of_parse_phandle(
-                       pdev->dev.of_node, "nvidia,i2s-controller", 0);
+       tegra_alc5632_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
        if (!tegra_alc5632_dai.cpu_of_node) {
                dev_err(&pdev->dev,
-               "Property 'nvidia,i2s-controller' missing or invalid\n");
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
                ret = -EINVAL;
                goto err;
        }
index ba419f8..24fb001 100644 (file)
@@ -43,8 +43,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
        case 88200:
                if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
                        new_baseclock = 56448000;
-               else
+               else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
                        new_baseclock = 564480000;
+               else
+                       new_baseclock = 282240000;
                break;
        case 8000:
        case 16000:
@@ -54,8 +56,10 @@ int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
        case 96000:
                if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
                        new_baseclock = 73728000;
-               else
+               else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA30)
                        new_baseclock = 552960000;
+               else
+                       new_baseclock = 368640000;
                break;
        default:
                return -EINVAL;
@@ -169,6 +173,7 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                          struct device *dev)
 {
        int ret;
+       bool new_clocks = false;
 
        data->dev = dev;
 
@@ -176,28 +181,37 @@ int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
        else if (of_machine_is_compatible("nvidia,tegra30"))
                data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA30;
-       else if (!dev->of_node)
-               /* non-DT is always Tegra20 */
-               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA20;
-       else
-               /* DT boot, but unknown SoC */
+       else if (of_machine_is_compatible("nvidia,tegra114")) {
+               data->soc = TEGRA_ASOC_UTILS_SOC_TEGRA114;
+               new_clocks = true;
+       } else {
+               dev_err(data->dev, "SoC unknown to Tegra ASoC utils\n");
                return -EINVAL;
+       }
 
-       data->clk_pll_a = clk_get_sys(NULL, "pll_a");
+       if (new_clocks)
+               data->clk_pll_a = clk_get(dev, "pll_a");
+       else
+               data->clk_pll_a = clk_get_sys(NULL, "pll_a");
        if (IS_ERR(data->clk_pll_a)) {
                dev_err(data->dev, "Can't retrieve clk pll_a\n");
                ret = PTR_ERR(data->clk_pll_a);
                goto err;
        }
 
-       data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
+       if (new_clocks)
+               data->clk_pll_a_out0 = clk_get(dev, "pll_a_out0");
+       else
+               data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
        if (IS_ERR(data->clk_pll_a_out0)) {
                dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
                ret = PTR_ERR(data->clk_pll_a_out0);
                goto err_put_pll_a;
        }
 
-       if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
+       if (new_clocks)
+               data->clk_cdev1 = clk_get(dev, "mclk");
+       else if (data->soc == TEGRA_ASOC_UTILS_SOC_TEGRA20)
                data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
        else
                data->clk_cdev1 = clk_get_sys("extern1", NULL);
index 974c9f8..19fdcaf 100644 (file)
@@ -29,6 +29,7 @@ struct device;
 enum tegra_asoc_utils_soc {
        TEGRA_ASOC_UTILS_SOC_TEGRA20,
        TEGRA_ASOC_UTILS_SOC_TEGRA30,
+       TEGRA_ASOC_UTILS_SOC_TEGRA114,
 };
 
 struct tegra_asoc_utils_data {
index c925ab0..6d1c70c 100644 (file)
@@ -43,8 +43,6 @@
 static const struct snd_pcm_hardware tegra_pcm_hardware = {
        .info                   = SNDRV_PCM_INFO_MMAP |
                                  SNDRV_PCM_INFO_MMAP_VALID |
-                                 SNDRV_PCM_INFO_PAUSE |
-                                 SNDRV_PCM_INFO_RESUME |
                                  SNDRV_PCM_INFO_INTERLEAVED,
        .formats                = SNDRV_PCM_FMTBIT_S16_LE,
        .channels_min           = 2,
@@ -75,24 +73,15 @@ static int tegra_pcm_open(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int tegra_pcm_close(struct snd_pcm_substream *substream)
-{
-       snd_dmaengine_pcm_close(substream);
-       return 0;
-}
-
 static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct device *dev = rtd->platform->dev;
        struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
-       struct tegra_pcm_dma_params *dmap;
        struct dma_slave_config slave_config;
        int ret;
 
-       dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
-
        ret = snd_hwparams_to_dma_slave_config(substream, params,
                                                &slave_config);
        if (ret) {
@@ -100,16 +89,9 @@ static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-               slave_config.dst_addr = dmap->addr;
-               slave_config.dst_maxburst = 4;
-       } else {
-               slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-               slave_config.src_addr = dmap->addr;
-               slave_config.src_maxburst = 4;
-       }
-       slave_config.slave_id = dmap->req_sel;
+       snd_dmaengine_pcm_set_config_from_dai_data(substream,
+                       snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
+                       &slave_config);
 
        ret = dmaengine_slave_config(chan, &slave_config);
        if (ret < 0) {
@@ -127,26 +109,6 @@ static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
        return 0;
 }
 
-static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               return snd_dmaengine_pcm_trigger(substream,
-                                       SNDRV_PCM_TRIGGER_START);
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               return snd_dmaengine_pcm_trigger(substream,
-                                       SNDRV_PCM_TRIGGER_STOP);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
 static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
                                struct vm_area_struct *vma)
 {
@@ -160,11 +122,11 @@ static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops tegra_pcm_ops = {
        .open           = tegra_pcm_open,
-       .close          = tegra_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = tegra_pcm_hw_params,
        .hw_free        = tegra_pcm_hw_free,
-       .trigger        = tegra_pcm_trigger,
+       .trigger        = snd_dmaengine_pcm_trigger,
        .pointer        = snd_dmaengine_pcm_pointer,
        .mmap           = tegra_pcm_mmap,
 };
index bc8b46a..68ad901 100644 (file)
 #ifndef __TEGRA_PCM_H__
 #define __TEGRA_PCM_H__
 
-struct tegra_pcm_dma_params {
-       unsigned long addr;
-       unsigned long wrap;
-       unsigned long width;
-       unsigned long req_sel;
-};
-
 int tegra_pcm_platform_register(struct device *dev);
 void tegra_pcm_platform_unregister(struct device *dev);
 
index c8ef88a..f87fc53 100644 (file)
@@ -124,6 +124,7 @@ static struct snd_soc_card snd_soc_tegra_wm8753 = {
 
 static int tegra_wm8753_driver_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_tegra_wm8753;
        struct tegra_wm8753 *machine;
        int ret;
@@ -132,8 +133,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                               GFP_KERNEL);
        if (!machine) {
                dev_err(&pdev->dev, "Can't allocate tegra_wm8753 struct\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
        card->dev = &pdev->dev;
@@ -148,8 +148,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
        if (ret)
                goto err;
 
-       tegra_wm8753_dai.codec_of_node = of_parse_phandle(
-                       pdev->dev.of_node, "nvidia,audio-codec", 0);
+       tegra_wm8753_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
        if (!tegra_wm8753_dai.codec_of_node) {
                dev_err(&pdev->dev,
                        "Property 'nvidia,audio-codec' missing or invalid\n");
@@ -157,8 +157,8 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_wm8753_dai.cpu_of_node = of_parse_phandle(
-                       pdev->dev.of_node, "nvidia,i2s-controller", 0);
+       tegra_wm8753_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
        if (!tegra_wm8753_dai.cpu_of_node) {
                dev_err(&pdev->dev,
                        "Property 'nvidia,i2s-controller' missing or invalid\n");
@@ -166,8 +166,7 @@ static int tegra_wm8753_driver_probe(struct platform_device *pdev)
                goto err;
        }
 
-       tegra_wm8753_dai.platform_of_node =
-                               tegra_wm8753_dai.cpu_of_node;
+       tegra_wm8753_dai.platform_of_node = tegra_wm8753_dai.cpu_of_node;
 
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
index bbd79bf..4ac7373 100644 (file)
@@ -39,7 +39,6 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
-#include <sound/tegra_wm8903.h>
 
 #include "../codecs/wm8903.h"
 
 #define DRV_NAME "tegra-snd-wm8903"
 
 struct tegra_wm8903 {
-       struct tegra_wm8903_platform_data pdata;
+       int gpio_spkr_en;
+       int gpio_hp_det;
+       int gpio_hp_mute;
+       int gpio_int_mic_en;
+       int gpio_ext_mic_en;
        struct tegra_asoc_utils_data util_data;
 };
 
@@ -129,12 +132,11 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (!gpio_is_valid(pdata->gpio_spkr_en))
+       if (!gpio_is_valid(machine->gpio_spkr_en))
                return 0;
 
-       gpio_set_value_cansleep(pdata->gpio_spkr_en,
+       gpio_set_value_cansleep(machine->gpio_spkr_en,
                                SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
@@ -146,12 +148,11 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w,
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (!gpio_is_valid(pdata->gpio_hp_mute))
+       if (!gpio_is_valid(machine->gpio_hp_mute))
                return 0;
 
-       gpio_set_value_cansleep(pdata->gpio_hp_mute,
+       gpio_set_value_cansleep(machine->gpio_hp_mute,
                                !SND_SOC_DAPM_EVENT_ON(event));
 
        return 0;
@@ -163,17 +164,6 @@ static const struct snd_soc_dapm_widget tegra_wm8903_dapm_widgets[] = {
        SND_SOC_DAPM_MIC("Mic Jack", NULL),
 };
 
-static const struct snd_soc_dapm_route harmony_audio_map[] = {
-       {"Headphone Jack", NULL, "HPOUTR"},
-       {"Headphone Jack", NULL, "HPOUTL"},
-       {"Int Spk", NULL, "ROP"},
-       {"Int Spk", NULL, "RON"},
-       {"Int Spk", NULL, "LOP"},
-       {"Int Spk", NULL, "LON"},
-       {"Mic Jack", NULL, "MICBIAS"},
-       {"IN1L", NULL, "Mic Jack"},
-};
-
 static const struct snd_kcontrol_new tegra_wm8903_controls[] = {
        SOC_DAPM_PIN_SWITCH("Int Spk"),
 };
@@ -185,10 +175,9 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd)
        struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = codec->card;
        struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card);
-       struct tegra_wm8903_platform_data *pdata = &machine->pdata;
 
-       if (gpio_is_valid(pdata->gpio_hp_det)) {
-               tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det;
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               tegra_wm8903_hp_jack_gpio.gpio = machine->gpio_hp_det;
                snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
                                &tegra_wm8903_hp_jack);
                snd_soc_jack_add_pins(&tegra_wm8903_hp_jack,
@@ -226,9 +215,6 @@ static int tegra_wm8903_remove(struct snd_soc_card *card)
 static struct snd_soc_dai_link tegra_wm8903_dai = {
        .name = "WM8903",
        .stream_name = "WM8903 PCM",
-       .codec_name = "wm8903.0-001a",
-       .platform_name = "tegra20-i2s.0",
-       .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "wm8903-hifi",
        .init = tegra_wm8903_init,
        .ops = &tegra_wm8903_ops,
@@ -257,96 +243,25 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_tegra_wm8903;
        struct tegra_wm8903 *machine;
-       struct tegra_wm8903_platform_data *pdata;
        int ret;
 
-       if (!pdev->dev.platform_data && !pdev->dev.of_node) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
        machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm8903),
                               GFP_KERNEL);
        if (!machine) {
                dev_err(&pdev->dev, "Can't allocate tegra_wm8903 struct\n");
-               ret = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
-       pdata = &machine->pdata;
 
        card->dev = &pdev->dev;
        platform_set_drvdata(pdev, card);
        snd_soc_card_set_drvdata(card, machine);
 
-       if (pdev->dev.platform_data) {
-               memcpy(pdata, card->dev->platform_data, sizeof(*pdata));
-       } else if (np) {
-               pdata->gpio_spkr_en = of_get_named_gpio(np,
-                                               "nvidia,spkr-en-gpios", 0);
-               if (pdata->gpio_spkr_en == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_hp_mute = of_get_named_gpio(np,
-                                               "nvidia,hp-mute-gpios", 0);
-               if (pdata->gpio_hp_mute == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_hp_det = of_get_named_gpio(np,
-                                               "nvidia,hp-det-gpios", 0);
-               if (pdata->gpio_hp_det == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_int_mic_en = of_get_named_gpio(np,
-                                               "nvidia,int-mic-en-gpios", 0);
-               if (pdata->gpio_int_mic_en == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               pdata->gpio_ext_mic_en = of_get_named_gpio(np,
-                                               "nvidia,ext-mic-en-gpios", 0);
-               if (pdata->gpio_ext_mic_en == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-       }
-
-       if (np) {
-               ret = snd_soc_of_parse_card_name(card, "nvidia,model");
-               if (ret)
-                       goto err;
-
-               ret = snd_soc_of_parse_audio_routing(card,
-                                                    "nvidia,audio-routing");
-               if (ret)
-                       goto err;
-
-               tegra_wm8903_dai.codec_name = NULL;
-               tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
-                               "nvidia,audio-codec", 0);
-               if (!tegra_wm8903_dai.codec_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,audio-codec' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               tegra_wm8903_dai.cpu_dai_name = NULL;
-               tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
-                               "nvidia,i2s-controller", 0);
-               if (!tegra_wm8903_dai.cpu_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,i2s-controller' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               tegra_wm8903_dai.platform_name = NULL;
-               tegra_wm8903_dai.platform_of_node =
-                                       tegra_wm8903_dai.cpu_of_node;
-       } else {
-               card->dapm_routes = harmony_audio_map;
-               card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
-       }
-
-       if (gpio_is_valid(pdata->gpio_spkr_en)) {
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en,
+       machine->gpio_spkr_en = of_get_named_gpio(np, "nvidia,spkr-en-gpios",
+                                                 0);
+       if (machine->gpio_spkr_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_spkr_en)) {
+               ret = devm_gpio_request_one(&pdev->dev, machine->gpio_spkr_en,
                                            GPIOF_OUT_INIT_LOW, "spkr_en");
                if (ret) {
                        dev_err(card->dev, "cannot get spkr_en gpio\n");
@@ -354,8 +269,12 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
-       if (gpio_is_valid(pdata->gpio_hp_mute)) {
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute,
+       machine->gpio_hp_mute = of_get_named_gpio(np, "nvidia,hp-mute-gpios",
+                                                 0);
+       if (machine->gpio_hp_mute == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_hp_mute)) {
+               ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_mute,
                                            GPIOF_OUT_INIT_HIGH, "hp_mute");
                if (ret) {
                        dev_err(card->dev, "cannot get hp_mute gpio\n");
@@ -363,9 +282,18 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
-       if (gpio_is_valid(pdata->gpio_int_mic_en)) {
+       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (machine->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       machine->gpio_int_mic_en = of_get_named_gpio(np,
+                                               "nvidia,int-mic-en-gpios", 0);
+       if (machine->gpio_int_mic_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_int_mic_en)) {
                /* Disable int mic; enable signal is active-high */
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en,
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           machine->gpio_int_mic_en,
                                            GPIOF_OUT_INIT_LOW, "int_mic_en");
                if (ret) {
                        dev_err(card->dev, "cannot get int_mic_en gpio\n");
@@ -373,9 +301,14 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
-       if (gpio_is_valid(pdata->gpio_ext_mic_en)) {
+       machine->gpio_ext_mic_en = of_get_named_gpio(np,
+                                               "nvidia,ext-mic-en-gpios", 0);
+       if (machine->gpio_ext_mic_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_ext_mic_en)) {
                /* Enable ext mic; enable signal is active-low */
-               ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en,
+               ret = devm_gpio_request_one(&pdev->dev,
+                                           machine->gpio_ext_mic_en,
                                            GPIOF_OUT_INIT_LOW, "ext_mic_en");
                if (ret) {
                        dev_err(card->dev, "cannot get ext_mic_en gpio\n");
@@ -383,6 +316,34 @@ static int tegra_wm8903_driver_probe(struct platform_device *pdev)
                }
        }
 
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_wm8903_dai.codec_of_node = of_parse_phandle(np,
+                                               "nvidia,audio-codec", 0);
+       if (!tegra_wm8903_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_wm8903_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_wm8903_dai.platform_of_node = tegra_wm8903_dai.cpu_of_node;
+
        ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
        if (ret)
                goto err;
index 68d4240..5e11963 100644 (file)
@@ -55,7 +55,7 @@ static int tegra_wm9712_init(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_dai_link tegra_wm9712_dai = {
        .name = "AC97 HiFi",
        .stream_name = "AC97 HiFi",
-       .cpu_dai_name = "tegra-ac97-pcm",
+       .cpu_dai_name = "tegra20-ac97",
        .codec_dai_name = "wm9712-hifi",
        .codec_name = "wm9712-codec",
        .init = tegra_wm9712_init,
@@ -79,11 +79,6 @@ static int tegra_wm9712_driver_probe(struct platform_device *pdev)
        struct tegra_wm9712 *machine;
        int ret;
 
-       if (!pdev->dev.of_node) {
-               dev_err(&pdev->dev, "No platform data supplied\n");
-               return -EINVAL;
-       }
-
        machine = devm_kzalloc(&pdev->dev, sizeof(struct tegra_wm9712),
                               GFP_KERNEL);
        if (!machine) {
index 7fcf6c2..05c68aa 100644 (file)
@@ -97,9 +97,6 @@ static const struct snd_soc_dapm_route trimslice_audio_map[] = {
 static struct snd_soc_dai_link trimslice_tlv320aic23_dai = {
        .name = "TLV320AIC23",
        .stream_name = "AIC23",
-       .codec_name = "tlv320aic23-codec.2-001a",
-       .platform_name = "tegra20-i2s.0",
-       .cpu_dai_name = "tegra20-i2s.0",
        .codec_dai_name = "tlv320aic23-hifi",
        .ops = &trimslice_asoc_ops,
        .dai_fmt = SND_SOC_DAIFMT_I2S |
@@ -122,6 +119,7 @@ static struct snd_soc_card snd_soc_trimslice = {
 
 static int tegra_snd_trimslice_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct snd_soc_card *card = &snd_soc_trimslice;
        struct tegra_trimslice *trimslice;
        int ret;
@@ -130,44 +128,38 @@ static int tegra_snd_trimslice_probe(struct platform_device *pdev)
                                 GFP_KERNEL);
        if (!trimslice) {
                dev_err(&pdev->dev, "Can't allocate tegra_trimslice\n");
-               ret = -ENOMEM;
+               return -ENOMEM;
+       }
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, trimslice);
+
+       trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!trimslice_tlv320aic23_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
                goto err;
        }
 
-       if (pdev->dev.of_node) {
-               trimslice_tlv320aic23_dai.codec_name = NULL;
-               trimslice_tlv320aic23_dai.codec_of_node = of_parse_phandle(
-                               pdev->dev.of_node, "nvidia,audio-codec", 0);
-               if (!trimslice_tlv320aic23_dai.codec_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,audio-codec' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               trimslice_tlv320aic23_dai.cpu_dai_name = NULL;
-               trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(
-                               pdev->dev.of_node, "nvidia,i2s-controller", 0);
-               if (!trimslice_tlv320aic23_dai.cpu_of_node) {
-                       dev_err(&pdev->dev,
-                               "Property 'nvidia,i2s-controller' missing or invalid\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               trimslice_tlv320aic23_dai.platform_name = NULL;
-               trimslice_tlv320aic23_dai.platform_of_node =
-                               trimslice_tlv320aic23_dai.cpu_of_node;
+       trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!trimslice_tlv320aic23_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
        }
 
+       trimslice_tlv320aic23_dai.platform_of_node =
+                       trimslice_tlv320aic23_dai.cpu_of_node;
+
        ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev);
        if (ret)
                goto err;
 
-       card->dev = &pdev->dev;
-       platform_set_drvdata(pdev, card);
-       snd_soc_card_set_drvdata(card, trimslice);
-
        ret = snd_soc_register_card(card);
        if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
index 16ab696..8a28403 100644 (file)
@@ -170,6 +170,10 @@ static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
        },
 };
 
+static const struct snd_soc_component_driver txx9aclc_ac97_component = {
+       .name           = "txx9aclc-ac97",
+};
+
 static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
 {
        struct txx9aclc_plat_drvdata *drvdata;
@@ -205,12 +209,13 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev)
        if (err < 0)
                return err;
 
-       return snd_soc_register_dai(&pdev->dev, &txx9aclc_ac97_dai);
+       return snd_soc_register_component(&pdev->dev, &txx9aclc_ac97_component,
+                                         &txx9aclc_ac97_dai, 1);
 }
 
 static int txx9aclc_ac97_dev_remove(struct platform_device *pdev)
 {
-       snd_soc_unregister_dai(&pdev->dev);
+       snd_soc_unregister_component(&pdev->dev);
        return 0;
 }
 
index 94a3e57..f1e8a5e 100644 (file)
@@ -768,6 +768,11 @@ static struct snd_soc_dai_driver ux500_msp_dai_drv[UX500_NBR_OF_DAI] = {
        },
 };
 
+static const struct snd_soc_component_driver ux500_msp_component = {
+       .name           = "ux500-msp",
+};
+
+
 static int ux500_msp_drv_probe(struct platform_device *pdev)
 {
        struct ux500_msp_i2s_drvdata *drvdata;
@@ -825,8 +830,8 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        }
        dev_set_drvdata(&pdev->dev, drvdata);
 
-       ret = snd_soc_register_dai(&pdev->dev,
-                               &ux500_msp_dai_drv[drvdata->msp->id]);
+       ret = snd_soc_register_component(&pdev->dev, &ux500_msp_component,
+                                        &ux500_msp_dai_drv[drvdata->msp->id], 1);
        if (ret < 0) {
                dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n",
                        __func__, drvdata->msp->id);
@@ -844,7 +849,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev)
        return 0;
 
 err_reg_plat:
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+       snd_soc_unregister_component(&pdev->dev);
 err_init_msp:
        clk_put(drvdata->clk);
 err_clk:
@@ -861,7 +866,7 @@ static int ux500_msp_drv_remove(struct platform_device *pdev)
 
        ux500_pcm_unregister_platform(pdev);
 
-       snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(ux500_msp_dai_drv));
+       snd_soc_unregister_component(&pdev->dev);
 
        devm_regulator_put(drvdata->reg_vape);
        prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s");
index 9c778d9..f531043 100644 (file)
 #define FRAME_PER_8_SLOTS                              138
 #define FRAME_PER_16_SLOTS                             277
 
-#ifndef CONFIG_SND_SOC_UX500_AB5500
 #define UX500_MSP_INTERNAL_CLOCK_FREQ  40000000
 #define UX500_MSP1_INTERNAL_CLOCK_FREQ UX500_MSP_INTERNAL_CLOCK_FREQ
-#else
-#define UX500_MSP_INTERNAL_CLOCK_FREQ 13000000
-#define UX500_MSP1_INTERNAL_CLOCK_FREQ (UX500_MSP_INTERNAL_CLOCK_FREQ * 2)
-#endif
 
 #define UX500_MSP_MIN_CHANNELS         1
 #define UX500_MSP_MAX_CHANNELS         8
index 846fa82..09b5364 100644 (file)
 #include "ux500_msp_i2s.h"
 #include "ux500_pcm.h"
 
-static struct snd_pcm_hardware ux500_pcm_hw_playback = {
-       .info = SNDRV_PCM_INFO_INTERLEAVED |
-               SNDRV_PCM_INFO_MMAP |
-               SNDRV_PCM_INFO_RESUME |
-               SNDRV_PCM_INFO_PAUSE,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE |
-               SNDRV_PCM_FMTBIT_U16_LE |
-               SNDRV_PCM_FMTBIT_S16_BE |
-               SNDRV_PCM_FMTBIT_U16_BE,
-       .rates = SNDRV_PCM_RATE_KNOT,
-       .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
-       .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
-       .channels_min = UX500_PLATFORM_MIN_CHANNELS,
-       .channels_max = UX500_PLATFORM_MAX_CHANNELS,
-       .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
-       .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
-       .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
-       .periods_min = UX500_PLATFORM_PERIODS_MIN,
-       .periods_max = UX500_PLATFORM_PERIODS_MAX,
-};
+#define UX500_PLATFORM_MIN_RATE 8000
+#define UX500_PLATFORM_MAX_RATE 48000
+
+#define UX500_PLATFORM_MIN_CHANNELS 1
+#define UX500_PLATFORM_MAX_CHANNELS 8
 
-static struct snd_pcm_hardware ux500_pcm_hw_capture = {
+#define UX500_PLATFORM_PERIODS_BYTES_MIN       128
+#define UX500_PLATFORM_PERIODS_BYTES_MAX       (64 * PAGE_SIZE)
+#define UX500_PLATFORM_PERIODS_MIN             2
+#define UX500_PLATFORM_PERIODS_MAX             48
+#define UX500_PLATFORM_BUFFER_BYTES_MAX                (2048 * PAGE_SIZE)
+
+static struct snd_pcm_hardware ux500_pcm_hw = {
        .info = SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_MMAP |
                SNDRV_PCM_INFO_RESUME |
@@ -59,8 +50,8 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
                SNDRV_PCM_FMTBIT_S16_BE |
                SNDRV_PCM_FMTBIT_U16_BE,
        .rates = SNDRV_PCM_RATE_KNOT,
-       .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
-       .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
+       .rate_min = UX500_PLATFORM_MIN_RATE,
+       .rate_max = UX500_PLATFORM_MAX_RATE,
        .channels_min = UX500_PLATFORM_MIN_CHANNELS,
        .channels_max = UX500_PLATFORM_MAX_CHANNELS,
        .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
@@ -90,8 +81,6 @@ static void ux500_pcm_dma_hw_free(struct device *dev,
 
 static int ux500_pcm_open(struct snd_pcm_substream *substream)
 {
-       int stream_id = substream->pstr->stream;
-       struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *dai = rtd->cpu_dai;
        struct device *dev = dai->dev;
@@ -104,26 +93,7 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
                snd_pcm_stream_str(substream));
 
        dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__);
-       if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_soc_set_runtime_hwparams(substream,
-                                       &ux500_pcm_hw_playback);
-       else
-               snd_soc_set_runtime_hwparams(substream,
-                                       &ux500_pcm_hw_capture);
-
-       /* ensure that buffer size is a multiple of period size */
-       ret = snd_pcm_hw_constraint_integer(runtime,
-                                       SNDRV_PCM_HW_PARAM_PERIODS);
-       if (ret < 0) {
-               dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
-               snd_pcm_stream_str(substream));
-       runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
-               ux500_pcm_hw_playback : ux500_pcm_hw_capture;
+       snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw);
 
        mem_data_width = STEDMA40_HALFWORD_WIDTH;
 
@@ -164,20 +134,6 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
                return ret;
        }
 
-       snd_dmaengine_pcm_set_data(substream, dma_cfg);
-
-       return 0;
-}
-
-static int ux500_pcm_close(struct snd_pcm_substream *substream)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *dai = rtd->cpu_dai;
-
-       dev_dbg(dai->dev, "%s: Enter\n", __func__);
-
-       snd_dmaengine_pcm_close(substream);
-
        return 0;
 }
 
@@ -255,7 +211,7 @@ static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
 
 static struct snd_pcm_ops ux500_pcm_ops = {
        .open           = ux500_pcm_open,
-       .close          = ux500_pcm_close,
+       .close          = snd_dmaengine_pcm_close,
        .ioctl          = snd_pcm_lib_ioctl,
        .hw_params      = ux500_pcm_hw_params,
        .hw_free        = ux500_pcm_hw_free,
index 76d3444..d76e1af 100644 (file)
 
 #include <linux/workqueue.h>
 
-#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
-#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
-#define UX500_PLATFORM_MIN_RATE_CAPTURE        8000
-#define UX500_PLATFORM_MAX_RATE_CAPTURE        48000
-
-#define UX500_PLATFORM_MIN_CHANNELS 1
-#define UX500_PLATFORM_MAX_CHANNELS 8
-
-#define UX500_PLATFORM_PERIODS_BYTES_MIN       128
-#define UX500_PLATFORM_PERIODS_BYTES_MAX       (64 * PAGE_SIZE)
-#define UX500_PLATFORM_PERIODS_MIN             2
-#define UX500_PLATFORM_PERIODS_MAX             48
-#define UX500_PLATFORM_BUFFER_BYTES_MAX                (2048 * PAGE_SIZE)
-
 int ux500_pcm_register_platform(struct platform_device *pdev);
 int ux500_pcm_unregister_platform(struct platform_device *pdev);
 
index adc68fe..f18013f 100644 (file)
@@ -1541,21 +1541,38 @@ int kvm_write_guest(struct kvm *kvm, gpa_t gpa, const void *data,
 }
 
 int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
-                             gpa_t gpa)
+                             gpa_t gpa, unsigned long len)
 {
        struct kvm_memslots *slots = kvm_memslots(kvm);
        int offset = offset_in_page(gpa);
-       gfn_t gfn = gpa >> PAGE_SHIFT;
+       gfn_t start_gfn = gpa >> PAGE_SHIFT;
+       gfn_t end_gfn = (gpa + len - 1) >> PAGE_SHIFT;
+       gfn_t nr_pages_needed = end_gfn - start_gfn + 1;
+       gfn_t nr_pages_avail;
 
        ghc->gpa = gpa;
        ghc->generation = slots->generation;
-       ghc->memslot = gfn_to_memslot(kvm, gfn);
-       ghc->hva = gfn_to_hva_many(ghc->memslot, gfn, NULL);
-       if (!kvm_is_error_hva(ghc->hva))
+       ghc->len = len;
+       ghc->memslot = gfn_to_memslot(kvm, start_gfn);
+       ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn, &nr_pages_avail);
+       if (!kvm_is_error_hva(ghc->hva) && nr_pages_avail >= nr_pages_needed) {
                ghc->hva += offset;
-       else
-               return -EFAULT;
-
+       } else {
+               /*
+                * If the requested region crosses two memslots, we still
+                * verify that the entire region is valid here.
+                */
+               while (start_gfn <= end_gfn) {
+                       ghc->memslot = gfn_to_memslot(kvm, start_gfn);
+                       ghc->hva = gfn_to_hva_many(ghc->memslot, start_gfn,
+                                                  &nr_pages_avail);
+                       if (kvm_is_error_hva(ghc->hva))
+                               return -EFAULT;
+                       start_gfn += nr_pages_avail;
+               }
+               /* Use the slow path for cross page reads and writes. */
+               ghc->memslot = NULL;
+       }
        return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_gfn_to_hva_cache_init);
@@ -1566,8 +1583,13 @@ int kvm_write_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
        struct kvm_memslots *slots = kvm_memslots(kvm);
        int r;
 
+       BUG_ON(len > ghc->len);
+
        if (slots->generation != ghc->generation)
-               kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa);
+               kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa, ghc->len);
+
+       if (unlikely(!ghc->memslot))
+               return kvm_write_guest(kvm, ghc->gpa, data, len);
 
        if (kvm_is_error_hva(ghc->hva))
                return -EFAULT;
@@ -1587,8 +1609,13 @@ int kvm_read_guest_cached(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
        struct kvm_memslots *slots = kvm_memslots(kvm);
        int r;
 
+       BUG_ON(len > ghc->len);
+
        if (slots->generation != ghc->generation)
-               kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa);
+               kvm_gfn_to_hva_cache_init(kvm, ghc, ghc->gpa, ghc->len);
+
+       if (unlikely(!ghc->memslot))
+               return kvm_read_guest(kvm, ghc->gpa, data, len);
 
        if (kvm_is_error_hva(ghc->hva))
                return -EFAULT;