]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'asoc-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound...
authorTakashi Iwai <tiwai@suse.de>
Mon, 20 Feb 2017 20:43:40 +0000 (21:43 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 20 Feb 2017 20:43:40 +0000 (21:43 +0100)
ASoC: Updates for v4.11

Another release that's mainly focused on drivers rather than core
changes, highlights include:

 - A huge batch of updates to the Intel drivers, mainly around
   DisplayPort and HDMI with some additional board support too.
 - Channel mapping support for HDMI.
 - Support for AllWinner A31 and A33, Everest Semiconductor ES8328,
   Nuvoton NAU8540.

275 files changed:
Documentation/gpu/i915.rst
MAINTAINERS
Makefile
arch/arm64/crypto/aes-modes.S
arch/powerpc/Kconfig
arch/powerpc/include/asm/cpu_has_feature.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/module.h
arch/powerpc/include/asm/stackprotector.h [deleted file]
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/entry_32.S
arch/powerpc/kernel/module_64.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/mm/pgtable-radix.c
arch/sparc/include/asm/mmu_context_64.h
arch/sparc/kernel/irq_64.c
arch/sparc/kernel/sstate.c
arch/sparc/kernel/traps_64.c
arch/x86/events/intel/rapl.c
arch/x86/events/intel/uncore.c
arch/x86/include/asm/microcode.h
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/microcode/amd.c
arch/x86/kernel/cpu/microcode/core.c
arch/x86/kernel/cpu/microcode/intel.c
arch/x86/kernel/fpu/core.c
arch/x86/kernel/hpet.c
arch/x86/kvm/x86.c
arch/x86/platform/efi/efi_64.c
arch/xtensa/kernel/setup.c
crypto/algapi.c
drivers/ata/libata-core.c
drivers/ata/sata_mv.c
drivers/base/firmware_class.c
drivers/base/memory.c
drivers/bcma/bcma_private.h
drivers/bcma/driver_chipcommon.c
drivers/bcma/driver_mips.c
drivers/dma/cppi41.c
drivers/dma/pl330.c
drivers/firmware/efi/libstub/fdt.c
drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c
drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_atomic_plane.c
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fbc.c
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_lpe_audio.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/nouveau/dispnv04/hw.c
drivers/gpu/drm/nouveau/nouveau_fence.h
drivers/gpu/drm/nouveau/nouveau_led.h
drivers/gpu/drm/nouveau/nouveau_usif.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/hid/hid-cp2112.c
drivers/hid/hid-ids.h
drivers/hid/hid-lg.c
drivers/hid/usbhid/hid-quirks.c
drivers/hid/wacom_wac.c
drivers/hv/ring_buffer.c
drivers/iio/adc/palmas_gpadc.c
drivers/iio/health/afe4403.c
drivers/iio/health/afe4404.c
drivers/iio/health/max30100.c
drivers/iio/humidity/dht11.c
drivers/input/rmi4/rmi_driver.c
drivers/input/touchscreen/wm97xx-core.c
drivers/mmc/host/sdhci.c
drivers/net/ethernet/adaptec/starfire.c
drivers/net/ethernet/cadence/macb.c
drivers/net/ethernet/cadence/macb.h
drivers/net/ethernet/cavium/thunder/thunder_xcv.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/mellanox/mlx4/catas.c
drivers/net/ethernet/mellanox/mlx4/intf.c
drivers/net/ethernet/mellanox/mlx4/mlx4.h
drivers/net/ethernet/mellanox/mlx5/core/cmd.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs.c
drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/port.c
drivers/net/ethernet/mellanox/mlx5/core/vport.c
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/hyperv/netvsc.c
drivers/net/phy/micrel.c
drivers/net/wireless/intel/iwlwifi/iwl-8000.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/tt.c
drivers/pci/pcie/aspm.c
drivers/pinctrl/berlin/berlin-bg4ct.c
drivers/pinctrl/intel/pinctrl-baytrail.c
drivers/pinctrl/intel/pinctrl-merrifield.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/regulator/axp20x-regulator.c
drivers/regulator/fixed.c
drivers/regulator/twl6030-regulator.c
drivers/rtc/Kconfig
drivers/rtc/rtc-jz4740.c
drivers/scsi/virtio_scsi.c
drivers/staging/greybus/timesync_platform.c
drivers/usb/core/quirks.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/qcserial.c
drivers/vfio/vfio_iommu_spapr_tce.c
drivers/vhost/vhost.c
drivers/virtio/virtio_ring.c
fs/cifs/readdir.c
fs/dax.c
fs/fscache/cookie.c
fs/fscache/netfs.c
fs/fscache/object.c
fs/iomap.c
fs/nfsd/nfs4layouts.c
fs/nfsd/nfs4state.c
fs/nfsd/state.h
fs/nfsd/vfs.c
include/asm-generic/export.h
include/drm/drmP.h
include/drm/drm_connector.h
include/drm/intel_lpe_audio.h [new file with mode: 0644]
include/linux/can/core.h
include/linux/cpuhotplug.h
include/linux/export.h
include/linux/fscache-cache.h
include/linux/hyperv.h
include/linux/irq.h
include/linux/log2.h
include/linux/memory_hotplug.h
include/linux/module.h
include/linux/netdevice.h
include/linux/percpu-refcount.h
include/net/ipv6.h
include/sound/pcm.h
include/sound/rawmidi.h
include/sound/snd_wavefront.h
include/uapi/linux/ethtool.h
init/Kconfig
kernel/cgroup.c
kernel/events/core.c
kernel/irq/irqdomain.c
kernel/module.c
kernel/trace/trace_hwlat.c
kernel/trace/trace_kprobe.c
mm/filemap.c
mm/kasan/report.c
mm/memory_hotplug.c
mm/shmem.c
mm/zswap.c
net/can/af_can.c
net/can/af_can.h
net/can/bcm.c
net/can/gw.c
net/can/raw.c
net/ipv4/tcp_output.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/sched/cls_flower.c
net/sched/cls_matchall.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
scripts/Makefile.build
scripts/genksyms/genksyms.c
scripts/kallsyms.c
scripts/mod/modpost.c
sound/Kconfig
sound/Makefile
sound/core/rawmidi.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_queue.c
sound/core/seq/seq_virmidi.c
sound/drivers/mpu401/mpu401_uart.c
sound/drivers/mtpav.c
sound/drivers/mts64.c
sound/drivers/portman2x4.c
sound/drivers/serial-u16550.c
sound/drivers/vx/vx_pcm.c
sound/firewire/Kconfig
sound/firewire/bebob/bebob_hwdep.c
sound/firewire/bebob/bebob_midi.c
sound/firewire/bebob/bebob_pcm.c
sound/firewire/dice/dice-interface.h
sound/firewire/dice/dice-midi.c
sound/firewire/dice/dice-stream.c
sound/firewire/digi00x/digi00x-hwdep.c
sound/firewire/digi00x/digi00x-midi.c
sound/firewire/digi00x/digi00x-pcm.c
sound/firewire/fireworks/fireworks_hwdep.c
sound/firewire/fireworks/fireworks_midi.c
sound/firewire/fireworks/fireworks_pcm.c
sound/firewire/oxfw/oxfw-midi.c
sound/firewire/oxfw/oxfw-scs1x.c
sound/firewire/oxfw/oxfw.c
sound/firewire/tascam/tascam-hwdep.c
sound/firewire/tascam/tascam-midi.c
sound/firewire/tascam/tascam-pcm.c
sound/isa/gus/gus_uart.c
sound/isa/msnd/msnd_midi.c
sound/isa/sb/sb8_midi.c
sound/isa/wavefront/wavefront_midi.c
sound/mips/hal2.c
sound/oss/ad1848.c
sound/pci/ca0106/ca_midi.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs5535audio/cs5535audio_pm.c
sound/pci/echoaudio/midi.c
sound/pci/emu10k1/emu10k1_callback.c
sound/pci/emu10k1/emu10k1x.c
sound/pci/emu10k1/emumpu401.c
sound/pci/ens1370.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_ca0132.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/ice1712/ice1724.c
sound/pci/mixart/mixart.h
sound/pci/rme9652/hdsp.c
sound/pci/rme9652/hdspm.c
sound/pci/vx222/vx222_ops.c
sound/pcmcia/vx/vxp_ops.c
sound/synth/emux/emux_seq.c
sound/usb/6fire/midi.c
sound/usb/Makefile
sound/usb/bcd2000/bcd2000.c
sound/usb/caiaq/midi.c
sound/usb/line6/driver.c
sound/usb/line6/midi.c
sound/usb/midi.c
sound/usb/mixer_quirks.c
sound/usb/mixer_us16x08.c [new file with mode: 0644]
sound/usb/mixer_us16x08.h [new file with mode: 0644]
sound/usb/quirks.c
sound/x86/Kconfig [new file with mode: 0644]
sound/x86/Makefile [new file with mode: 0644]
sound/x86/intel_hdmi_audio.c [new file with mode: 0644]
sound/x86/intel_hdmi_audio.h [new file with mode: 0644]
sound/x86/intel_hdmi_lpe_audio.h [new file with mode: 0644]
tools/objtool/arch/x86/decode.c

index 117d2ab7a5f73d0c28be683fefb66e3baca9b345..7fb605af090e8ade66a57f75d1efef926db5d195 100644 (file)
@@ -144,6 +144,15 @@ High Definition Audio
 .. kernel-doc:: include/drm/i915_component.h
    :internal:
 
+Intel HDMI LPE Audio Support
+----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c
+   :doc: LPE Audio integration for HDMI or DP playback
+
+.. kernel-doc:: drivers/gpu/drm/i915/intel_lpe_audio.c
+   :internal:
+
 Panel Self Refresh PSR (PSR/SRD)
 --------------------------------
 
index 5f10c28b2e158fbcd05f86832062c66121370d73..187b9615e31a85d49fcd10ca96f4f20e19272652 100644 (file)
@@ -10195,7 +10195,6 @@ F:      drivers/media/tuners/qt1010*
 QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
 M:     QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
 L:     linux-wireless@vger.kernel.org
-L:     ath9k-devel@lists.ath9k.org
 W:     http://wireless.kernel.org/en/users/Drivers/ath9k
 S:     Supported
 F:     drivers/net/wireless/ath/ath9k/
@@ -13066,7 +13065,7 @@ F:      drivers/input/serio/userio.c
 F:     include/uapi/linux/userio.h
 
 VIRTIO CONSOLE DRIVER
-M:     Amit Shah <amit.shah@redhat.com>
+M:     Amit Shah <amit@kernel.org>
 L:     virtualization@lists.linux-foundation.org
 S:     Maintained
 F:     drivers/char/virtio_console.c
index 96b27a888285c5258dc57f666b2876fcece1a1aa..8e223e081c9d3b28f1b19c9472c1970bc0c19234 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 4
 PATCHLEVEL = 10
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc7
 NAME = Fearless Coyote
 
 # *DOCUMENTATION*
@@ -797,7 +797,7 @@ KBUILD_CFLAGS   += $(call cc-option,-Werror=incompatible-pointer-types)
 KBUILD_ARFLAGS := $(call ar-option,D)
 
 # check for 'asm goto'
-ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y)
        KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
        KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO
 endif
index c53dbeae79f2f5fce8353b169e96ff6c79294aa5..838dad5c209fae0f3a660e79d1f5fef8eb1f0c68 100644 (file)
@@ -193,15 +193,16 @@ AES_ENTRY(aes_cbc_encrypt)
        cbz             w6, .Lcbcencloop
 
        ld1             {v0.16b}, [x5]                  /* get iv */
-       enc_prepare     w3, x2, x5
+       enc_prepare     w3, x2, x6
 
 .Lcbcencloop:
        ld1             {v1.16b}, [x1], #16             /* get next pt block */
        eor             v0.16b, v0.16b, v1.16b          /* ..and xor with iv */
-       encrypt_block   v0, w3, x2, x5, w6
+       encrypt_block   v0, w3, x2, x6, w7
        st1             {v0.16b}, [x0], #16
        subs            w4, w4, #1
        bne             .Lcbcencloop
+       st1             {v0.16b}, [x5]                  /* return iv */
        ret
 AES_ENDPROC(aes_cbc_encrypt)
 
@@ -211,7 +212,7 @@ AES_ENTRY(aes_cbc_decrypt)
        cbz             w6, .LcbcdecloopNx
 
        ld1             {v7.16b}, [x5]                  /* get iv */
-       dec_prepare     w3, x2, x5
+       dec_prepare     w3, x2, x6
 
 .LcbcdecloopNx:
 #if INTERLEAVE >= 2
@@ -248,7 +249,7 @@ AES_ENTRY(aes_cbc_decrypt)
 .Lcbcdecloop:
        ld1             {v1.16b}, [x1], #16             /* get next ct block */
        mov             v0.16b, v1.16b                  /* ...and copy to v0 */
-       decrypt_block   v0, w3, x2, x5, w6
+       decrypt_block   v0, w3, x2, x6, w7
        eor             v0.16b, v0.16b, v7.16b          /* xor with iv => pt */
        mov             v7.16b, v1.16b                  /* ct is next iv */
        st1             {v0.16b}, [x0], #16
@@ -256,6 +257,7 @@ AES_ENTRY(aes_cbc_decrypt)
        bne             .Lcbcdecloop
 .Lcbcdecout:
        FRAME_POP
+       st1             {v7.16b}, [x5]                  /* return iv */
        ret
 AES_ENDPROC(aes_cbc_decrypt)
 
@@ -267,24 +269,15 @@ AES_ENDPROC(aes_cbc_decrypt)
 
 AES_ENTRY(aes_ctr_encrypt)
        FRAME_PUSH
-       cbnz            w6, .Lctrfirst          /* 1st time around? */
-       umov            x5, v4.d[1]             /* keep swabbed ctr in reg */
-       rev             x5, x5
-#if INTERLEAVE >= 2
-       cmn             w5, w4                  /* 32 bit overflow? */
-       bcs             .Lctrinc
-       add             x5, x5, #1              /* increment BE ctr */
-       b               .LctrincNx
-#else
-       b               .Lctrinc
-#endif
-.Lctrfirst:
+       cbz             w6, .Lctrnotfirst       /* 1st time around? */
        enc_prepare     w3, x2, x6
        ld1             {v4.16b}, [x5]
-       umov            x5, v4.d[1]             /* keep swabbed ctr in reg */
-       rev             x5, x5
+
+.Lctrnotfirst:
+       umov            x8, v4.d[1]             /* keep swabbed ctr in reg */
+       rev             x8, x8
 #if INTERLEAVE >= 2
-       cmn             w5, w4                  /* 32 bit overflow? */
+       cmn             w8, w4                  /* 32 bit overflow? */
        bcs             .Lctrloop
 .LctrloopNx:
        subs            w4, w4, #INTERLEAVE
@@ -292,11 +285,11 @@ AES_ENTRY(aes_ctr_encrypt)
 #if INTERLEAVE == 2
        mov             v0.8b, v4.8b
        mov             v1.8b, v4.8b
-       rev             x7, x5
-       add             x5, x5, #1
+       rev             x7, x8
+       add             x8, x8, #1
        ins             v0.d[1], x7
-       rev             x7, x5
-       add             x5, x5, #1
+       rev             x7, x8
+       add             x8, x8, #1
        ins             v1.d[1], x7
        ld1             {v2.16b-v3.16b}, [x1], #32      /* get 2 input blocks */
        do_encrypt_block2x
@@ -305,7 +298,7 @@ AES_ENTRY(aes_ctr_encrypt)
        st1             {v0.16b-v1.16b}, [x0], #32
 #else
        ldr             q8, =0x30000000200000001        /* addends 1,2,3[,0] */
-       dup             v7.4s, w5
+       dup             v7.4s, w8
        mov             v0.16b, v4.16b
        add             v7.4s, v7.4s, v8.4s
        mov             v1.16b, v4.16b
@@ -323,18 +316,12 @@ AES_ENTRY(aes_ctr_encrypt)
        eor             v2.16b, v7.16b, v2.16b
        eor             v3.16b, v5.16b, v3.16b
        st1             {v0.16b-v3.16b}, [x0], #64
-       add             x5, x5, #INTERLEAVE
+       add             x8, x8, #INTERLEAVE
 #endif
-       cbz             w4, .LctroutNx
-.LctrincNx:
-       rev             x7, x5
+       rev             x7, x8
        ins             v4.d[1], x7
+       cbz             w4, .Lctrout
        b               .LctrloopNx
-.LctroutNx:
-       sub             x5, x5, #1
-       rev             x7, x5
-       ins             v4.d[1], x7
-       b               .Lctrout
 .Lctr1x:
        adds            w4, w4, #INTERLEAVE
        beq             .Lctrout
@@ -342,30 +329,39 @@ AES_ENTRY(aes_ctr_encrypt)
 .Lctrloop:
        mov             v0.16b, v4.16b
        encrypt_block   v0, w3, x2, x6, w7
+
+       adds            x8, x8, #1              /* increment BE ctr */
+       rev             x7, x8
+       ins             v4.d[1], x7
+       bcs             .Lctrcarry              /* overflow? */
+
+.Lctrcarrydone:
        subs            w4, w4, #1
        bmi             .Lctrhalfblock          /* blocks < 0 means 1/2 block */
        ld1             {v3.16b}, [x1], #16
        eor             v3.16b, v0.16b, v3.16b
        st1             {v3.16b}, [x0], #16
-       beq             .Lctrout
-.Lctrinc:
-       adds            x5, x5, #1              /* increment BE ctr */
-       rev             x7, x5
-       ins             v4.d[1], x7
-       bcc             .Lctrloop               /* no overflow? */
-       umov            x7, v4.d[0]             /* load upper word of ctr  */
-       rev             x7, x7                  /* ... to handle the carry */
-       add             x7, x7, #1
-       rev             x7, x7
-       ins             v4.d[0], x7
-       b               .Lctrloop
+       bne             .Lctrloop
+
+.Lctrout:
+       st1             {v4.16b}, [x5]          /* return next CTR value */
+       FRAME_POP
+       ret
+
 .Lctrhalfblock:
        ld1             {v3.8b}, [x1]
        eor             v3.8b, v0.8b, v3.8b
        st1             {v3.8b}, [x0]
-.Lctrout:
        FRAME_POP
        ret
+
+.Lctrcarry:
+       umov            x7, v4.d[0]             /* load upper word of ctr  */
+       rev             x7, x7                  /* ... to handle the carry */
+       add             x7, x7, #1
+       rev             x7, x7
+       ins             v4.d[0], x7
+       b               .Lctrcarrydone
 AES_ENDPROC(aes_ctr_encrypt)
        .ltorg
 
index a8ee573fe610bd5e2d8191b4dffb05e134a6d3c2..281f4f1fcd1f68ab2fbc613afa3f2597bd090550 100644 (file)
@@ -164,7 +164,6 @@ config PPC
        select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE
        select HAVE_ARCH_HARDENED_USERCOPY
        select HAVE_KERNEL_GZIP
-       select HAVE_CC_STACKPROTECTOR
 
 config GENERIC_CSUM
        def_bool CPU_LITTLE_ENDIAN
@@ -484,6 +483,7 @@ config RELOCATABLE
        bool "Build a relocatable kernel"
        depends on (PPC64 && !COMPILE_TEST) || (FLATMEM && (44x || FSL_BOOKE))
        select NONSTATIC_KERNEL
+       select MODULE_REL_CRCS if MODVERSIONS
        help
          This builds a kernel image that is capable of running at the
          location the kernel is loaded at. For ppc32, there is no any
index b312b152461b0539a22c5939ba7728a38f5d8d32..6e834caa37206a476792823463e81ac4c9617f9c 100644 (file)
@@ -23,7 +23,9 @@ static __always_inline bool cpu_has_feature(unsigned long feature)
 {
        int i;
 
+#ifndef __clang__ /* clang can't cope with this */
        BUILD_BUG_ON(!__builtin_constant_p(feature));
+#endif
 
 #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG
        if (!static_key_initialized) {
index a34c764ca8dd83435faf75307e30e5149e55de4b..233a7e8cc8e32d6cf0ac904b3f02b2f340e3883b 100644 (file)
@@ -160,7 +160,9 @@ static __always_inline bool mmu_has_feature(unsigned long feature)
 {
        int i;
 
+#ifndef __clang__ /* clang can't cope with this */
        BUILD_BUG_ON(!__builtin_constant_p(feature));
+#endif
 
 #ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG
        if (!static_key_initialized) {
index cc12c61ef315fc6ca5d43233bd54889cd19a01a0..53885512b8d31b12acec28dc3ba6688e57fb9615 100644 (file)
@@ -90,9 +90,5 @@ static inline int module_finalize_ftrace(struct module *mod, const Elf_Shdr *sec
 }
 #endif
 
-#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
-#define ARCH_RELOCATES_KCRCTAB
-#define reloc_start PHYSICAL_START
-#endif
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_MODULE_H */
diff --git a/arch/powerpc/include/asm/stackprotector.h b/arch/powerpc/include/asm/stackprotector.h
deleted file mode 100644 (file)
index 6720190..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * GCC stack protector support.
- *
- * Stack protector works by putting predefined pattern at the start of
- * the stack frame and verifying that it hasn't been overwritten when
- * returning from the function.  The pattern is called stack canary
- * and gcc expects it to be defined by a global variable called
- * "__stack_chk_guard" on PPC.  This unfortunately means that on SMP
- * we cannot have a different canary value per task.
- */
-
-#ifndef _ASM_STACKPROTECTOR_H
-#define _ASM_STACKPROTECTOR_H
-
-#include <linux/random.h>
-#include <linux/version.h>
-#include <asm/reg.h>
-
-extern unsigned long __stack_chk_guard;
-
-/*
- * Initialize the stackprotector canary value.
- *
- * NOTE: this must only be called from functions that never return,
- * and it must always be inlined.
- */
-static __always_inline void boot_init_stack_canary(void)
-{
-       unsigned long canary;
-
-       /* Try to get a semi random initial value. */
-       get_random_bytes(&canary, sizeof(canary));
-       canary ^= mftb();
-       canary ^= LINUX_VERSION_CODE;
-
-       current->stack_canary = canary;
-       __stack_chk_guard = current->stack_canary;
-}
-
-#endif /* _ASM_STACKPROTECTOR_H */
index 23f8082d7bfad95f4c9fbb8201e3e58c3104928f..f4c2b52e58b36eb44bcb6be2a2428bc0458f7660 100644 (file)
@@ -19,10 +19,6 @@ CFLAGS_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
 
-# -fstack-protector triggers protection checks in this code,
-# but it is being used too early to link to meaningful stack_chk logic.
-CFLAGS_prom_init.o += $(call cc-option, -fno-stack-protector)
-
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace early boot code
 CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE)
index 0601e6a7297c64ea4b2129011d32ae42a662ac07..195a9fc8f81c8fc41fca8b05239948d4f28d54af 100644 (file)
@@ -91,9 +91,6 @@ int main(void)
        DEFINE(TI_livepatch_sp, offsetof(struct thread_info, livepatch_sp));
 #endif
 
-#ifdef CONFIG_CC_STACKPROTECTOR
-       DEFINE(TSK_STACK_CANARY, offsetof(struct task_struct, stack_canary));
-#endif
        DEFINE(KSP, offsetof(struct thread_struct, ksp));
        DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
 #ifdef CONFIG_BOOKE
index d88573bdd0907c6682cf03395bc296155cea9124..b94887165a101557c97fd6a53139ae7df67dbbd9 100644 (file)
@@ -545,7 +545,7 @@ static void *eeh_pe_detach_dev(void *data, void *userdata)
 static void *__eeh_clear_pe_frozen_state(void *data, void *flag)
 {
        struct eeh_pe *pe = (struct eeh_pe *)data;
-       bool *clear_sw_state = flag;
+       bool clear_sw_state = *(bool *)flag;
        int i, rc = 1;
 
        for (i = 0; rc && i < 3; i++)
index 5742dbdbee4677924ebf0019b891e43879410131..3841d749a430069f4d4f2705c4199c08609b3757 100644 (file)
@@ -674,11 +674,7 @@ BEGIN_FTR_SECTION
        mtspr   SPRN_SPEFSCR,r0         /* restore SPEFSCR reg */
 END_FTR_SECTION_IFSET(CPU_FTR_SPE)
 #endif /* CONFIG_SPE */
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
-       lwz     r0,TSK_STACK_CANARY(r2)
-       lis     r4,__stack_chk_guard@ha
-       stw     r0,__stack_chk_guard@l(r4)
-#endif
+
        lwz     r0,_CCR(r1)
        mtcrf   0xFF,r0
        /* r3-r12 are destroyed -- Cort */
index bb1807184bad5da5f9b65ce69087184e67534c03..0b0f89685b679745895251b011d0db522d4558e1 100644 (file)
@@ -286,14 +286,6 @@ static void dedotify_versions(struct modversion_info *vers,
        for (end = (void *)vers + size; vers < end; vers++)
                if (vers->name[0] == '.') {
                        memmove(vers->name, vers->name+1, strlen(vers->name));
-#ifdef ARCH_RELOCATES_KCRCTAB
-                       /* The TOC symbol has no CRC computed. To avoid CRC
-                        * check failing, we must force it to the expected
-                        * value (see CRC check in module.c).
-                        */
-                       if (!strcmp(vers->name, "TOC."))
-                               vers->crc = -(unsigned long)reloc_start;
-#endif
                }
 }
 
index 04885cec24df1413f90121115cf6569e4aa444e6..5dd056df0baaec576431adb4cbe8ab370d8f44c1 100644 (file)
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 
-#ifdef CONFIG_CC_STACKPROTECTOR
-#include <linux/stackprotector.h>
-unsigned long __stack_chk_guard __read_mostly;
-EXPORT_SYMBOL(__stack_chk_guard);
-#endif
-
 /* Transactional Memory debug */
 #ifdef TM_DEBUG_SW
 #define TM_DEBUG(x...) printk(KERN_INFO x)
index ec47a939cbdd6dd81c6c05ed6707f28e12d9f0ea..ac83eb04a8b871293c53e7bd6ff4d439b89704a9 100644 (file)
@@ -2834,6 +2834,9 @@ static void __init prom_find_boot_cpu(void)
 
        cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
 
+       if (!PHANDLE_VALID(cpu_pkg))
+               return;
+
        prom_getprop(cpu_pkg, "reg", &rval, sizeof(rval));
        prom.cpu = be32_to_cpu(rval);
 
index cfa53ccc8bafc908e80532a4a64e44ad358dffc7..34f1a0dbc898ee4a28a6adcd41c0ce5d3fe61198 100644 (file)
@@ -65,7 +65,7 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,
                if (!pmdp)
                        return -ENOMEM;
                if (map_page_size == PMD_SIZE) {
-                       ptep = (pte_t *)pudp;
+                       ptep = pmdp_ptep(pmdp);
                        goto set_the_pte;
                }
                ptep = pte_alloc_kernel(pmdp, ea);
@@ -90,7 +90,7 @@ int radix__map_kernel_page(unsigned long ea, unsigned long pa,
                }
                pmdp = pmd_offset(pudp, ea);
                if (map_page_size == PMD_SIZE) {
-                       ptep = (pte_t *)pudp;
+                       ptep = pmdp_ptep(pmdp);
                        goto set_the_pte;
                }
                if (!pmd_present(*pmdp)) {
index b84be675e507857e27766b6339e438270aea0ebe..d0317993e9476fd1178a693638d9ede23860171b 100644 (file)
@@ -35,15 +35,15 @@ void __tsb_context_switch(unsigned long pgd_pa,
 static inline void tsb_context_switch(struct mm_struct *mm)
 {
        __tsb_context_switch(__pa(mm->pgd),
-                            &mm->context.tsb_block[0],
+                            &mm->context.tsb_block[MM_TSB_BASE],
 #if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
-                            (mm->context.tsb_block[1].tsb ?
-                             &mm->context.tsb_block[1] :
+                            (mm->context.tsb_block[MM_TSB_HUGE].tsb ?
+                             &mm->context.tsb_block[MM_TSB_HUGE] :
                              NULL)
 #else
                             NULL
 #endif
-                            , __pa(&mm->context.tsb_descr[0]));
+                            , __pa(&mm->context.tsb_descr[MM_TSB_BASE]));
 }
 
 void tsb_grow(struct mm_struct *mm,
index 3bebf395252cc63ee3b39996f8a0d0431e7faf37..4d0248aa0928695597161d93f325a49311b43e2c 100644 (file)
@@ -1021,7 +1021,7 @@ static void __init alloc_one_queue(unsigned long *pa_ptr, unsigned long qmask)
        unsigned long order = get_order(size);
        unsigned long p;
 
-       p = __get_free_pages(GFP_KERNEL, order);
+       p = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
        if (!p) {
                prom_printf("SUN4V: Error, cannot allocate queue.\n");
                prom_halt();
index c59af546f522999342361a5babcb64a1dfab3ccd..3caed40235898698751ff0cf3d6ca7d98dc83da6 100644 (file)
@@ -43,8 +43,8 @@ static const char poweroff_msg[32] __attribute__((aligned(32))) =
        "Linux powering off";
 static const char rebooting_msg[32] __attribute__((aligned(32))) =
        "Linux rebooting";
-static const char panicing_msg[32] __attribute__((aligned(32))) =
-       "Linux panicing";
+static const char panicking_msg[32] __attribute__((aligned(32))) =
+       "Linux panicking";
 
 static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
 {
@@ -76,7 +76,7 @@ static struct notifier_block sstate_reboot_notifier = {
 
 static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
 {
-       do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
+       do_set_sstate(HV_SOFT_STATE_TRANSITION, panicking_msg);
 
        return NOTIFY_DONE;
 }
index 4bc10e44d1ca32a0acdf69b8492e128e7ef0e600..dfc97a47c9a08a330f31040fe120030ebe8cc098 100644 (file)
@@ -2051,6 +2051,73 @@ void sun4v_resum_overflow(struct pt_regs *regs)
        atomic_inc(&sun4v_resum_oflow_cnt);
 }
 
+/* Given a set of registers, get the virtual addressi that was being accessed
+ * by the faulting instructions at tpc.
+ */
+static unsigned long sun4v_get_vaddr(struct pt_regs *regs)
+{
+       unsigned int insn;
+
+       if (!copy_from_user(&insn, (void __user *)regs->tpc, 4)) {
+               return compute_effective_address(regs, insn,
+                                                (insn >> 25) & 0x1f);
+       }
+       return 0;
+}
+
+/* Attempt to handle non-resumable errors generated from userspace.
+ * Returns true if the signal was handled, false otherwise.
+ */
+bool sun4v_nonresum_error_user_handled(struct pt_regs *regs,
+                                 struct sun4v_error_entry *ent) {
+
+       unsigned int attrs = ent->err_attrs;
+
+       if (attrs & SUN4V_ERR_ATTRS_MEMORY) {
+               unsigned long addr = ent->err_raddr;
+               siginfo_t info;
+
+               if (addr == ~(u64)0) {
+                       /* This seems highly unlikely to ever occur */
+                       pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory error detected in unknown location!\n");
+               } else {
+                       unsigned long page_cnt = DIV_ROUND_UP(ent->err_size,
+                                                             PAGE_SIZE);
+
+                       /* Break the unfortunate news. */
+                       pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory failed at %016lX\n",
+                                addr);
+                       pr_emerg("SUN4V NON-RECOVERABLE ERROR:   Claiming %lu ages.\n",
+                                page_cnt);
+
+                       while (page_cnt-- > 0) {
+                               if (pfn_valid(addr >> PAGE_SHIFT))
+                                       get_page(pfn_to_page(addr >> PAGE_SHIFT));
+                               addr += PAGE_SIZE;
+                       }
+               }
+               info.si_signo = SIGKILL;
+               info.si_errno = 0;
+               info.si_trapno = 0;
+               force_sig_info(info.si_signo, &info, current);
+
+               return true;
+       }
+       if (attrs & SUN4V_ERR_ATTRS_PIO) {
+               siginfo_t info;
+
+               info.si_signo = SIGBUS;
+               info.si_code = BUS_ADRERR;
+               info.si_addr = (void __user *)sun4v_get_vaddr(regs);
+               force_sig_info(info.si_signo, &info, current);
+
+               return true;
+       }
+
+       /* Default to doing nothing */
+       return false;
+}
+
 /* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate.
  * Log the event, clear the first word of the entry, and die.
  */
@@ -2075,6 +2142,12 @@ void sun4v_nonresum_error(struct pt_regs *regs, unsigned long offset)
 
        put_cpu();
 
+       if (!(regs->tstate & TSTATE_PRIV) &&
+           sun4v_nonresum_error_user_handled(regs, &local_copy)) {
+               /* DON'T PANIC: This userspace error was handled. */
+               return;
+       }
+
 #ifdef CONFIG_PCI
        /* Check for the special PCI poke sequence. */
        if (pci_poke_in_progress && pci_poke_cpu == cpu) {
index 17c3564d087a48bc24e41417fe6f128b5d7b9f0d..22ef4f72cf320adf510545ce08fd342bc89839d2 100644 (file)
@@ -161,7 +161,13 @@ static u64 rapl_timer_ms;
 
 static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
 {
-       return rapl_pmus->pmus[topology_logical_package_id(cpu)];
+       unsigned int pkgid = topology_logical_package_id(cpu);
+
+       /*
+        * The unsigned check also catches the '-1' return value for non
+        * existent mappings in the topology map.
+        */
+       return pkgid < rapl_pmus->maxpkg ? rapl_pmus->pmus[pkgid] : NULL;
 }
 
 static inline u64 rapl_read_counter(struct perf_event *event)
@@ -402,6 +408,8 @@ static int rapl_pmu_event_init(struct perf_event *event)
 
        /* must be done before validate_group */
        pmu = cpu_to_rapl_pmu(event->cpu);
+       if (!pmu)
+               return -EINVAL;
        event->cpu = pmu->cpu;
        event->pmu_private = pmu;
        event->hw.event_base = msr;
@@ -585,6 +593,20 @@ static int rapl_cpu_online(unsigned int cpu)
        struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
        int target;
 
+       if (!pmu) {
+               pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
+               if (!pmu)
+                       return -ENOMEM;
+
+               raw_spin_lock_init(&pmu->lock);
+               INIT_LIST_HEAD(&pmu->active_list);
+               pmu->pmu = &rapl_pmus->pmu;
+               pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
+               rapl_hrtimer_init(pmu);
+
+               rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
+       }
+
        /*
         * Check if there is an online cpu in the package which collects rapl
         * events already.
@@ -598,27 +620,6 @@ static int rapl_cpu_online(unsigned int cpu)
        return 0;
 }
 
-static int rapl_cpu_prepare(unsigned int cpu)
-{
-       struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
-
-       if (pmu)
-               return 0;
-
-       pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
-       if (!pmu)
-               return -ENOMEM;
-
-       raw_spin_lock_init(&pmu->lock);
-       INIT_LIST_HEAD(&pmu->active_list);
-       pmu->pmu = &rapl_pmus->pmu;
-       pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
-       pmu->cpu = -1;
-       rapl_hrtimer_init(pmu);
-       rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
-       return 0;
-}
-
 static int rapl_check_hw_unit(bool apply_quirk)
 {
        u64 msr_rapl_power_unit_bits;
@@ -803,29 +804,21 @@ static int __init rapl_pmu_init(void)
        /*
         * Install callbacks. Core will call them for each online cpu.
         */
-
-       ret = cpuhp_setup_state(CPUHP_PERF_X86_RAPL_PREP, "perf/x86/rapl:prepare",
-                               rapl_cpu_prepare, NULL);
-       if (ret)
-               goto out;
-
        ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
                                "perf/x86/rapl:online",
                                rapl_cpu_online, rapl_cpu_offline);
        if (ret)
-               goto out1;
+               goto out;
 
        ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
        if (ret)
-               goto out2;
+               goto out1;
 
        rapl_advertise();
        return 0;
 
-out2:
-       cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
 out1:
-       cpuhp_remove_state(CPUHP_PERF_X86_RAPL_PREP);
+       cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
 out:
        pr_warn("Initialization failed (%d), disabled\n", ret);
        cleanup_rapl_pmus();
@@ -836,7 +829,6 @@ module_init(rapl_pmu_init);
 static void __exit intel_rapl_exit(void)
 {
        cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
-       cpuhp_remove_state_nocalls(CPUHP_PERF_X86_RAPL_PREP);
        perf_pmu_unregister(&rapl_pmus->pmu);
        cleanup_rapl_pmus();
 }
index 8c4ccdc3a3f3607ee0af4f4006029df3000e0839..1ab45976474d52597700b291e24b0b0a235dff03 100644 (file)
@@ -100,7 +100,13 @@ ssize_t uncore_event_show(struct kobject *kobj,
 
 struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
 {
-       return pmu->boxes[topology_logical_package_id(cpu)];
+       unsigned int pkgid = topology_logical_package_id(cpu);
+
+       /*
+        * The unsigned check also catches the '-1' return value for non
+        * existent mappings in the topology map.
+        */
+       return pkgid < max_packages ? pmu->boxes[pkgid] : NULL;
 }
 
 u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
@@ -764,30 +770,6 @@ static void uncore_pmu_unregister(struct intel_uncore_pmu *pmu)
        pmu->registered = false;
 }
 
-static void __uncore_exit_boxes(struct intel_uncore_type *type, int cpu)
-{
-       struct intel_uncore_pmu *pmu = type->pmus;
-       struct intel_uncore_box *box;
-       int i, pkg;
-
-       if (pmu) {
-               pkg = topology_physical_package_id(cpu);
-               for (i = 0; i < type->num_boxes; i++, pmu++) {
-                       box = pmu->boxes[pkg];
-                       if (box)
-                               uncore_box_exit(box);
-               }
-       }
-}
-
-static void uncore_exit_boxes(void *dummy)
-{
-       struct intel_uncore_type **types;
-
-       for (types = uncore_msr_uncores; *types; types++)
-               __uncore_exit_boxes(*types++, smp_processor_id());
-}
-
 static void uncore_free_boxes(struct intel_uncore_pmu *pmu)
 {
        int pkg;
@@ -1058,86 +1040,6 @@ static void uncore_pci_exit(void)
        }
 }
 
-static int uncore_cpu_dying(unsigned int cpu)
-{
-       struct intel_uncore_type *type, **types = uncore_msr_uncores;
-       struct intel_uncore_pmu *pmu;
-       struct intel_uncore_box *box;
-       int i, pkg;
-
-       pkg = topology_logical_package_id(cpu);
-       for (; *types; types++) {
-               type = *types;
-               pmu = type->pmus;
-               for (i = 0; i < type->num_boxes; i++, pmu++) {
-                       box = pmu->boxes[pkg];
-                       if (box && atomic_dec_return(&box->refcnt) == 0)
-                               uncore_box_exit(box);
-               }
-       }
-       return 0;
-}
-
-static int first_init;
-
-static int uncore_cpu_starting(unsigned int cpu)
-{
-       struct intel_uncore_type *type, **types = uncore_msr_uncores;
-       struct intel_uncore_pmu *pmu;
-       struct intel_uncore_box *box;
-       int i, pkg, ncpus = 1;
-
-       if (first_init) {
-               /*
-                * On init we get the number of online cpus in the package
-                * and set refcount for all of them.
-                */
-               ncpus = cpumask_weight(topology_core_cpumask(cpu));
-       }
-
-       pkg = topology_logical_package_id(cpu);
-       for (; *types; types++) {
-               type = *types;
-               pmu = type->pmus;
-               for (i = 0; i < type->num_boxes; i++, pmu++) {
-                       box = pmu->boxes[pkg];
-                       if (!box)
-                               continue;
-                       /* The first cpu on a package activates the box */
-                       if (atomic_add_return(ncpus, &box->refcnt) == ncpus)
-                               uncore_box_init(box);
-               }
-       }
-
-       return 0;
-}
-
-static int uncore_cpu_prepare(unsigned int cpu)
-{
-       struct intel_uncore_type *type, **types = uncore_msr_uncores;
-       struct intel_uncore_pmu *pmu;
-       struct intel_uncore_box *box;
-       int i, pkg;
-
-       pkg = topology_logical_package_id(cpu);
-       for (; *types; types++) {
-               type = *types;
-               pmu = type->pmus;
-               for (i = 0; i < type->num_boxes; i++, pmu++) {
-                       if (pmu->boxes[pkg])
-                               continue;
-                       /* First cpu of a package allocates the box */
-                       box = uncore_alloc_box(type, cpu_to_node(cpu));
-                       if (!box)
-                               return -ENOMEM;
-                       box->pmu = pmu;
-                       box->pkgid = pkg;
-                       pmu->boxes[pkg] = box;
-               }
-       }
-       return 0;
-}
-
 static void uncore_change_type_ctx(struct intel_uncore_type *type, int old_cpu,
                                   int new_cpu)
 {
@@ -1177,12 +1079,14 @@ static void uncore_change_context(struct intel_uncore_type **uncores,
 
 static int uncore_event_cpu_offline(unsigned int cpu)
 {
-       int target;
+       struct intel_uncore_type *type, **types = uncore_msr_uncores;
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       int i, pkg, target;
 
        /* Check if exiting cpu is used for collecting uncore events */
        if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
-               return 0;
-
+               goto unref;
        /* Find a new cpu to collect uncore events */
        target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
 
@@ -1194,12 +1098,82 @@ static int uncore_event_cpu_offline(unsigned int cpu)
 
        uncore_change_context(uncore_msr_uncores, cpu, target);
        uncore_change_context(uncore_pci_uncores, cpu, target);
+
+unref:
+       /* Clear the references */
+       pkg = topology_logical_package_id(cpu);
+       for (; *types; types++) {
+               type = *types;
+               pmu = type->pmus;
+               for (i = 0; i < type->num_boxes; i++, pmu++) {
+                       box = pmu->boxes[pkg];
+                       if (box && atomic_dec_return(&box->refcnt) == 0)
+                               uncore_box_exit(box);
+               }
+       }
        return 0;
 }
 
+static int allocate_boxes(struct intel_uncore_type **types,
+                        unsigned int pkg, unsigned int cpu)
+{
+       struct intel_uncore_box *box, *tmp;
+       struct intel_uncore_type *type;
+       struct intel_uncore_pmu *pmu;
+       LIST_HEAD(allocated);
+       int i;
+
+       /* Try to allocate all required boxes */
+       for (; *types; types++) {
+               type = *types;
+               pmu = type->pmus;
+               for (i = 0; i < type->num_boxes; i++, pmu++) {
+                       if (pmu->boxes[pkg])
+                               continue;
+                       box = uncore_alloc_box(type, cpu_to_node(cpu));
+                       if (!box)
+                               goto cleanup;
+                       box->pmu = pmu;
+                       box->pkgid = pkg;
+                       list_add(&box->active_list, &allocated);
+               }
+       }
+       /* Install them in the pmus */
+       list_for_each_entry_safe(box, tmp, &allocated, active_list) {
+               list_del_init(&box->active_list);
+               box->pmu->boxes[pkg] = box;
+       }
+       return 0;
+
+cleanup:
+       list_for_each_entry_safe(box, tmp, &allocated, active_list) {
+               list_del_init(&box->active_list);
+               kfree(box);
+       }
+       return -ENOMEM;
+}
+
 static int uncore_event_cpu_online(unsigned int cpu)
 {
-       int target;
+       struct intel_uncore_type *type, **types = uncore_msr_uncores;
+       struct intel_uncore_pmu *pmu;
+       struct intel_uncore_box *box;
+       int i, ret, pkg, target;
+
+       pkg = topology_logical_package_id(cpu);
+       ret = allocate_boxes(types, pkg, cpu);
+       if (ret)
+               return ret;
+
+       for (; *types; types++) {
+               type = *types;
+               pmu = type->pmus;
+               for (i = 0; i < type->num_boxes; i++, pmu++) {
+                       box = pmu->boxes[pkg];
+                       if (!box && atomic_inc_return(&box->refcnt) == 1)
+                               uncore_box_init(box);
+               }
+       }
 
        /*
         * Check if there is an online cpu in the package
@@ -1389,38 +1363,16 @@ static int __init intel_uncore_init(void)
        if (cret && pret)
                return -ENODEV;
 
-       /*
-        * Install callbacks. Core will call them for each online cpu.
-        *
-        * The first online cpu of each package allocates and takes
-        * the refcounts for all other online cpus in that package.
-        * If msrs are not enabled no allocation is required and
-        * uncore_cpu_prepare() is not called for each online cpu.
-        */
-       if (!cret) {
-              ret = cpuhp_setup_state(CPUHP_PERF_X86_UNCORE_PREP,
-                                      "perf/x86/intel/uncore:prepare",
-                                      uncore_cpu_prepare, NULL);
-               if (ret)
-                       goto err;
-       } else {
-               cpuhp_setup_state_nocalls(CPUHP_PERF_X86_UNCORE_PREP,
-                                         "perf/x86/intel/uncore:prepare",
-                                         uncore_cpu_prepare, NULL);
-       }
-       first_init = 1;
-       cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_STARTING,
-                         "perf/x86/uncore:starting",
-                         uncore_cpu_starting, uncore_cpu_dying);
-       first_init = 0;
-       cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE,
-                         "perf/x86/uncore:online",
-                         uncore_event_cpu_online, uncore_event_cpu_offline);
+       /* Install hotplug callbacks to setup the targets for each package */
+       ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE,
+                               "perf/x86/intel/uncore:online",
+                               uncore_event_cpu_online,
+                               uncore_event_cpu_offline);
+       if (ret)
+               goto err;
        return 0;
 
 err:
-       /* Undo box->init_box() */
-       on_each_cpu_mask(&uncore_cpu_mask, uncore_exit_boxes, NULL, 1);
        uncore_types_exit(uncore_msr_uncores);
        uncore_pci_exit();
        return ret;
@@ -1429,9 +1381,7 @@ module_init(intel_uncore_init);
 
 static void __exit intel_uncore_exit(void)
 {
-       cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
-       cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_UNCORE_STARTING);
-       cpuhp_remove_state_nocalls(CPUHP_PERF_X86_UNCORE_PREP);
+       cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
        uncore_types_exit(uncore_msr_uncores);
        uncore_pci_exit();
 }
index 38711df3bcb56b6939f2f84af16b920f0409049b..2266f864b7477a3ff88fee26f07df62eb5073ab4 100644 (file)
@@ -140,6 +140,7 @@ extern void __init load_ucode_bsp(void);
 extern void load_ucode_ap(void);
 void reload_early_microcode(void);
 extern bool get_builtin_firmware(struct cpio_data *cd, const char *name);
+extern bool initrd_gone;
 #else
 static inline int __init microcode_init(void)                  { return 0; };
 static inline void __init load_ucode_bsp(void)                 { }
index 1e35dd06b090ee91189cb5a52fdf026f2ca5e74b..52f352b063fdf372bddd62d5887296fa43661931 100644 (file)
@@ -2117,6 +2117,7 @@ static inline void __init check_timer(void)
                        if (idx != -1 && irq_trigger(idx))
                                unmask_ioapic_irq(irq_get_chip_data(0));
                }
+               irq_domain_deactivate_irq(irq_data);
                irq_domain_activate_irq(irq_data);
                if (timer_irq_works()) {
                        if (disable_timer_pin_1 > 0)
@@ -2138,6 +2139,7 @@ static inline void __init check_timer(void)
                 * legacy devices should be connected to IO APIC #0
                 */
                replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
+               irq_domain_deactivate_irq(irq_data);
                irq_domain_activate_irq(irq_data);
                legacy_pic->unmask(0);
                if (timer_irq_works()) {
index 00ef43233e034b0cde9b2adc88b8003ddc42d00b..537c6647d84ca3e7cca771feb6c98bda94ef8c70 100644 (file)
@@ -1373,20 +1373,15 @@ static unsigned long mce_adjust_timer_default(unsigned long interval)
 
 static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default;
 
-static void __restart_timer(struct timer_list *t, unsigned long interval)
+static void __start_timer(struct timer_list *t, unsigned long interval)
 {
        unsigned long when = jiffies + interval;
        unsigned long flags;
 
        local_irq_save(flags);
 
-       if (timer_pending(t)) {
-               if (time_before(when, t->expires))
-                       mod_timer(t, when);
-       } else {
-               t->expires = round_jiffies(when);
-               add_timer_on(t, smp_processor_id());
-       }
+       if (!timer_pending(t) || time_before(when, t->expires))
+               mod_timer(t, round_jiffies(when));
 
        local_irq_restore(flags);
 }
@@ -1421,7 +1416,7 @@ static void mce_timer_fn(unsigned long data)
 
 done:
        __this_cpu_write(mce_next_interval, iv);
-       __restart_timer(t, iv);
+       __start_timer(t, iv);
 }
 
 /*
@@ -1432,7 +1427,7 @@ void mce_timer_kick(unsigned long interval)
        struct timer_list *t = this_cpu_ptr(&mce_timer);
        unsigned long iv = __this_cpu_read(mce_next_interval);
 
-       __restart_timer(t, interval);
+       __start_timer(t, interval);
 
        if (interval < iv)
                __this_cpu_write(mce_next_interval, interval);
@@ -1779,17 +1774,15 @@ static void __mcheck_cpu_clear_vendor(struct cpuinfo_x86 *c)
        }
 }
 
-static void mce_start_timer(unsigned int cpu, struct timer_list *t)
+static void mce_start_timer(struct timer_list *t)
 {
        unsigned long iv = check_interval * HZ;
 
        if (mca_cfg.ignore_ce || !iv)
                return;
 
-       per_cpu(mce_next_interval, cpu) = iv;
-
-       t->expires = round_jiffies(jiffies + iv);
-       add_timer_on(t, cpu);
+       this_cpu_write(mce_next_interval, iv);
+       __start_timer(t, iv);
 }
 
 static void __mcheck_cpu_setup_timer(void)
@@ -1806,7 +1799,7 @@ static void __mcheck_cpu_init_timer(void)
        unsigned int cpu = smp_processor_id();
 
        setup_pinned_timer(t, mce_timer_fn, cpu);
-       mce_start_timer(cpu, t);
+       mce_start_timer(t);
 }
 
 /* Handle unconfigured int18 (should never happen) */
@@ -2566,7 +2559,7 @@ static int mce_cpu_dead(unsigned int cpu)
 
 static int mce_cpu_online(unsigned int cpu)
 {
-       struct timer_list *t = &per_cpu(mce_timer, cpu);
+       struct timer_list *t = this_cpu_ptr(&mce_timer);
        int ret;
 
        mce_device_create(cpu);
@@ -2577,13 +2570,13 @@ static int mce_cpu_online(unsigned int cpu)
                return ret;
        }
        mce_reenable_cpu();
-       mce_start_timer(cpu, t);
+       mce_start_timer(t);
        return 0;
 }
 
 static int mce_cpu_pre_down(unsigned int cpu)
 {
-       struct timer_list *t = &per_cpu(mce_timer, cpu);
+       struct timer_list *t = this_cpu_ptr(&mce_timer);
 
        mce_disable_cpu();
        del_timer_sync(t);
index 6a31e2691f3aa0ac68620459c371ca42912c4475..079e81733a58950486a7012b70e06f45e71af688 100644 (file)
@@ -384,8 +384,9 @@ void load_ucode_amd_ap(unsigned int family)
 reget:
                if (!get_builtin_microcode(&cp, family)) {
 #ifdef CONFIG_BLK_DEV_INITRD
-                       cp = find_cpio_data(ucode_path, (void *)initrd_start,
-                                           initrd_end - initrd_start, NULL);
+                       if (!initrd_gone)
+                               cp = find_cpio_data(ucode_path, (void *)initrd_start,
+                                                   initrd_end - initrd_start, NULL);
 #endif
                        if (!(cp.data && cp.size)) {
                                /*
index 2af69d27da629a5c802498e692300f9980862a2a..73102d932760b871896a956a88ff178362cc5a94 100644 (file)
@@ -46,6 +46,8 @@
 static struct microcode_ops    *microcode_ops;
 static bool dis_ucode_ldr = true;
 
+bool initrd_gone;
+
 LIST_HEAD(microcode_cache);
 
 /*
@@ -190,21 +192,24 @@ void load_ucode_ap(void)
 static int __init save_microcode_in_initrd(void)
 {
        struct cpuinfo_x86 *c = &boot_cpu_data;
+       int ret = -EINVAL;
 
        switch (c->x86_vendor) {
        case X86_VENDOR_INTEL:
                if (c->x86 >= 6)
-                       return save_microcode_in_initrd_intel();
+                       ret = save_microcode_in_initrd_intel();
                break;
        case X86_VENDOR_AMD:
                if (c->x86 >= 0x10)
-                       return save_microcode_in_initrd_amd(c->x86);
+                       ret = save_microcode_in_initrd_amd(c->x86);
                break;
        default:
                break;
        }
 
-       return -EINVAL;
+       initrd_gone = true;
+
+       return ret;
 }
 
 struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
@@ -247,9 +252,16 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
         * has the virtual address of the beginning of the initrd. It also
         * possibly relocates the ramdisk. In either case, initrd_start contains
         * the updated address so use that instead.
+        *
+        * initrd_gone is for the hotplug case where we've thrown out initrd
+        * already.
         */
-       if (!use_pa && initrd_start)
-               start = initrd_start;
+       if (!use_pa) {
+               if (initrd_gone)
+                       return (struct cpio_data){ NULL, 0, "" };
+               if (initrd_start)
+                       start = initrd_start;
+       }
 
        return find_cpio_data(path, (void *)start, size, NULL);
 #else /* !CONFIG_BLK_DEV_INITRD */
index 3f329b74e040c23b6b85dfd12a85f80d630c63ac..8325d8a09ab0768dd08156b8e4c5b755b78c10f9 100644 (file)
@@ -41,7 +41,7 @@
 
 static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
 
-/* Current microcode patch used in early patching */
+/* Current microcode patch used in early patching on the APs. */
 struct microcode_intel *intel_ucode_patch;
 
 static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1,
@@ -607,12 +607,6 @@ int __init save_microcode_in_initrd_intel(void)
        struct ucode_cpu_info uci;
        struct cpio_data cp;
 
-       /*
-        * AP loading didn't find any microcode patch, no need to save anything.
-        */
-       if (!intel_ucode_patch || IS_ERR(intel_ucode_patch))
-               return 0;
-
        if (!load_builtin_intel_microcode(&cp))
                cp = find_microcode_in_initrd(ucode_path, false);
 
@@ -628,7 +622,6 @@ int __init save_microcode_in_initrd_intel(void)
        return 0;
 }
 
-
 /*
  * @res_patch, output: a pointer to the patch we found.
  */
index e4e97a5355ce852ac49937fd180f62b614c1286c..de7234401275b56760f27573eea5669e2bda4f68 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/fpu/regset.h>
 #include <asm/fpu/signal.h>
 #include <asm/fpu/types.h>
+#include <asm/fpu/xstate.h>
 #include <asm/traps.h>
 
 #include <linux/hardirq.h>
@@ -183,7 +184,8 @@ void fpstate_init(union fpregs_state *state)
         * it will #GP. Make sure it is replaced after the memset().
         */
        if (static_cpu_has(X86_FEATURE_XSAVES))
-               state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT;
+               state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT |
+                                              xfeatures_mask;
 
        if (static_cpu_has(X86_FEATURE_FXSR))
                fpstate_init_fxstate(&state->fxsave);
index 85e87b46c318026ed28d87056c516aec3e5fb9ed..dc6ba5bda9fc83630c773a80c4adea6871db0a59 100644 (file)
@@ -352,6 +352,7 @@ static int hpet_resume(struct clock_event_device *evt, int timer)
        } else {
                struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
 
+               irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq));
                irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
                disable_irq(hdev->irq);
                irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
index d153be8929a68440ae5e5894497cbb7fa1ab9913..e52c9088660fac47d6da377b39412378ff0157b0 100644 (file)
@@ -3182,6 +3182,7 @@ static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu)
        memcpy(dest, xsave, XSAVE_HDR_OFFSET);
 
        /* Set XSTATE_BV */
+       xstate_bv &= vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE;
        *(u64 *)(dest + XSAVE_HDR_OFFSET) = xstate_bv;
 
        /*
index 319148bd4b05091d24576a7535b10aad7bec0c2d..2f25a363068cf9723e8b418e8c1942a6d3ca4029 100644 (file)
@@ -268,6 +268,22 @@ int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages)
 
        efi_scratch.use_pgd = true;
 
+       /*
+        * Certain firmware versions are way too sentimential and still believe
+        * they are exclusive and unquestionable owners of the first physical page,
+        * even though they explicitly mark it as EFI_CONVENTIONAL_MEMORY
+        * (but then write-access it later during SetVirtualAddressMap()).
+        *
+        * Create a 1:1 mapping for this page, to avoid triple faults during early
+        * boot with such firmware. We are free to hand this page to the BIOS,
+        * as trim_bios_range() will reserve the first page and isolate it away
+        * from memory allocators anyway.
+        */
+       if (kernel_map_pages_in_pgd(pgd, 0x0, 0x0, 1, _PAGE_RW)) {
+               pr_err("Failed to create 1:1 mapping for the first page!\n");
+               return 1;
+       }
+
        /*
         * When making calls to the firmware everything needs to be 1:1
         * mapped and addressable with 32-bit pointers. Map the kernel
index 848e8568fb3c4a90c2eb89783c0420f8b5526cd6..8fd4be610607c2683b16a3e0da4249f4aea732e4 100644 (file)
@@ -419,7 +419,7 @@ subsys_initcall(topology_init);
 
 void cpu_reset(void)
 {
-#if XCHAL_HAVE_PTP_MMU
+#if XCHAL_HAVE_PTP_MMU && IS_ENABLED(CONFIG_MMU)
        local_irq_disable();
        /*
         * We have full MMU: all autoload ways, ways 7, 8 and 9 of DTLB must
index df939b54b09f731eac02657957f3f573c51a1ec5..1fad2a6b3bbbf0d1d4ee07f585bdc4d501467b5d 100644 (file)
@@ -356,6 +356,7 @@ int crypto_register_alg(struct crypto_alg *alg)
        struct crypto_larval *larval;
        int err;
 
+       alg->cra_flags &= ~CRYPTO_ALG_DEAD;
        err = crypto_check_alg(alg);
        if (err)
                return err;
index 9cd0a2d4181699d94f73f2af82490e59f23373e2..c2d3785ec2279f42013cdc4816beb60785279d95 100644 (file)
@@ -1702,6 +1702,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
 
                if (qc->err_mask & ~AC_ERR_OTHER)
                        qc->err_mask &= ~AC_ERR_OTHER;
+       } else if (qc->tf.command == ATA_CMD_REQ_SENSE_DATA) {
+               qc->result_tf.command |= ATA_SENSE;
        }
 
        /* finish up */
@@ -4356,10 +4358,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "ST380013AS",         "3.20",         ATA_HORKAGE_MAX_SEC_1024 },
 
        /*
-        * Device times out with higher max sects.
+        * These devices time out with higher max sects.
         * https://bugzilla.kernel.org/show_bug.cgi?id=121671
         */
-       { "LITEON CX1-JB256-HP", NULL,          ATA_HORKAGE_MAX_SEC_1024 },
+       { "LITEON CX1-JB*-HP",  NULL,           ATA_HORKAGE_MAX_SEC_1024 },
 
        /* Devices we expect to fail diagnostics */
 
index 823e938c9a7877a1cadefde9127d447832630061..2f32782cea6d9c584797d1f7d9dc8e99eac0b796 100644 (file)
@@ -4132,6 +4132,9 @@ static int mv_platform_probe(struct platform_device *pdev)
        host->iomap = NULL;
        hpriv->base = devm_ioremap(&pdev->dev, res->start,
                                   resource_size(res));
+       if (!hpriv->base)
+               return -ENOMEM;
+
        hpriv->base -= SATAHC0_REG_BASE;
 
        hpriv->clk = clk_get(&pdev->dev, NULL);
index 4497d263209fb861e08e1650ddf654a98f2102e3..ac350c518e0c9479c05c4d9ff9f6ae918f26b96c 100644 (file)
@@ -558,9 +558,6 @@ static void fw_load_abort(struct firmware_priv *fw_priv)
        struct firmware_buf *buf = fw_priv->buf;
 
        __fw_load_abort(buf);
-
-       /* avoid user action after loading abort */
-       fw_priv->buf = NULL;
 }
 
 static LIST_HEAD(pending_fw_head);
@@ -713,7 +710,7 @@ static ssize_t firmware_loading_store(struct device *dev,
 
        mutex_lock(&fw_lock);
        fw_buf = fw_priv->buf;
-       if (!fw_buf)
+       if (fw_state_is_aborted(&fw_buf->fw_st))
                goto out;
 
        switch (loading) {
index dacb6a8418aa927e8d75a86470b35b414bf48598..fa26ffd25fa61bae95bd441699a54ee8e16818d2 100644 (file)
@@ -389,33 +389,33 @@ static ssize_t show_valid_zones(struct device *dev,
 {
        struct memory_block *mem = to_memory_block(dev);
        unsigned long start_pfn, end_pfn;
+       unsigned long valid_start, valid_end, valid_pages;
        unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
-       struct page *first_page;
        struct zone *zone;
        int zone_shift = 0;
 
        start_pfn = section_nr_to_pfn(mem->start_section_nr);
        end_pfn = start_pfn + nr_pages;
-       first_page = pfn_to_page(start_pfn);
 
        /* The block contains more than one zone can not be offlined. */
-       if (!test_pages_in_a_zone(start_pfn, end_pfn))
+       if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
                return sprintf(buf, "none\n");
 
-       zone = page_zone(first_page);
+       zone = page_zone(pfn_to_page(valid_start));
+       valid_pages = valid_end - valid_start;
 
        /* MMOP_ONLINE_KEEP */
        sprintf(buf, "%s", zone->name);
 
        /* MMOP_ONLINE_KERNEL */
-       zone_can_shift(start_pfn, nr_pages, ZONE_NORMAL, &zone_shift);
+       zone_can_shift(valid_start, valid_pages, ZONE_NORMAL, &zone_shift);
        if (zone_shift) {
                strcat(buf, " ");
                strcat(buf, (zone + zone_shift)->name);
        }
 
        /* MMOP_ONLINE_MOVABLE */
-       zone_can_shift(start_pfn, nr_pages, ZONE_MOVABLE, &zone_shift);
+       zone_can_shift(valid_start, valid_pages, ZONE_MOVABLE, &zone_shift);
        if (zone_shift) {
                strcat(buf, " ");
                strcat(buf, (zone + zone_shift)->name);
index f642c4264c277bc05d98dc99eb15ac8091886ba5..168fa175d65a08319f5e92ad10f8f5ff4baea54a 100644 (file)
@@ -45,6 +45,9 @@ int bcma_sprom_get(struct bcma_bus *bus);
 void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
 void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
 void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
 
 /* driver_chipcommon_b.c */
 int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
index b4f6520e74f05b8b7a0c1ec710042c0f38a02d7d..62f5bfa5065d919ee3acd9e596373923070e574a 100644 (file)
@@ -15,8 +15,6 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
-static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
-
 static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
                                         u32 mask, u32 value)
 {
@@ -186,9 +184,6 @@ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
        if (cc->capabilities & BCMA_CC_CAP_PMU)
                bcma_pmu_early_init(cc);
 
-       if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
-               bcma_chipco_serial_init(cc);
-
        if (bus->hosttype == BCMA_HOSTTYPE_SOC)
                bcma_core_chipcommon_flash_detect(cc);
 
@@ -378,9 +373,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
        return res;
 }
 
-static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 {
-#if IS_BUILTIN(CONFIG_BCM47XX)
        unsigned int irq;
        u32 baud_base;
        u32 i;
@@ -422,5 +417,5 @@ static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
                ports[i].baud_base = baud_base;
                ports[i].reg_shift = 0;
        }
-#endif /* CONFIG_BCM47XX */
 }
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
index 96f17132820080843e9216523bc1328b2f8f7939..89af807cf29ce49e38f60e9e1c3e177ceb0e261a 100644 (file)
@@ -278,9 +278,12 @@ static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
 
 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
 {
+       struct bcma_bus *bus = mcore->core->bus;
+
        if (mcore->early_setup_done)
                return;
 
+       bcma_chipco_serial_init(&bus->drv_cc);
        bcma_core_mips_nvram_init(mcore);
 
        mcore->early_setup_done = true;
index d5ba43a87a682b6e718d5e2ad7c804498bad61de..200828c60db9ffce12b968956271954a88ac54d0 100644 (file)
@@ -153,6 +153,8 @@ struct cppi41_dd {
 
        /* context for suspend/resume */
        unsigned int dma_tdfdq;
+
+       bool is_suspended;
 };
 
 #define FIST_COMPLETION_QUEUE  93
@@ -257,6 +259,10 @@ static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
        BUG_ON(desc_num >= ALLOC_DECS_NUM);
        c = cdd->chan_busy[desc_num];
        cdd->chan_busy[desc_num] = NULL;
+
+       /* Usecount for chan_busy[], paired with push_desc_queue() */
+       pm_runtime_put(cdd->ddev.dev);
+
        return c;
 }
 
@@ -317,12 +323,12 @@ static irqreturn_t cppi41_irq(int irq, void *data)
 
                while (val) {
                        u32 desc, len;
-                       int error;
 
-                       error = pm_runtime_get(cdd->ddev.dev);
-                       if (error < 0)
-                               dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n",
-                                       __func__, error);
+                       /*
+                        * This should never trigger, see the comments in
+                        * push_desc_queue()
+                        */
+                       WARN_ON(cdd->is_suspended);
 
                        q_num = __fls(val);
                        val &= ~(1 << q_num);
@@ -343,9 +349,6 @@ static irqreturn_t cppi41_irq(int irq, void *data)
                        c->residue = pd_trans_len(c->desc->pd6) - len;
                        dma_cookie_complete(&c->txd);
                        dmaengine_desc_get_callback_invoke(&c->txd, NULL);
-
-                       pm_runtime_mark_last_busy(cdd->ddev.dev);
-                       pm_runtime_put_autosuspend(cdd->ddev.dev);
                }
        }
        return IRQ_HANDLED;
@@ -447,6 +450,15 @@ static void push_desc_queue(struct cppi41_channel *c)
         */
        __iowmb();
 
+       /*
+        * DMA transfers can take at least 200ms to complete with USB mass
+        * storage connected. To prevent autosuspend timeouts, we must use
+        * pm_runtime_get/put() when chan_busy[] is modified. This will get
+        * cleared in desc_to_chan() or cppi41_stop_chan() depending on the
+        * outcome of the transfer.
+        */
+       pm_runtime_get(cdd->ddev.dev);
+
        desc_phys = lower_32_bits(c->desc_phys);
        desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
        WARN_ON(cdd->chan_busy[desc_num]);
@@ -457,20 +469,26 @@ static void push_desc_queue(struct cppi41_channel *c)
        cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
 }
 
-static void pending_desc(struct cppi41_channel *c)
+/*
+ * Caller must hold cdd->lock to prevent push_desc_queue()
+ * getting called out of order. We have both cppi41_dma_issue_pending()
+ * and cppi41_runtime_resume() call this function.
+ */
+static void cppi41_run_queue(struct cppi41_dd *cdd)
 {
-       struct cppi41_dd *cdd = c->cdd;
-       unsigned long flags;
+       struct cppi41_channel *c, *_c;
 
-       spin_lock_irqsave(&cdd->lock, flags);
-       list_add_tail(&c->node, &cdd->pending);
-       spin_unlock_irqrestore(&cdd->lock, flags);
+       list_for_each_entry_safe(c, _c, &cdd->pending, node) {
+               push_desc_queue(c);
+               list_del(&c->node);
+       }
 }
 
 static void cppi41_dma_issue_pending(struct dma_chan *chan)
 {
        struct cppi41_channel *c = to_cpp41_chan(chan);
        struct cppi41_dd *cdd = c->cdd;
+       unsigned long flags;
        int error;
 
        error = pm_runtime_get(cdd->ddev.dev);
@@ -482,10 +500,11 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan)
                return;
        }
 
-       if (likely(pm_runtime_active(cdd->ddev.dev)))
-               push_desc_queue(c);
-       else
-               pending_desc(c);
+       spin_lock_irqsave(&cdd->lock, flags);
+       list_add_tail(&c->node, &cdd->pending);
+       if (!cdd->is_suspended)
+               cppi41_run_queue(cdd);
+       spin_unlock_irqrestore(&cdd->lock, flags);
 
        pm_runtime_mark_last_busy(cdd->ddev.dev);
        pm_runtime_put_autosuspend(cdd->ddev.dev);
@@ -705,6 +724,9 @@ static int cppi41_stop_chan(struct dma_chan *chan)
        WARN_ON(!cdd->chan_busy[desc_num]);
        cdd->chan_busy[desc_num] = NULL;
 
+       /* Usecount for chan_busy[], paired with push_desc_queue() */
+       pm_runtime_put(cdd->ddev.dev);
+
        return 0;
 }
 
@@ -1150,8 +1172,12 @@ static int __maybe_unused cppi41_resume(struct device *dev)
 static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
 {
        struct cppi41_dd *cdd = dev_get_drvdata(dev);
+       unsigned long flags;
 
+       spin_lock_irqsave(&cdd->lock, flags);
+       cdd->is_suspended = true;
        WARN_ON(!list_empty(&cdd->pending));
+       spin_unlock_irqrestore(&cdd->lock, flags);
 
        return 0;
 }
@@ -1159,14 +1185,11 @@ static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
 static int __maybe_unused cppi41_runtime_resume(struct device *dev)
 {
        struct cppi41_dd *cdd = dev_get_drvdata(dev);
-       struct cppi41_channel *c, *_c;
        unsigned long flags;
 
        spin_lock_irqsave(&cdd->lock, flags);
-       list_for_each_entry_safe(c, _c, &cdd->pending, node) {
-               push_desc_queue(c);
-               list_del(&c->node);
-       }
+       cdd->is_suspended = false;
+       cppi41_run_queue(cdd);
        spin_unlock_irqrestore(&cdd->lock, flags);
 
        return 0;
index 740bbb942594873b08deecb59c801460dcc868ab..7539f73df9e0edbf71b424a66bcabc7d8df01e44 100644 (file)
@@ -1699,7 +1699,6 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i)
 static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
 {
        struct pl330_thread *thrd = NULL;
-       unsigned long flags;
        int chans, i;
 
        if (pl330->state == DYING)
@@ -1707,8 +1706,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
 
        chans = pl330->pcfg.num_chan;
 
-       spin_lock_irqsave(&pl330->lock, flags);
-
        for (i = 0; i < chans; i++) {
                thrd = &pl330->channels[i];
                if ((thrd->free) && (!_manager_ns(thrd) ||
@@ -1726,8 +1723,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
                thrd = NULL;
        }
 
-       spin_unlock_irqrestore(&pl330->lock, flags);
-
        return thrd;
 }
 
@@ -1745,7 +1740,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev)
 static void pl330_release_channel(struct pl330_thread *thrd)
 {
        struct pl330_dmac *pl330;
-       unsigned long flags;
 
        if (!thrd || thrd->free)
                return;
@@ -1757,10 +1751,8 @@ static void pl330_release_channel(struct pl330_thread *thrd)
 
        pl330 = thrd->dmac;
 
-       spin_lock_irqsave(&pl330->lock, flags);
        _free_event(thrd, thrd->ev);
        thrd->free = true;
-       spin_unlock_irqrestore(&pl330->lock, flags);
 }
 
 /* Initialize the structure for PL330 configuration, that can be used
@@ -2122,20 +2114,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
        struct pl330_dmac *pl330 = pch->dmac;
        unsigned long flags;
 
-       spin_lock_irqsave(&pch->lock, flags);
+       spin_lock_irqsave(&pl330->lock, flags);
 
        dma_cookie_init(chan);
        pch->cyclic = false;
 
        pch->thread = pl330_request_channel(pl330);
        if (!pch->thread) {
-               spin_unlock_irqrestore(&pch->lock, flags);
+               spin_unlock_irqrestore(&pl330->lock, flags);
                return -ENOMEM;
        }
 
        tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
 
-       spin_unlock_irqrestore(&pch->lock, flags);
+       spin_unlock_irqrestore(&pl330->lock, flags);
 
        return 1;
 }
@@ -2238,12 +2230,13 @@ static int pl330_pause(struct dma_chan *chan)
 static void pl330_free_chan_resources(struct dma_chan *chan)
 {
        struct dma_pl330_chan *pch = to_pchan(chan);
+       struct pl330_dmac *pl330 = pch->dmac;
        unsigned long flags;
 
        tasklet_kill(&pch->task);
 
        pm_runtime_get_sync(pch->dmac->ddma.dev);
-       spin_lock_irqsave(&pch->lock, flags);
+       spin_lock_irqsave(&pl330->lock, flags);
 
        pl330_release_channel(pch->thread);
        pch->thread = NULL;
@@ -2251,7 +2244,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
        if (pch->cyclic)
                list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
 
-       spin_unlock_irqrestore(&pch->lock, flags);
+       spin_unlock_irqrestore(&pl330->lock, flags);
        pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
        pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
 }
index 921dfa047202952c9064cd39971e68e0e3c28b49..260c4b4b492ec38735715859522068da40c21381 100644 (file)
@@ -187,6 +187,7 @@ static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
 struct exit_boot_struct {
        efi_memory_desc_t *runtime_map;
        int *runtime_entry_count;
+       void *new_fdt_addr;
 };
 
 static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
@@ -202,7 +203,7 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
        efi_get_virtmap(*map->map, *map->map_size, *map->desc_size,
                        p->runtime_map, p->runtime_entry_count);
 
-       return EFI_SUCCESS;
+       return update_fdt_memmap(p->new_fdt_addr, map);
 }
 
 /*
@@ -300,22 +301,13 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
 
        priv.runtime_map = runtime_map;
        priv.runtime_entry_count = &runtime_entry_count;
+       priv.new_fdt_addr = (void *)*new_fdt_addr;
        status = efi_exit_boot_services(sys_table, handle, &map, &priv,
                                        exit_boot_func);
 
        if (status == EFI_SUCCESS) {
                efi_set_virtual_address_map_t *svam;
 
-               status = update_fdt_memmap((void *)*new_fdt_addr, &map);
-               if (status != EFI_SUCCESS) {
-                       /*
-                        * The kernel won't get far without the memory map, but
-                        * may still be able to print something meaningful so
-                        * return success here.
-                        */
-                       return EFI_SUCCESS;
-               }
-
                /* Install the new virtual address map */
                svam = sys_table->runtime->set_virtual_address_map;
                status = svam(runtime_entry_count * desc_size, desc_size,
index e2b0b1646f995fd94d12e17a8cb1258bec34061f..0635829b18cf3aed41239079e4208336b00cda0f 100644 (file)
@@ -254,6 +254,9 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
        }
        WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0);
 
+       if (adev->mode_info.num_crtc)
+               amdgpu_display_set_vga_render_state(adev, false);
+
        gmc_v6_0_mc_stop(adev, &save);
 
        if (gmc_v6_0_wait_for_idle((void *)adev)) {
@@ -283,7 +286,6 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev)
                dev_warn(adev->dev, "Wait for MC idle timedout !\n");
        }
        gmc_v6_0_mc_resume(adev, &save);
-       amdgpu_display_set_vga_render_state(adev, false);
 }
 
 static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
index 50f5cf7b69d1dc55fd427efa61e7e8e5eeff80d0..fdfb1ec17e660efa0b1f2c1f7273fa8d6fd8567a 100644 (file)
@@ -2032,13 +2032,16 @@ static void complete_crtc_signaling(struct drm_device *dev,
        }
 
        for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               struct drm_pending_vblank_event *event = crtc_state->event;
                /*
-                * TEST_ONLY and PAGE_FLIP_EVENT are mutually
-                * exclusive, if they weren't, this code should be
-                * called on success for TEST_ONLY too.
+                * Free the allocated event. drm_atomic_helper_setup_commit
+                * can allocate an event too, so only free it if it's ours
+                * to prevent a double free in drm_atomic_state_clear.
                 */
-               if (crtc_state->event)
-                       drm_event_cancel_free(dev, &crtc_state->event->base);
+               if (event && (event->base.fence || event->base.file_priv)) {
+                       drm_event_cancel_free(dev, &event->base);
+                       crtc_state->event = NULL;
+               }
        }
 
        if (!fence_state)
index 34f757bcabae8d88382f18392467e67f4e0f6100..4594477dee00bc0ffb7847da556985848df717e7 100644 (file)
@@ -1666,9 +1666,6 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev,
 
                funcs = plane->helper_private;
 
-               if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc))
-                       continue;
-
                if (funcs->prepare_fb) {
                        ret = funcs->prepare_fb(plane, plane_state);
                        if (ret)
@@ -1685,9 +1682,6 @@ fail:
                if (j >= i)
                        continue;
 
-               if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc))
-                       continue;
-
                funcs = plane->helper_private;
 
                if (funcs->cleanup_fb)
@@ -1954,9 +1948,6 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev,
        for_each_plane_in_state(old_state, plane, plane_state, i) {
                const struct drm_plane_helper_funcs *funcs;
 
-               if (!drm_atomic_helper_framebuffer_changed(dev, old_state, plane_state->crtc))
-                       continue;
-
                funcs = plane->helper_private;
 
                if (funcs->cleanup_fb)
index 5a452628939272969c54239498b9a1ca86cd4a67..7a7019ac93884eeeba046ad62b3c81037796beb7 100644 (file)
@@ -225,6 +225,7 @@ int drm_connector_init(struct drm_device *dev,
 
        INIT_LIST_HEAD(&connector->probed_modes);
        INIT_LIST_HEAD(&connector->modes);
+       mutex_init(&connector->mutex);
        connector->edid_blob_ptr = NULL;
        connector->status = connector_status_unknown;
 
@@ -359,6 +360,8 @@ void drm_connector_cleanup(struct drm_connector *connector)
                connector->funcs->atomic_destroy_state(connector,
                                                       connector->state);
 
+       mutex_destroy(&connector->mutex);
+
        memset(connector, 0, sizeof(*connector));
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
@@ -374,14 +377,18 @@ EXPORT_SYMBOL(drm_connector_cleanup);
  */
 int drm_connector_register(struct drm_connector *connector)
 {
-       int ret;
+       int ret = 0;
 
-       if (connector->registered)
+       if (!connector->dev->registered)
                return 0;
 
+       mutex_lock(&connector->mutex);
+       if (connector->registered)
+               goto unlock;
+
        ret = drm_sysfs_connector_add(connector);
        if (ret)
-               return ret;
+               goto unlock;
 
        ret = drm_debugfs_connector_add(connector);
        if (ret) {
@@ -397,12 +404,14 @@ int drm_connector_register(struct drm_connector *connector)
        drm_mode_object_register(connector->dev, &connector->base);
 
        connector->registered = true;
-       return 0;
+       goto unlock;
 
 err_debugfs:
        drm_debugfs_connector_remove(connector);
 err_sysfs:
        drm_sysfs_connector_remove(connector);
+unlock:
+       mutex_unlock(&connector->mutex);
        return ret;
 }
 EXPORT_SYMBOL(drm_connector_register);
@@ -415,8 +424,11 @@ EXPORT_SYMBOL(drm_connector_register);
  */
 void drm_connector_unregister(struct drm_connector *connector)
 {
-       if (!connector->registered)
+       mutex_lock(&connector->mutex);
+       if (!connector->registered) {
+               mutex_unlock(&connector->mutex);
                return;
+       }
 
        if (connector->funcs->early_unregister)
                connector->funcs->early_unregister(connector);
@@ -425,6 +437,7 @@ void drm_connector_unregister(struct drm_connector *connector)
        drm_debugfs_connector_remove(connector);
 
        connector->registered = false;
+       mutex_unlock(&connector->mutex);
 }
 EXPORT_SYMBOL(drm_connector_unregister);
 
index a525751b4559e9f3cc99850d5aac6e5c3eb6f16c..6594b4088f11bc8e5aa6a6c308ba3fdf633921a3 100644 (file)
@@ -745,6 +745,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
        if (ret)
                goto err_minors;
 
+       dev->registered = true;
+
        if (dev->driver->load) {
                ret = dev->driver->load(dev, flags);
                if (ret)
@@ -785,6 +787,8 @@ void drm_dev_unregister(struct drm_device *dev)
 
        drm_lastclose(dev);
 
+       dev->registered = false;
+
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                drm_modeset_unregister_all(dev);
 
index 3dea46af9fe6785c5b5543a246b6ab43c9d39f6a..78711dddd9377730bc23323d840b81f8c5ae226c 100644 (file)
@@ -122,6 +122,9 @@ i915-y += intel_gvt.o
 include $(src)/gvt/Makefile
 endif
 
+# LPE Audio for VLV and CHT
+i915-y += intel_lpe_audio.o
+
 obj-$(CONFIG_DRM_I915) += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
index b2c4a0b8a627e39c5828922083b78dfd667ad047..77ae0be3d4baa653e47bc1bb417e8d9dcc410979 100644 (file)
@@ -1138,7 +1138,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
        if (IS_GEN5(dev_priv))
                intel_gpu_ips_init(dev_priv);
 
-       i915_audio_component_init(dev_priv);
+       intel_audio_init(dev_priv);
 
        /*
         * Some ports require correctly set-up hpd registers for detection to
@@ -1156,7 +1156,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
  */
 static void i915_driver_unregister(struct drm_i915_private *dev_priv)
 {
-       i915_audio_component_cleanup(dev_priv);
+       intel_audio_deinit(dev_priv);
 
        intel_gpu_ips_teardown();
        acpi_video_unregister();
index 69bc3b0c43905eccf19ad142cf32c7064a09feb0..029d5c3c81efd8547e997fad34801b9110c69fa7 100644 (file)
@@ -1012,6 +1012,8 @@ struct intel_fbc {
        struct work_struct underrun_work;
 
        struct intel_fbc_state_cache {
+               struct i915_vma *vma;
+
                struct {
                        unsigned int mode_flags;
                        uint32_t hsw_bdw_pixel_rate;
@@ -1025,15 +1027,14 @@ struct intel_fbc {
                } plane;
 
                struct {
-                       u64 ilk_ggtt_offset;
                        uint32_t pixel_format;
                        unsigned int stride;
-                       int fence_reg;
-                       unsigned int tiling_mode;
                } fb;
        } state_cache;
 
        struct intel_fbc_reg_params {
+               struct i915_vma *vma;
+
                struct {
                        enum pipe pipe;
                        enum plane plane;
@@ -1041,10 +1042,8 @@ struct intel_fbc {
                } crtc;
 
                struct {
-                       u64 ggtt_offset;
                        uint32_t pixel_format;
                        unsigned int stride;
-                       int fence_reg;
                } fb;
 
                int cfb_size;
@@ -2141,6 +2140,12 @@ struct drm_i915_private {
        /* Used to save the pipe-to-encoder mapping for audio */
        struct intel_encoder *av_enc_map[I915_MAX_PIPES];
 
+       /* necessary resource sharing with HDMI LPE audio driver. */
+       struct {
+               struct platform_device *platdev;
+               int     irq;
+       } lpe_audio;
+
        /*
         * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
         * will be rejected. Instead look for a better place.
@@ -3168,13 +3173,6 @@ i915_gem_object_to_ggtt(struct drm_i915_gem_object *obj,
        return i915_gem_obj_to_vma(obj, &to_i915(obj->base.dev)->ggtt.base, view);
 }
 
-static inline unsigned long
-i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o,
-                           const struct i915_ggtt_view *view)
-{
-       return i915_ggtt_offset(i915_gem_object_to_ggtt(o, view));
-}
-
 /* i915_gem_fence_reg.c */
 int __must_check i915_vma_get_fence(struct i915_vma *vma);
 int __must_check i915_vma_put_fence(struct i915_vma *vma);
@@ -3395,6 +3393,14 @@ extern int i915_restore_state(struct drm_device *dev);
 void i915_setup_sysfs(struct drm_i915_private *dev_priv);
 void i915_teardown_sysfs(struct drm_i915_private *dev_priv);
 
+/* intel_lpe_audio.c */
+int  intel_lpe_audio_init(struct drm_i915_private *dev_priv);
+void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv);
+void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv);
+void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
+                           void *eld, int port, int pipe, int tmds_clk_speed,
+                           bool dp_output, int link_rate);
+
 /* intel_i2c.c */
 extern int intel_setup_gmbus(struct drm_device *dev);
 extern void intel_teardown_gmbus(struct drm_device *dev);
index 07ca71cabb2bfe94a6c250cc538dce500157f404..f0880afbb87858db7198145f5fedc1bf3150e6a2 100644 (file)
@@ -1893,6 +1893,10 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                 * signalled in iir */
                valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & (I915_LPE_PIPE_A_INTERRUPT |
+                          I915_LPE_PIPE_B_INTERRUPT))
+                       intel_lpe_audio_irq_handler(dev_priv);
+
                /*
                 * VLV_IIR is single buffered, and reflects the level
                 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
@@ -1973,6 +1977,11 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
                 * signalled in iir */
                valleyview_pipestat_irq_ack(dev_priv, iir, pipe_stats);
 
+               if (iir & (I915_LPE_PIPE_A_INTERRUPT |
+                          I915_LPE_PIPE_B_INTERRUPT |
+                          I915_LPE_PIPE_C_INTERRUPT))
+                       intel_lpe_audio_irq_handler(dev_priv);
+
                /*
                 * VLV_IIR is single buffered, and reflects the level
                 * from PIPESTAT/PORT_HOTPLUG_STAT, hence clear it last.
@@ -2914,6 +2923,7 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
        u32 pipestat_mask;
        u32 enable_mask;
        enum pipe pipe;
+       u32 val;
 
        pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
                        PIPE_CRC_DONE_INTERRUPT_STATUS;
@@ -2930,6 +2940,12 @@ static void vlv_display_irq_postinstall(struct drm_i915_private *dev_priv)
 
        WARN_ON(dev_priv->irq_mask != ~0);
 
+       val = (I915_LPE_PIPE_A_INTERRUPT |
+               I915_LPE_PIPE_B_INTERRUPT |
+               I915_LPE_PIPE_C_INTERRUPT);
+
+       enable_mask |= val;
+
        dev_priv->irq_mask = ~enable_mask;
 
        GEN5_IRQ_INIT(VLV_, dev_priv->irq_mask, enable_mask);
index c70c07a7b5864955f251d25db496fd33f5a66812..4f15a3dc6d9899d6075ea90af91eae33879d7fdd 100644 (file)
@@ -2058,6 +2058,22 @@ enum skl_disp_power_wells {
 #define I915_ASLE_INTERRUPT                            (1<<0)
 #define I915_BSD_USER_INTERRUPT                                (1<<25)
 
+#define I915_HDMI_LPE_AUDIO_BASE       (VLV_DISPLAY_BASE + 0x65000)
+#define I915_HDMI_LPE_AUDIO_SIZE       0x1000
+
+/* DisplayPort Audio w/ LPE */
+#define VLV_AUD_CHICKEN_BIT_REG                _MMIO(VLV_DISPLAY_BASE + 0x62F38)
+#define VLV_CHICKEN_BIT_DBG_ENABLE     (1 << 0)
+
+#define _VLV_AUD_PORT_EN_B_DBG         (VLV_DISPLAY_BASE + 0x62F20)
+#define _VLV_AUD_PORT_EN_C_DBG         (VLV_DISPLAY_BASE + 0x62F30)
+#define _VLV_AUD_PORT_EN_D_DBG         (VLV_DISPLAY_BASE + 0x62F34)
+#define VLV_AUD_PORT_EN_DBG(port)      _MMIO_PORT3((port) - PORT_B,       \
+                                                   _VLV_AUD_PORT_EN_B_DBG, \
+                                                   _VLV_AUD_PORT_EN_C_DBG, \
+                                                   _VLV_AUD_PORT_EN_D_DBG)
+#define VLV_AMP_MUTE                   (1 << 1)
+
 #define GEN6_BSD_RNCID                 _MMIO(0x12198)
 
 #define GEN7_FF_THREAD_MODE            _MMIO(0x20a0)
index dbe9fb41ae535449f996ab36e51bd626be6651fc..8d3e515f27bade27acda9544a30d975628ac8ab3 100644 (file)
@@ -85,6 +85,8 @@ intel_plane_duplicate_state(struct drm_plane *plane)
 
        __drm_atomic_helper_plane_duplicate_state(plane, state);
 
+       intel_state->vma = NULL;
+
        return state;
 }
 
@@ -100,6 +102,24 @@ void
 intel_plane_destroy_state(struct drm_plane *plane,
                          struct drm_plane_state *state)
 {
+       struct i915_vma *vma;
+
+       vma = fetch_and_zero(&to_intel_plane_state(state)->vma);
+
+       /*
+        * FIXME: Normally intel_cleanup_plane_fb handles destruction of vma.
+        * We currently don't clear all planes during driver unload, so we have
+        * to be able to unpin vma here for now.
+        *
+        * Normally this can only happen during unload when kmscon is disabled
+        * and userspace doesn't attempt to set a framebuffer at all.
+        */
+       if (vma) {
+               mutex_lock(&plane->dev->struct_mutex);
+               intel_unpin_fb_vma(vma);
+               mutex_unlock(&plane->dev->struct_mutex);
+       }
+
        drm_atomic_helper_plane_destroy_state(plane, state);
 }
 
index 49f10538d4aa1214b05670d33769be4e50ca88df..892169b7952b09647757e4116b890de72810989d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/component.h>
 #include <drm/i915_component.h>
+#include <drm/intel_lpe_audio.h>
 #include "intel_drv.h"
 
 #include <drm/drmP.h>
@@ -623,13 +624,28 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder,
        dev_priv->av_enc_map[pipe] = intel_encoder;
        mutex_unlock(&dev_priv->av_mutex);
 
-       /* audio drivers expect pipe = -1 to indicate Non-MST cases */
-       if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
-               pipe = -1;
-
-       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
+       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+               /* audio drivers expect pipe = -1 to indicate Non-MST cases */
+               if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
+                       pipe = -1;
                acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
                                                 (int) port, (int) pipe);
+       }
+
+       switch (intel_encoder->type) {
+       case INTEL_OUTPUT_HDMI:
+               intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe,
+                                      crtc_state->port_clock,
+                                      false, 0);
+               break;
+       case INTEL_OUTPUT_DP:
+               intel_lpe_audio_notify(dev_priv, connector->eld, port, pipe,
+                                      adjusted_mode->crtc_clock,
+                                      true, crtc_state->port_clock);
+               break;
+       default:
+               break;
+       }
 }
 
 /**
@@ -656,13 +672,15 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
        dev_priv->av_enc_map[pipe] = NULL;
        mutex_unlock(&dev_priv->av_mutex);
 
-       /* audio drivers expect pipe = -1 to indicate Non-MST cases */
-       if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
-               pipe = -1;
-
-       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
+       if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) {
+               /* audio drivers expect pipe = -1 to indicate Non-MST cases */
+               if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
+                       pipe = -1;
                acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
                                                 (int) port, (int) pipe);
+       }
+
+       intel_lpe_audio_notify(dev_priv, NULL, port, pipe, 0, false, 0);
 }
 
 /**
@@ -931,3 +949,28 @@ void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
        component_del(dev_priv->drm.dev, &i915_audio_component_bind_ops);
        dev_priv->audio_component_registered = false;
 }
+
+/**
+ * intel_audio_init() - Initialize the audio driver either using
+ * component framework or using lpe audio bridge
+ * @dev_priv: the i915 drm device private data
+ *
+ */
+void intel_audio_init(struct drm_i915_private *dev_priv)
+{
+       if (intel_lpe_audio_init(dev_priv) < 0)
+               i915_audio_component_init(dev_priv);
+}
+
+/**
+ * intel_audio_deinit() - deinitialize the audio driver
+ * @dev_priv: the i915 drm device private data
+ *
+ */
+void intel_audio_deinit(struct drm_i915_private *dev_priv)
+{
+       if ((dev_priv)->lpe_audio.platdev != NULL)
+               intel_lpe_audio_teardown(dev_priv);
+       else
+               i915_audio_component_cleanup(dev_priv);
+}
index f0b9aa7a0483d1928aecec439d342fa2c85b78d9..f1e4a21d46643b53a3cf492671b872ed03215105 100644 (file)
@@ -2235,27 +2235,22 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
                        i915_vma_pin_fence(vma);
        }
 
+       i915_vma_get(vma);
 err:
        intel_runtime_pm_put(dev_priv);
        return vma;
 }
 
-void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
+void intel_unpin_fb_vma(struct i915_vma *vma)
 {
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct i915_ggtt_view view;
-       struct i915_vma *vma;
-
-       WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
-
-       intel_fill_fb_ggtt_view(&view, fb, rotation);
-       vma = i915_gem_object_to_ggtt(obj, &view);
+       lockdep_assert_held(&vma->vm->dev->struct_mutex);
 
        if (WARN_ON_ONCE(!vma))
                return;
 
        i915_vma_unpin_fence(vma);
        i915_gem_object_unpin_from_display_plane(vma);
+       i915_vma_put(vma);
 }
 
 static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
@@ -2750,7 +2745,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_crtc *c;
-       struct intel_crtc *i;
        struct drm_i915_gem_object *obj;
        struct drm_plane *primary = intel_crtc->base.primary;
        struct drm_plane_state *plane_state = primary->state;
@@ -2775,20 +2769,20 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
         * an fb with another CRTC instead
         */
        for_each_crtc(dev, c) {
-               i = to_intel_crtc(c);
+               struct intel_plane_state *state;
 
                if (c == &intel_crtc->base)
                        continue;
 
-               if (!i->active)
+               if (!to_intel_crtc(c)->active)
                        continue;
 
-               fb = c->primary->fb;
-               if (!fb)
+               state = to_intel_plane_state(c->primary->state);
+               if (!state->vma)
                        continue;
 
-               obj = intel_fb_obj(fb);
-               if (i915_gem_object_ggtt_offset(obj, NULL) == plane_config->base) {
+               if (intel_plane_ggtt_offset(state) == plane_config->base) {
+                       fb = c->primary->fb;
                        drm_framebuffer_reference(fb);
                        goto valid_fb;
                }
@@ -2809,6 +2803,19 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
        return;
 
 valid_fb:
+       mutex_lock(&dev->struct_mutex);
+       intel_state->vma =
+               intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+       mutex_unlock(&dev->struct_mutex);
+       if (IS_ERR(intel_state->vma)) {
+               DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
+                         intel_crtc->pipe, PTR_ERR(intel_state->vma));
+
+               intel_state->vma = NULL;
+               drm_framebuffer_unreference(fb);
+               return;
+       }
+
        plane_state->src_x = 0;
        plane_state->src_y = 0;
        plane_state->src_w = fb->width << 16;
@@ -3104,13 +3111,13 @@ static void i9xx_update_primary_plane(struct drm_plane *primary,
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_GEN(dev_priv) >= 4) {
                I915_WRITE(DSPSURF(plane),
-                          intel_fb_gtt_offset(fb, rotation) +
+                          intel_plane_ggtt_offset(plane_state) +
                           intel_crtc->dspaddr_offset);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPLINOFF(plane), linear_offset);
        } else {
                I915_WRITE(DSPADDR(plane),
-                          intel_fb_gtt_offset(fb, rotation) +
+                          intel_plane_ggtt_offset(plane_state) +
                           intel_crtc->dspaddr_offset);
        }
        POSTING_READ(reg);
@@ -3207,7 +3214,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary,
 
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_WRITE(DSPSURF(plane),
-                  intel_fb_gtt_offset(fb, rotation) +
+                  intel_plane_ggtt_offset(plane_state) +
                   intel_crtc->dspaddr_offset);
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
@@ -3230,23 +3237,6 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv,
        }
 }
 
-u32 intel_fb_gtt_offset(struct drm_framebuffer *fb,
-                       unsigned int rotation)
-{
-       struct drm_i915_gem_object *obj = intel_fb_obj(fb);
-       struct i915_ggtt_view view;
-       struct i915_vma *vma;
-
-       intel_fill_fb_ggtt_view(&view, fb, rotation);
-
-       vma = i915_gem_object_to_ggtt(obj, &view);
-       if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
-                view.type))
-               return -1;
-
-       return i915_ggtt_offset(vma);
-}
-
 static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
 {
        struct drm_device *dev = intel_crtc->base.dev;
@@ -3441,7 +3431,7 @@ static void skylake_update_primary_plane(struct drm_plane *plane,
        }
 
        I915_WRITE(PLANE_SURF(pipe, 0),
-                  intel_fb_gtt_offset(fb, rotation) + surf_addr);
+                  intel_plane_ggtt_offset(plane_state) + surf_addr);
 
        POSTING_READ(PLANE_SURF(pipe, 0));
 }
@@ -11536,7 +11526,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
                flush_work(&work->mmio_work);
 
        mutex_lock(&dev->struct_mutex);
-       intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
+       intel_unpin_fb_vma(work->old_vma);
        i915_gem_object_put(work->pending_flip_obj);
        mutex_unlock(&dev->struct_mutex);
 
@@ -12246,8 +12236,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                goto cleanup_pending;
        }
 
-       work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation);
-       work->gtt_offset += intel_crtc->dspaddr_offset;
+       work->old_vma = to_intel_plane_state(primary->state)->vma;
+       to_intel_plane_state(primary->state)->vma = vma;
+
+       work->gtt_offset = i915_ggtt_offset(vma) + intel_crtc->dspaddr_offset;
        work->rotation = crtc->primary->state->rotation;
 
        /*
@@ -12301,7 +12293,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 cleanup_request:
        i915_add_request_no_flush(request);
 cleanup_unpin:
-       intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
+       to_intel_plane_state(primary->state)->vma = work->old_vma;
+       intel_unpin_fb_vma(vma);
 cleanup_pending:
        atomic_dec(&intel_crtc->unpin_work_count);
 unlock:
@@ -14794,6 +14787,8 @@ intel_prepare_plane_fb(struct drm_plane *plane,
                        DRM_DEBUG_KMS("failed to pin object\n");
                        return PTR_ERR(vma);
                }
+
+               to_intel_plane_state(new_state)->vma = vma;
        }
 
        return 0;
@@ -14812,19 +14807,12 @@ void
 intel_cleanup_plane_fb(struct drm_plane *plane,
                       struct drm_plane_state *old_state)
 {
-       struct drm_i915_private *dev_priv = to_i915(plane->dev);
-       struct intel_plane_state *old_intel_state;
-       struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb);
-       struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb);
-
-       old_intel_state = to_intel_plane_state(old_state);
-
-       if (!obj && !old_obj)
-               return;
+       struct i915_vma *vma;
 
-       if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
-           !INTEL_INFO(dev_priv)->cursor_needs_physical))
-               intel_unpin_fb_obj(old_state->fb, old_state->rotation);
+       /* Should only be called after a successful intel_prepare_plane_fb()! */
+       vma = fetch_and_zero(&to_intel_plane_state(old_state)->vma);
+       if (vma)
+               intel_unpin_fb_vma(vma);
 }
 
 int
@@ -15166,7 +15154,7 @@ intel_update_cursor_plane(struct drm_plane *plane,
        if (!obj)
                addr = 0;
        else if (!INTEL_INFO(dev_priv)->cursor_needs_physical)
-               addr = i915_gem_object_ggtt_offset(obj, NULL);
+               addr = intel_plane_ggtt_offset(state);
        else
                addr = obj->phys_handle->busaddr;
 
@@ -17066,41 +17054,12 @@ void intel_display_resume(struct drm_device *dev)
 void intel_modeset_gem_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_crtc *c;
-       struct drm_i915_gem_object *obj;
 
        intel_init_gt_powersave(dev_priv);
 
        intel_modeset_init_hw(dev);
 
        intel_setup_overlay(dev_priv);
-
-       /*
-        * Make sure any fbs we allocated at startup are properly
-        * pinned & fenced.  When we do the allocation it's too early
-        * for this.
-        */
-       for_each_crtc(dev, c) {
-               struct i915_vma *vma;
-
-               obj = intel_fb_obj(c->primary->fb);
-               if (obj == NULL)
-                       continue;
-
-               mutex_lock(&dev->struct_mutex);
-               vma = intel_pin_and_fence_fb_obj(c->primary->fb,
-                                                c->primary->state->rotation);
-               mutex_unlock(&dev->struct_mutex);
-               if (IS_ERR(vma)) {
-                       DRM_ERROR("failed to pin boot fb on pipe %d\n",
-                                 to_intel_crtc(c)->pipe);
-                       drm_framebuffer_unreference(c->primary->fb);
-                       c->primary->fb = NULL;
-                       c->primary->crtc = c->primary->state->crtc = NULL;
-                       update_state_fb(c->primary);
-                       c->state->plane_mask &= ~(1 << drm_plane_index(c->primary));
-               }
-       }
 }
 
 int intel_connector_register(struct drm_connector *connector)
index cd72ae171eeb673de11f1ca6dcc6f1ab06fde81c..ba2323f1b92b6e1ff7f60ba014d0fb69e11ac231 100644 (file)
@@ -377,6 +377,7 @@ struct intel_atomic_state {
 struct intel_plane_state {
        struct drm_plane_state base;
        struct drm_rect clip;
+       struct i915_vma *vma;
 
        struct {
                u32 offset;
@@ -1046,6 +1047,7 @@ struct intel_flip_work {
        struct work_struct mmio_work;
 
        struct drm_crtc *crtc;
+       struct i915_vma *old_vma;
        struct drm_framebuffer *old_fb;
        struct drm_i915_gem_object *pending_flip_obj;
        struct drm_pending_vblank_event *event;
@@ -1194,6 +1196,8 @@ void intel_audio_codec_enable(struct intel_encoder *encoder,
 void intel_audio_codec_disable(struct intel_encoder *encoder);
 void i915_audio_component_init(struct drm_i915_private *dev_priv);
 void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
+void intel_audio_init(struct drm_i915_private *dev_priv);
+void intel_audio_deinit(struct drm_i915_private *dev_priv);
 
 /* intel_display.c */
 enum transcoder intel_crtc_pch_transcoder(struct intel_crtc *crtc);
@@ -1273,7 +1277,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                                    struct drm_modeset_acquire_ctx *ctx);
 struct i915_vma *
 intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
-void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
+void intel_unpin_fb_vma(struct i915_vma *vma);
 struct drm_framebuffer *
 __intel_framebuffer_create(struct drm_device *dev,
                           struct drm_mode_fb_cmd2 *mode_cmd,
@@ -1362,7 +1366,10 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode,
 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
 int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
 
-u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation);
+static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
+{
+       return i915_ggtt_offset(state->vma);
+}
 
 u32 skl_plane_ctl_format(uint32_t pixel_format);
 u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
index 62f215b12eb5274b8251d3f46d2a4fdbfc590e96..f3a1d6a5cabe9fcf76f5812dc526781b678f7e41 100644 (file)
@@ -173,7 +173,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv)
        if (IS_I945GM(dev_priv))
                fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
        fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
-       fbc_ctl |= params->fb.fence_reg;
+       fbc_ctl |= params->vma->fence->id;
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 }
 
@@ -193,8 +193,8 @@ static void g4x_fbc_activate(struct drm_i915_private *dev_priv)
        else
                dpfc_ctl |= DPFC_CTL_LIMIT_1X;
 
-       if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
-               dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg;
+       if (params->vma->fence) {
+               dpfc_ctl |= DPFC_CTL_FENCE_EN | params->vma->fence->id;
                I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
        } else {
                I915_WRITE(DPFC_FENCE_YOFF, 0);
@@ -251,13 +251,14 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
                break;
        }
 
-       if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+       if (params->vma->fence) {
                dpfc_ctl |= DPFC_CTL_FENCE_EN;
                if (IS_GEN5(dev_priv))
-                       dpfc_ctl |= params->fb.fence_reg;
+                       dpfc_ctl |= params->vma->fence->id;
                if (IS_GEN6(dev_priv)) {
                        I915_WRITE(SNB_DPFC_CTL_SA,
-                                  SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+                                  SNB_CPU_FENCE_ENABLE |
+                                  params->vma->fence->id);
                        I915_WRITE(DPFC_CPU_FENCE_OFFSET,
                                   params->crtc.fence_y_offset);
                }
@@ -269,7 +270,8 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv)
        }
 
        I915_WRITE(ILK_DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
-       I915_WRITE(ILK_FBC_RT_BASE, params->fb.ggtt_offset | ILK_FBC_RT_VALID);
+       I915_WRITE(ILK_FBC_RT_BASE,
+                  i915_ggtt_offset(params->vma) | ILK_FBC_RT_VALID);
        /* enable it... */
        I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
@@ -319,10 +321,11 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv)
                break;
        }
 
-       if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+       if (params->vma->fence) {
                dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
                I915_WRITE(SNB_DPFC_CTL_SA,
-                          SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+                          SNB_CPU_FENCE_ENABLE |
+                          params->vma->fence->id);
                I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset);
        } else {
                I915_WRITE(SNB_DPFC_CTL_SA,0);
@@ -727,14 +730,6 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)
        return effective_w <= max_w && effective_h <= max_h;
 }
 
-/* XXX replace me when we have VMA tracking for intel_plane_state */
-static int get_fence_id(struct drm_framebuffer *fb)
-{
-       struct i915_vma *vma = i915_gem_object_to_ggtt(intel_fb_obj(fb), NULL);
-
-       return vma && vma->fence ? vma->fence->id : I915_FENCE_REG_NONE;
-}
-
 static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
                                         struct intel_crtc_state *crtc_state,
                                         struct intel_plane_state *plane_state)
@@ -743,7 +738,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
        struct intel_fbc *fbc = &dev_priv->fbc;
        struct intel_fbc_state_cache *cache = &fbc->state_cache;
        struct drm_framebuffer *fb = plane_state->base.fb;
-       struct drm_i915_gem_object *obj;
+
+       cache->vma = NULL;
 
        cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
        if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
@@ -758,16 +754,10 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
        if (!cache->plane.visible)
                return;
 
-       obj = intel_fb_obj(fb);
-
-       /* FIXME: We lack the proper locking here, so only run this on the
-        * platforms that need. */
-       if (IS_GEN(dev_priv, 5, 6))
-               cache->fb.ilk_ggtt_offset = i915_gem_object_ggtt_offset(obj, NULL);
        cache->fb.pixel_format = fb->pixel_format;
        cache->fb.stride = fb->pitches[0];
-       cache->fb.fence_reg = get_fence_id(fb);
-       cache->fb.tiling_mode = i915_gem_object_get_tiling(obj);
+
+       cache->vma = plane_state->vma;
 }
 
 static bool intel_fbc_can_activate(struct intel_crtc *crtc)
@@ -784,7 +774,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
                return false;
        }
 
-       if (!cache->plane.visible) {
+       if (!cache->vma) {
                fbc->no_fbc_reason = "primary plane not visible";
                return false;
        }
@@ -807,8 +797,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc)
         * so have no fence associated with it) due to aperture constaints
         * at the time of pinning.
         */
-       if (cache->fb.tiling_mode != I915_TILING_X ||
-           cache->fb.fence_reg == I915_FENCE_REG_NONE) {
+       if (!cache->vma->fence) {
                fbc->no_fbc_reason = "framebuffer not tiled or fenced";
                return false;
        }
@@ -888,17 +877,16 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc,
         * zero. */
        memset(params, 0, sizeof(*params));
 
+       params->vma = cache->vma;
+
        params->crtc.pipe = crtc->pipe;
        params->crtc.plane = crtc->plane;
        params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc);
 
        params->fb.pixel_format = cache->fb.pixel_format;
        params->fb.stride = cache->fb.stride;
-       params->fb.fence_reg = cache->fb.fence_reg;
 
        params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache);
-
-       params->fb.ggtt_offset = cache->fb.ilk_ggtt_offset;
 }
 
 static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
index 8cf2d80f22540a35dc4245a842d8473ce7d852d9..f4a8c4fc57c4e654a1af91903275189c841b35bd 100644 (file)
@@ -284,7 +284,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 out_destroy_fbi:
        drm_fb_helper_release_fbi(helper);
 out_unpin:
-       intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+       intel_unpin_fb_vma(vma);
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
        return ret;
@@ -549,7 +549,7 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev)
 
        if (ifbdev->fb) {
                mutex_lock(&ifbdev->helper.dev->struct_mutex);
-               intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+               intel_unpin_fb_vma(ifbdev->vma);
                mutex_unlock(&ifbdev->helper.dev->struct_mutex);
 
                drm_framebuffer_remove(&ifbdev->fb->base);
index fb88e32e25a3de7831b7b61f00f6a463e51698fa..02d50e334ac621adfd3b1dfd4620f90ba18e6876 100644 (file)
@@ -36,6 +36,7 @@
 #include <drm/drm_edid.h>
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
+#include <drm/intel_lpe_audio.h>
 #include "i915_drv.h"
 
 static struct drm_device *intel_hdmi_to_dev(struct intel_hdmi *intel_hdmi)
diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c
new file mode 100644 (file)
index 0000000..7a5b41b
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * Copyright Â© 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+ *    Jerome Anand <jerome.anand@intel.com>
+ *    based on VED patches
+ *
+ */
+
+/**
+ * DOC: LPE Audio integration for HDMI or DP playback
+ *
+ * Motivation:
+ * Atom platforms (e.g. valleyview and cherryTrail) integrates a DMA-based
+ * interface as an alternative to the traditional HDaudio path. While this
+ * mode is unrelated to the LPE aka SST audio engine, the documentation refers
+ * to this mode as LPE so we keep this notation for the sake of consistency.
+ *
+ * The interface is handled by a separate standalone driver maintained in the
+ * ALSA subsystem for simplicity. To minimize the interaction between the two
+ * subsystems, a bridge is setup between the hdmi-lpe-audio and i915:
+ * 1. Create a platform device to share MMIO/IRQ resources
+ * 2. Make the platform device child of i915 device for runtime PM.
+ * 3. Create IRQ chip to forward the LPE audio irqs.
+ * the hdmi-lpe-audio driver probes the lpe audio device and creates a new
+ * sound card
+ *
+ * Threats:
+ * Due to the restriction in Linux platform device model, user need manually
+ * uninstall the hdmi-lpe-audio driver before uninstalling i915 module,
+ * otherwise we might run into use-after-free issues after i915 removes the
+ * platform device: even though hdmi-lpe-audio driver is released, the modules
+ * is still in "installed" status.
+ *
+ * Implementation:
+ * The MMIO/REG platform resources are created according to the registers
+ * specification.
+ * When forwarding LPE audio irqs, the flow control handler selection depends
+ * on the platform, for example on valleyview handle_simple_irq is enough.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include "i915_drv.h"
+#include <linux/delay.h>
+#include <drm/intel_lpe_audio.h>
+
+#define HAS_LPE_AUDIO(dev_priv) ((dev_priv)->lpe_audio.platdev != NULL)
+
+static struct platform_device *
+lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
+{
+       int ret;
+       struct drm_device *dev = &dev_priv->drm;
+       struct platform_device_info pinfo = {};
+       struct resource *rsc;
+       struct platform_device *platdev;
+       struct intel_hdmi_lpe_audio_pdata *pdata;
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       rsc = kcalloc(2, sizeof(*rsc), GFP_KERNEL);
+       if (!rsc) {
+               kfree(pdata);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       rsc[0].start    = rsc[0].end = dev_priv->lpe_audio.irq;
+       rsc[0].flags    = IORESOURCE_IRQ;
+       rsc[0].name     = "hdmi-lpe-audio-irq";
+
+       rsc[1].start    = pci_resource_start(dev->pdev, 0) +
+               I915_HDMI_LPE_AUDIO_BASE;
+       rsc[1].end      = pci_resource_start(dev->pdev, 0) +
+               I915_HDMI_LPE_AUDIO_BASE + I915_HDMI_LPE_AUDIO_SIZE - 1;
+       rsc[1].flags    = IORESOURCE_MEM;
+       rsc[1].name     = "hdmi-lpe-audio-mmio";
+
+       pinfo.parent = dev->dev;
+       pinfo.name = "hdmi-lpe-audio";
+       pinfo.id = -1;
+       pinfo.res = rsc;
+       pinfo.num_res = 2;
+       pinfo.data = pdata;
+       pinfo.size_data = sizeof(*pdata);
+       pinfo.dma_mask = DMA_BIT_MASK(32);
+
+       spin_lock_init(&pdata->lpe_audio_slock);
+
+       platdev = platform_device_register_full(&pinfo);
+       if (IS_ERR(platdev)) {
+               ret = PTR_ERR(platdev);
+               DRM_ERROR("Failed to allocate LPE audio platform device\n");
+               goto err;
+       }
+
+       kfree(rsc);
+
+       return platdev;
+
+err:
+       kfree(rsc);
+       kfree(pdata);
+       return ERR_PTR(ret);
+}
+
+static void lpe_audio_platdev_destroy(struct drm_i915_private *dev_priv)
+{
+       platform_device_unregister(dev_priv->lpe_audio.platdev);
+       kfree(dev_priv->lpe_audio.platdev->dev.dma_mask);
+}
+
+static void lpe_audio_irq_unmask(struct irq_data *d)
+{
+       struct drm_i915_private *dev_priv = d->chip_data;
+       unsigned long irqflags;
+       u32 val = (I915_LPE_PIPE_A_INTERRUPT |
+               I915_LPE_PIPE_B_INTERRUPT);
+
+       if (IS_CHERRYVIEW(dev_priv))
+               val |= I915_LPE_PIPE_C_INTERRUPT;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+       dev_priv->irq_mask &= ~val;
+       I915_WRITE(VLV_IIR, val);
+       I915_WRITE(VLV_IIR, val);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       POSTING_READ(VLV_IMR);
+
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+static void lpe_audio_irq_mask(struct irq_data *d)
+{
+       struct drm_i915_private *dev_priv = d->chip_data;
+       unsigned long irqflags;
+       u32 val = (I915_LPE_PIPE_A_INTERRUPT |
+               I915_LPE_PIPE_B_INTERRUPT);
+
+       if (IS_CHERRYVIEW(dev_priv))
+               val |= I915_LPE_PIPE_C_INTERRUPT;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+
+       dev_priv->irq_mask |= val;
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IIR, val);
+       I915_WRITE(VLV_IIR, val);
+       POSTING_READ(VLV_IIR);
+
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+static struct irq_chip lpe_audio_irqchip = {
+       .name = "hdmi_lpe_audio_irqchip",
+       .irq_mask = lpe_audio_irq_mask,
+       .irq_unmask = lpe_audio_irq_unmask,
+};
+
+static int lpe_audio_irq_init(struct drm_i915_private *dev_priv)
+{
+       int irq = dev_priv->lpe_audio.irq;
+
+       WARN_ON(!intel_irqs_enabled(dev_priv));
+       irq_set_chip_and_handler_name(irq,
+                               &lpe_audio_irqchip,
+                               handle_simple_irq,
+                               "hdmi_lpe_audio_irq_handler");
+
+       return irq_set_chip_data(irq, dev_priv);
+}
+
+static bool lpe_audio_detect(struct drm_i915_private *dev_priv)
+{
+       int lpe_present = false;
+
+       if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
+               static const struct pci_device_id atom_hdaudio_ids[] = {
+                       /* Baytrail */
+                       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0f04)},
+                       /* Braswell */
+                       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2284)},
+                       {}
+               };
+
+               if (!pci_dev_present(atom_hdaudio_ids)) {
+                       DRM_INFO("%s\n", "HDaudio controller not detected, using LPE audio instead\n");
+                       lpe_present = true;
+               }
+       }
+       return lpe_present;
+}
+
+static int lpe_audio_setup(struct drm_i915_private *dev_priv)
+{
+       int ret;
+
+       dev_priv->lpe_audio.irq = irq_alloc_desc(0);
+       if (dev_priv->lpe_audio.irq < 0) {
+               DRM_ERROR("Failed to allocate IRQ desc: %d\n",
+                       dev_priv->lpe_audio.irq);
+               ret = dev_priv->lpe_audio.irq;
+               goto err;
+       }
+
+       DRM_DEBUG("irq = %d\n", dev_priv->lpe_audio.irq);
+
+       ret = lpe_audio_irq_init(dev_priv);
+
+       if (ret) {
+               DRM_ERROR("Failed to initialize irqchip for lpe audio: %d\n",
+                       ret);
+               goto err_free_irq;
+       }
+
+       dev_priv->lpe_audio.platdev = lpe_audio_platdev_create(dev_priv);
+
+       if (IS_ERR(dev_priv->lpe_audio.platdev)) {
+               ret = PTR_ERR(dev_priv->lpe_audio.platdev);
+               DRM_ERROR("Failed to create lpe audio platform device: %d\n",
+                       ret);
+               goto err_free_irq;
+       }
+
+       /* enable chicken bit; at least this is required for Dell Wyse 3040
+        * with DP outputs (but only sometimes by some reason!)
+        */
+       I915_WRITE(VLV_AUD_CHICKEN_BIT_REG, VLV_CHICKEN_BIT_DBG_ENABLE);
+
+       return 0;
+err_free_irq:
+       irq_free_desc(dev_priv->lpe_audio.irq);
+err:
+       dev_priv->lpe_audio.irq = -1;
+       dev_priv->lpe_audio.platdev = NULL;
+       return ret;
+}
+
+/**
+ * intel_lpe_audio_irq_handler() - forwards the LPE audio irq
+ * @dev_priv: the i915 drm device private data
+ *
+ * the LPE Audio irq is forwarded to the irq handler registered by LPE audio
+ * driver.
+ */
+void intel_lpe_audio_irq_handler(struct drm_i915_private *dev_priv)
+{
+       int ret;
+
+       if (!HAS_LPE_AUDIO(dev_priv))
+               return;
+
+       ret = generic_handle_irq(dev_priv->lpe_audio.irq);
+       if (ret)
+               DRM_ERROR_RATELIMITED("error handling LPE audio irq: %d\n",
+                               ret);
+}
+
+/**
+ * intel_lpe_audio_init() - detect and setup the bridge between HDMI LPE Audio
+ * driver and i915
+ * @dev_priv: the i915 drm device private data
+ *
+ * Return: 0 if successful. non-zero if detection or
+ * llocation/initialization fails
+ */
+int intel_lpe_audio_init(struct drm_i915_private *dev_priv)
+{
+       int ret = -ENODEV;
+
+       if (lpe_audio_detect(dev_priv)) {
+               ret = lpe_audio_setup(dev_priv);
+               if (ret < 0)
+                       DRM_ERROR("failed to setup LPE Audio bridge\n");
+       }
+       return ret;
+}
+
+/**
+ * intel_lpe_audio_teardown() - destroy the bridge between HDMI LPE
+ * audio driver and i915
+ * @dev_priv: the i915 drm device private data
+ *
+ * release all the resources for LPE audio <-> i915 bridge.
+ */
+void intel_lpe_audio_teardown(struct drm_i915_private *dev_priv)
+{
+       struct irq_desc *desc;
+
+       if (!HAS_LPE_AUDIO(dev_priv))
+               return;
+
+       desc = irq_to_desc(dev_priv->lpe_audio.irq);
+
+       lpe_audio_irq_mask(&desc->irq_data);
+
+       lpe_audio_platdev_destroy(dev_priv);
+
+       irq_free_desc(dev_priv->lpe_audio.irq);
+}
+
+
+/**
+ * intel_lpe_audio_notify() - notify lpe audio event
+ * audio driver and i915
+ * @dev_priv: the i915 drm device private data
+ * @eld : ELD data
+ * @port: port id
+ * @tmds_clk_speed: tmds clock frequency in Hz
+ *
+ * Notify lpe audio driver of eld change.
+ */
+void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
+                           void *eld, int port, int pipe, int tmds_clk_speed,
+                           bool dp_output, int link_rate)
+{
+       unsigned long irq_flags;
+       struct intel_hdmi_lpe_audio_pdata *pdata = NULL;
+       u32 audio_enable;
+
+       if (!HAS_LPE_AUDIO(dev_priv))
+               return;
+
+       pdata = dev_get_platdata(
+               &(dev_priv->lpe_audio.platdev->dev));
+
+       spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags);
+
+       audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port));
+
+       if (eld != NULL) {
+               memcpy(pdata->eld.eld_data, eld,
+                       HDMI_MAX_ELD_BYTES);
+               pdata->eld.port_id = port;
+               pdata->eld.pipe_id = pipe;
+               pdata->hdmi_connected = true;
+
+               pdata->dp_output = dp_output;
+               if (tmds_clk_speed)
+                       pdata->tmds_clock_speed = tmds_clk_speed;
+               if (link_rate)
+                       pdata->link_rate = link_rate;
+
+               /* Unmute the amp for both DP and HDMI */
+               I915_WRITE(VLV_AUD_PORT_EN_DBG(port),
+                          audio_enable & ~VLV_AMP_MUTE);
+
+       } else {
+               memset(pdata->eld.eld_data, 0,
+                       HDMI_MAX_ELD_BYTES);
+               pdata->hdmi_connected = false;
+               pdata->dp_output = false;
+
+               /* Mute the amp for both DP and HDMI */
+               I915_WRITE(VLV_AUD_PORT_EN_DBG(port),
+                          audio_enable | VLV_AMP_MUTE);
+       }
+
+       if (pdata->notify_audio_lpe)
+               pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev);
+       else
+               pdata->notify_pending = true;
+
+       spin_unlock_irqrestore(&pdata->lpe_audio_slock,
+                       irq_flags);
+}
index 8f131a08d440cf02cbcd9ffe255b94e3f4eb6077..242a73e66d82862bea3ba881474efe327cd02d6e 100644 (file)
@@ -273,7 +273,7 @@ skl_update_plane(struct drm_plane *drm_plane,
 
        I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
        I915_WRITE(PLANE_SURF(pipe, plane),
-                  intel_fb_gtt_offset(fb, rotation) + surf_addr);
+                  intel_plane_ggtt_offset(plane_state) + surf_addr);
        POSTING_READ(PLANE_SURF(pipe, plane));
 }
 
@@ -458,7 +458,7 @@ vlv_update_plane(struct drm_plane *dplane,
        I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(SPCNTR(pipe, plane), sprctl);
        I915_WRITE(SPSURF(pipe, plane),
-                  intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
+                  intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
        POSTING_READ(SPSURF(pipe, plane));
 }
 
@@ -594,7 +594,7 @@ ivb_update_plane(struct drm_plane *plane,
                I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
        I915_WRITE(SPRSURF(pipe),
-                  intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
+                  intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
        POSTING_READ(SPRSURF(pipe));
 }
 
@@ -721,7 +721,7 @@ ilk_update_plane(struct drm_plane *plane,
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
        I915_WRITE(DVSSURF(pipe),
-                  intel_fb_gtt_offset(fb, rotation) + dvssurf_offset);
+                  intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
        POSTING_READ(DVSSURF(pipe));
 }
 
index 74856a8b8f35943b08a59f8aed5a546e98058d3c..e64f52464ecf55b83a17f25b434cb9e1474c10e1 100644 (file)
@@ -222,6 +222,7 @@ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype)
                uint32_t mpllP;
 
                pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
+               mpllP = (mpllP >> 8) & 0xf;
                if (!mpllP)
                        mpllP = 4;
 
@@ -232,7 +233,7 @@ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype)
                uint32_t clock;
 
                pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
-               return clock;
+               return clock / 1000;
        }
 
        ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
index ccdce1b4eec4b8bf183235ebae2eb5395a306430..d5e58a38f160182354b8c9a126bdcbb5d459f40a 100644 (file)
@@ -99,6 +99,7 @@ struct nv84_fence_priv {
        struct nouveau_bo *bo;
        struct nouveau_bo *bo_gart;
        u32 *suspend;
+       struct mutex mutex;
 };
 
 int  nv84_fence_context_new(struct nouveau_channel *);
index 187ecdb8200273baa77c41a42fbc65c3bcb93db6..21a5775028cc612e9a6c81e280777329f18233fd 100644 (file)
@@ -42,7 +42,7 @@ nouveau_led(struct drm_device *dev)
 }
 
 /* nouveau_led.c */
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
 int  nouveau_led_init(struct drm_device *dev);
 void nouveau_led_suspend(struct drm_device *dev);
 void nouveau_led_resume(struct drm_device *dev);
index 08f9c6fa0f7f210d3e3fd5a0fbe8f11ff40b1972..1fba3862274474f0001deaec9fefaf6b0fd324b4 100644 (file)
@@ -313,7 +313,8 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
        if (!(ret = nvif_unpack(-ENOSYS, &data, &size, argv->v0, 0, 0, true))) {
                /* block access to objects not created via this interface */
                owner = argv->v0.owner;
-               if (argv->v0.object == 0ULL)
+               if (argv->v0.object == 0ULL &&
+                   argv->v0.type != NVIF_IOCTL_V0_DEL)
                        argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
                else
                        argv->v0.owner = NVDRM_OBJECT_USIF;
index 2c2c645076614b4f9c187d24a5e9d2667ea27778..32097fd615fd1e3a5954019c02dec36bd2e8db8c 100644 (file)
@@ -4052,6 +4052,11 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
                }
        }
 
+       for_each_crtc_in_state(state, crtc, crtc_state, i) {
+               if (crtc->state->event)
+                       drm_crtc_vblank_get(crtc);
+       }
+
        /* Update plane(s). */
        for_each_plane_in_state(state, plane, plane_state, i) {
                struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane->state);
@@ -4101,6 +4106,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
                        drm_crtc_send_vblank_event(crtc, crtc->state->event);
                        spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
                        crtc->state->event = NULL;
+                       drm_crtc_vblank_put(crtc);
                }
        }
 
index 52b87ae83e7b4d0df54e003d58783eddd8deb6f5..f0b322bec7df22de23bbae372333fb484ac6d9ed 100644 (file)
@@ -107,8 +107,10 @@ nv84_fence_context_del(struct nouveau_channel *chan)
        struct nv84_fence_chan *fctx = chan->fence;
 
        nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
+       mutex_lock(&priv->mutex);
        nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
        nouveau_bo_vma_del(priv->bo, &fctx->vma);
+       mutex_unlock(&priv->mutex);
        nouveau_fence_context_del(&fctx->base);
        chan->fence = NULL;
        nouveau_fence_context_free(&fctx->base);
@@ -134,11 +136,13 @@ nv84_fence_context_new(struct nouveau_channel *chan)
        fctx->base.sync32 = nv84_fence_sync32;
        fctx->base.sequence = nv84_fence_read(chan);
 
+       mutex_lock(&priv->mutex);
        ret = nouveau_bo_vma_add(priv->bo, cli->vm, &fctx->vma);
        if (ret == 0) {
                ret = nouveau_bo_vma_add(priv->bo_gart, cli->vm,
                                        &fctx->vma_gart);
        }
+       mutex_unlock(&priv->mutex);
 
        if (ret)
                nv84_fence_context_del(chan);
@@ -212,6 +216,8 @@ nv84_fence_create(struct nouveau_drm *drm)
        priv->base.context_base = dma_fence_context_alloc(priv->base.contexts);
        priv->base.uevent = true;
 
+       mutex_init(&priv->mutex);
+
        /* Use VRAM if there is any ; otherwise fallback to system memory */
        domain = drm->device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM :
                         /*
index 6f0436df021953337ba29f0ff9c02c507214b07b..f8f2f16c22a2a2502bf283c63a5d1fc124d0ff89 100644 (file)
@@ -59,7 +59,7 @@ gt215_hda_eld(NV50_DISP_MTHD_V1)
                        );
                }
                for (i = 0; i < size; i++)
-                       nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
+                       nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]);
                for (; i < 0x60; i++)
                        nvkm_wr32(device, 0x61c440 + soff, (i << 8));
                nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003);
index 567466f93cd5d9645020e3b89c282808d88397e4..0db8efbf1c2e2e9cd84b689098bdba9d666843bc 100644 (file)
@@ -433,8 +433,6 @@ nv50_disp_dptmds_war(struct nvkm_device *device)
        case 0x94:
        case 0x96:
        case 0x98:
-       case 0xaa:
-       case 0xac:
                return true;
        default:
                break;
index e0c143b865f39cb36074b5e524638530cadeede9..30bd4a6a9d466e11755bf95cee6929473ae65adf 100644 (file)
  *   2.46.0 - Add PFP_SYNC_ME support on evergreen
  *   2.47.0 - Add UVD_NO_OP register support
  *   2.48.0 - TA_CS_BC_BASE_ADDR allowed on SI
+ *   2.49.0 - DRM_RADEON_GEM_INFO ioctl returns correct vram_size/visible values
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       48
+#define KMS_DRIVER_MINOR       49
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index 0bcffd8a7bd3ceac0de37cd0b44344011963be77..96683f5b2b1b722db08de97550aa8cdf99444a1c 100644 (file)
@@ -220,8 +220,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
 
        man = &rdev->mman.bdev.man[TTM_PL_VRAM];
 
-       args->vram_size = rdev->mc.real_vram_size;
-       args->vram_visible = (u64)man->size << PAGE_SHIFT;
+       args->vram_size = (u64)man->size << PAGE_SHIFT;
+       args->vram_visible = rdev->mc.visible_vram_size;
        args->vram_visible -= rdev->vram_pin_size;
        args->gart_size = rdev->mc.gtt_size;
        args->gart_size -= rdev->gart_pin_size;
index f31a778b085148fea4a52599c6b89be203889781..b22d0f83f8e38a9ee0d0eb7381e95d6b90442b61 100644 (file)
@@ -168,7 +168,7 @@ struct cp2112_device {
        atomic_t xfer_avail;
        struct gpio_chip gc;
        u8 *in_out_buffer;
-       spinlock_t lock;
+       struct mutex lock;
 
        struct gpio_desc *desc[8];
        bool gpio_poll;
@@ -186,10 +186,9 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
        u8 *buf = dev->in_out_buffer;
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&dev->lock, flags);
+       mutex_lock(&dev->lock);
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
                                 CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
@@ -213,8 +212,8 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
        ret = 0;
 
 exit:
-       spin_unlock_irqrestore(&dev->lock, flags);
-       return ret <= 0 ? ret : -EIO;
+       mutex_unlock(&dev->lock);
+       return ret < 0 ? ret : -EIO;
 }
 
 static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
@@ -222,10 +221,9 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
        u8 *buf = dev->in_out_buffer;
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&dev->lock, flags);
+       mutex_lock(&dev->lock);
 
        buf[0] = CP2112_GPIO_SET;
        buf[1] = value ? 0xff : 0;
@@ -237,7 +235,7 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        if (ret < 0)
                hid_err(hdev, "error setting GPIO values: %d\n", ret);
 
-       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock);
 }
 
 static int cp2112_gpio_get_all(struct gpio_chip *chip)
@@ -245,10 +243,9 @@ static int cp2112_gpio_get_all(struct gpio_chip *chip)
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
        u8 *buf = dev->in_out_buffer;
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&dev->lock, flags);
+       mutex_lock(&dev->lock);
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf,
                                 CP2112_GPIO_GET_LENGTH, HID_FEATURE_REPORT,
@@ -262,7 +259,7 @@ static int cp2112_gpio_get_all(struct gpio_chip *chip)
        ret = buf[1];
 
 exit:
-       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock);
 
        return ret;
 }
@@ -284,10 +281,9 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
        struct cp2112_device *dev = gpiochip_get_data(chip);
        struct hid_device *hdev = dev->hdev;
        u8 *buf = dev->in_out_buffer;
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&dev->lock, flags);
+       mutex_lock(&dev->lock);
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
                                 CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
@@ -308,7 +304,7 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
                goto fail;
        }
 
-       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock);
 
        /*
         * Set gpio value when output direction is already set,
@@ -319,7 +315,7 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip,
        return 0;
 
 fail:
-       spin_unlock_irqrestore(&dev->lock, flags);
+       mutex_unlock(&dev->lock);
        return ret < 0 ? ret : -EIO;
 }
 
@@ -1235,7 +1231,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        if (!dev->in_out_buffer)
                return -ENOMEM;
 
-       spin_lock_init(&dev->lock);
+       mutex_init(&dev->lock);
 
        ret = hid_parse(hdev);
        if (ret) {
index f46f2c5117fae76a1c87105363e5c8db4c8673a3..350accfee8e85b2e545c0171f6582f4e62655b50 100644 (file)
@@ -76,6 +76,9 @@
 #define USB_VENDOR_ID_ALPS_JP          0x044E
 #define HID_DEVICE_ID_ALPS_U1_DUAL     0x120B
 
+#define USB_VENDOR_ID_AMI              0x046b
+#define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE      0xff10
+
 #define USB_VENDOR_ID_ANTON            0x1130
 #define USB_DEVICE_ID_ANTON_TOUCH_PAD  0x3101
 
index c5c5fbe9d60577f44085d86a7fb5cf60efb6acd3..52026dc94d5c4b0306ce585be293cbe2cb1910d9 100644 (file)
@@ -872,7 +872,7 @@ static const struct hid_device_id lg_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
                .driver_data = LG_NOGET | LG_FF4 },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
-               .driver_data = LG_FF2 },
+               .driver_data = LG_NOGET | LG_FF2 },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
                .driver_data = LG_FF3 },
        { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
index e9d6cc7cdfc5c8019422d45914dc0363448bcb12..30a2977e26454f10fd72b855ec0b634aa868dcae 100644 (file)
@@ -57,6 +57,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS },
+       { USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE, HID_QUIRK_ALWAYS_POLL },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
index 0884dc9554fdf632e684aa3689292368d5fb7e3b..672145b0d8f584d8fce50a74e799b36319448cb4 100644 (file)
@@ -166,19 +166,21 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
                wacom->id[0] = STYLUS_DEVICE_ID;
        }
 
-       pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
-       if (features->pressure_max > 255)
-               pressure = (pressure << 1) | ((data[4] >> 6) & 1);
-       pressure += (features->pressure_max + 1) / 2;
-
-       input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
-       input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
-       input_report_abs(input, ABS_PRESSURE, pressure);
-
-       input_report_key(input, BTN_TOUCH, data[4] & 0x08);
-       input_report_key(input, BTN_STYLUS, data[4] & 0x10);
-       /* Only allow the stylus2 button to be reported for the pen tool. */
-       input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+       if (prox) {
+               pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+               if (features->pressure_max > 255)
+                       pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+               pressure += (features->pressure_max + 1) / 2;
+
+               input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+               input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+               input_report_abs(input, ABS_PRESSURE, pressure);
+
+               input_report_key(input, BTN_TOUCH, data[4] & 0x08);
+               input_report_key(input, BTN_STYLUS, data[4] & 0x10);
+               /* Only allow the stylus2 button to be reported for the pen tool. */
+               input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+       }
 
        if (!prox)
                wacom->id[0] = 0;
index cd49cb17eb7fb385ddbf507ef14b2ea2be090159..308dbda700ebdaeb02f222aa46dc7bb79c24c0da 100644 (file)
@@ -383,6 +383,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel,
                return ret;
        }
 
+       init_cached_read_index(channel);
        next_read_location = hv_get_next_read_location(inring_info);
        next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
                                                    sizeof(desc),
index 2bbf0c521bebb5c44840a8ce5296024910d8d73d..7d61b566e148dddd21ce2986cba233567802f93c 100644 (file)
@@ -775,7 +775,7 @@ static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc)
 
 static int palmas_gpadc_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct palmas_gpadc *adc = iio_priv(indio_dev);
        int wakeup = adc->wakeup1_enable || adc->wakeup2_enable;
        int ret;
@@ -798,7 +798,7 @@ static int palmas_gpadc_suspend(struct device *dev)
 
 static int palmas_gpadc_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct palmas_gpadc *adc = iio_priv(indio_dev);
        int wakeup = adc->wakeup1_enable || adc->wakeup2_enable;
        int ret;
index 9a081465c42f4225d26747a734c5daceea68c842..6bb23a49e81eb8cf304a2f81f50c5e36a91e2d48 100644 (file)
@@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, afe4403_of_match);
 
 static int __maybe_unused afe4403_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev));
        struct afe4403_data *afe = iio_priv(indio_dev);
        int ret;
 
@@ -443,7 +443,7 @@ static int __maybe_unused afe4403_suspend(struct device *dev)
 
 static int __maybe_unused afe4403_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev));
        struct afe4403_data *afe = iio_priv(indio_dev);
        int ret;
 
index 45266404f7e3b5bd7c7790a0b05ff298fc24d5a9..964f5231a831c437c277e4bcfe292720104043f7 100644 (file)
@@ -428,7 +428,7 @@ MODULE_DEVICE_TABLE(of, afe4404_of_match);
 
 static int __maybe_unused afe4404_suspend(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
        struct afe4404_data *afe = iio_priv(indio_dev);
        int ret;
 
@@ -449,7 +449,7 @@ static int __maybe_unused afe4404_suspend(struct device *dev)
 
 static int __maybe_unused afe4404_resume(struct device *dev)
 {
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
        struct afe4404_data *afe = iio_priv(indio_dev);
        int ret;
 
index 90ab8a2d2846f8a8591ee6b1615dce2c984020ef..183c14329d6e350f6325b0e77a95dcb56de892dd 100644 (file)
@@ -238,7 +238,7 @@ static irqreturn_t max30100_interrupt_handler(int irq, void *private)
 
        mutex_lock(&data->lock);
 
-       while (cnt || (cnt = max30100_fifo_count(data) > 0)) {
+       while (cnt || (cnt = max30100_fifo_count(data)) > 0) {
                ret = max30100_read_measurement(data);
                if (ret)
                        break;
index 9c47bc98f3acdea4cb4b56b23a72e582c34a413b..2a22ad92033306d02eec60f288c00a65d5186c37 100644 (file)
@@ -71,7 +71,8 @@
  * a) select an implementation using busy loop polling on those systems
  * b) use the checksum to do some probabilistic decoding
  */
-#define DHT11_START_TRANSMISSION       18  /* ms */
+#define DHT11_START_TRANSMISSION_MIN   18000  /* us */
+#define DHT11_START_TRANSMISSION_MAX   20000  /* us */
 #define DHT11_MIN_TIMERES      34000  /* ns */
 #define DHT11_THRESHOLD                49000  /* ns */
 #define DHT11_AMBIG_LOW                23000  /* ns */
@@ -228,7 +229,8 @@ static int dht11_read_raw(struct iio_dev *iio_dev,
                ret = gpio_direction_output(dht11->gpio, 0);
                if (ret)
                        goto err;
-               msleep(DHT11_START_TRANSMISSION);
+               usleep_range(DHT11_START_TRANSMISSION_MIN,
+                            DHT11_START_TRANSMISSION_MAX);
                ret = gpio_direction_input(dht11->gpio);
                if (ret)
                        goto err;
index 11447ab1055cd4beadf7eca752bdf9494d76cef1..bf5c36e229bacd63dd7e77d028aa65fb4555ce89 100644 (file)
@@ -901,7 +901,7 @@ void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
        data->enabled = true;
        if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
                retval = disable_irq_wake(irq);
-               if (!retval)
+               if (retval)
                        dev_warn(&rmi_dev->dev,
                                 "Failed to disable irq for wake: %d\n",
                                 retval);
@@ -936,7 +936,7 @@ void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
        disable_irq(irq);
        if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
                retval = enable_irq_wake(irq);
-               if (!retval)
+               if (retval)
                        dev_warn(&rmi_dev->dev,
                                 "Failed to enable irq for wake: %d\n",
                                 retval);
index 83cf11312fd971e0cacc16bd70eb474dd9c13b52..c9d1c91e1887094f2ef740d9eee3af8d16ee6f82 100644 (file)
@@ -682,7 +682,7 @@ static int wm97xx_probe(struct device *dev)
        }
        platform_set_drvdata(wm->battery_dev, wm);
        wm->battery_dev->dev.parent = dev;
-       wm->battery_dev->dev.platform_data = pdata->batt_pdata;
+       wm->battery_dev->dev.platform_data = pdata ? pdata->batt_pdata : NULL;
        ret = platform_device_add(wm->battery_dev);
        if (ret < 0)
                goto batt_reg_err;
index 23909804ffb840d3187f21f67180a634a769425e..0def99590d162ebcfb86a16a6b9d5adf96f19cb6 100644 (file)
@@ -2733,7 +2733,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
                if (intmask & SDHCI_INT_RETUNE)
                        mmc_retune_needed(host->mmc);
 
-               if (intmask & SDHCI_INT_CARD_INT) {
+               if ((intmask & SDHCI_INT_CARD_INT) &&
+                   (host->ier & SDHCI_INT_CARD_INT)) {
                        sdhci_enable_sdio_irq_nolock(host, false);
                        host->thread_isr |= SDHCI_INT_CARD_INT;
                        result = IRQ_WAKE_THREAD;
index c12d2618eebf76397b2e71eaeb6f2fafa938fea6..3872ab96b80a39eecbb1d0b8150a2e8288915e46 100644 (file)
@@ -1152,6 +1152,12 @@ static void init_ring(struct net_device *dev)
                if (skb == NULL)
                        break;
                np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+               if (pci_dma_mapping_error(np->pci_dev,
+                                         np->rx_info[i].mapping)) {
+                       dev_kfree_skb(skb);
+                       np->rx_info[i].skb = NULL;
+                       break;
+               }
                /* Grrr, we cannot offset to correctly align the IP header. */
                np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
        }
@@ -1182,8 +1188,9 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
 {
        struct netdev_private *np = netdev_priv(dev);
        unsigned int entry;
+       unsigned int prev_tx;
        u32 status;
-       int i;
+       int i, j;
 
        /*
         * be cautious here, wrapping the queue has weird semantics
@@ -1201,6 +1208,7 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
        }
 #endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
 
+       prev_tx = np->cur_tx;
        entry = np->cur_tx % TX_RING_SIZE;
        for (i = 0; i < skb_num_frags(skb); i++) {
                int wrap_ring = 0;
@@ -1234,6 +1242,11 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
                                               skb_frag_size(this_frag),
                                               PCI_DMA_TODEVICE);
                }
+               if (pci_dma_mapping_error(np->pci_dev,
+                                         np->tx_info[entry].mapping)) {
+                       dev->stats.tx_dropped++;
+                       goto err_out;
+               }
 
                np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
                np->tx_ring[entry].status = cpu_to_le32(status);
@@ -1268,8 +1281,30 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
 
        return NETDEV_TX_OK;
-}
 
+err_out:
+       entry = prev_tx % TX_RING_SIZE;
+       np->tx_info[entry].skb = NULL;
+       if (i > 0) {
+               pci_unmap_single(np->pci_dev,
+                                np->tx_info[entry].mapping,
+                                skb_first_frag_len(skb),
+                                PCI_DMA_TODEVICE);
+               np->tx_info[entry].mapping = 0;
+               entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
+               for (j = 1; j < i; j++) {
+                       pci_unmap_single(np->pci_dev,
+                                        np->tx_info[entry].mapping,
+                                        skb_frag_size(
+                                               &skb_shinfo(skb)->frags[j-1]),
+                                        PCI_DMA_TODEVICE);
+                       entry++;
+               }
+       }
+       dev_kfree_skb_any(skb);
+       np->cur_tx = prev_tx;
+       return NETDEV_TX_OK;
+}
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
@@ -1569,6 +1604,12 @@ static void refill_rx_ring(struct net_device *dev)
                                break;  /* Better luck next round. */
                        np->rx_info[entry].mapping =
                                pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+                       if (pci_dma_mapping_error(np->pci_dev,
+                                               np->rx_info[entry].mapping)) {
+                               dev_kfree_skb(skb);
+                               np->rx_info[entry].skb = NULL;
+                               break;
+                       }
                        np->rx_ring[entry].rxaddr =
                                cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
                }
index c0fb80acc2dad4b91d3b3cb8198be50dc9597fbd..baba2db9d9c25988da94cb323e5d1a6832a12b51 100644 (file)
 #define DEFAULT_RX_RING_SIZE   512 /* must be power of 2 */
 #define MIN_RX_RING_SIZE       64
 #define MAX_RX_RING_SIZE       8192
-#define RX_RING_BYTES(bp)      (sizeof(struct macb_dma_desc)   \
+#define RX_RING_BYTES(bp)      (macb_dma_desc_get_size(bp)     \
                                 * (bp)->rx_ring_size)
 
 #define DEFAULT_TX_RING_SIZE   512 /* must be power of 2 */
 #define MIN_TX_RING_SIZE       64
 #define MAX_TX_RING_SIZE       4096
-#define TX_RING_BYTES(bp)      (sizeof(struct macb_dma_desc)   \
+#define TX_RING_BYTES(bp)      (macb_dma_desc_get_size(bp)     \
                                 * (bp)->tx_ring_size)
 
 /* level of occupied TX descriptors under which we wake up TX process */
  */
 #define MACB_HALT_TIMEOUT      1230
 
+/* DMA buffer descriptor might be different size
+ * depends on hardware configuration.
+ */
+static unsigned int macb_dma_desc_get_size(struct macb *bp)
+{
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+               return sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_64);
+#endif
+       return sizeof(struct macb_dma_desc);
+}
+
+static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int idx)
+{
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       /* Dma buffer descriptor is 4 words length (instead of 2 words)
+        * for 64b GEM.
+        */
+       if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+               idx <<= 1;
+#endif
+       return idx;
+}
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc)
+{
+       return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc));
+}
+#endif
+
 /* Ring buffer accessors */
 static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index)
 {
@@ -87,7 +118,9 @@ static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index)
 static struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue,
                                          unsigned int index)
 {
-       return &queue->tx_ring[macb_tx_ring_wrap(queue->bp, index)];
+       index = macb_tx_ring_wrap(queue->bp, index);
+       index = macb_adj_dma_desc_idx(queue->bp, index);
+       return &queue->tx_ring[index];
 }
 
 static struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue,
@@ -101,7 +134,7 @@ static dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index)
        dma_addr_t offset;
 
        offset = macb_tx_ring_wrap(queue->bp, index) *
-                sizeof(struct macb_dma_desc);
+                       macb_dma_desc_get_size(queue->bp);
 
        return queue->tx_ring_dma + offset;
 }
@@ -113,7 +146,9 @@ static unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index)
 
 static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
 {
-       return &bp->rx_ring[macb_rx_ring_wrap(bp, index)];
+       index = macb_rx_ring_wrap(bp, index);
+       index = macb_adj_dma_desc_idx(bp, index);
+       return &bp->rx_ring[index];
 }
 
 static void *macb_rx_buffer(struct macb *bp, unsigned int index)
@@ -560,12 +595,32 @@ static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb)
        }
 }
 
-static inline void macb_set_addr(struct macb_dma_desc *desc, dma_addr_t addr)
+static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr)
 {
-       desc->addr = (u32)addr;
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-       desc->addrh = (u32)(addr >> 32);
+       struct macb_dma_desc_64 *desc_64;
+
+       if (bp->hw_dma_cap == HW_DMA_CAP_64B) {
+               desc_64 = macb_64b_desc(bp, desc);
+               desc_64->addrh = upper_32_bits(addr);
+       }
 #endif
+       desc->addr = lower_32_bits(addr);
+}
+
+static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc)
+{
+       dma_addr_t addr = 0;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       struct macb_dma_desc_64 *desc_64;
+
+       if (bp->hw_dma_cap == HW_DMA_CAP_64B) {
+               desc_64 = macb_64b_desc(bp, desc);
+               addr = ((u64)(desc_64->addrh) << 32);
+       }
+#endif
+       addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
+       return addr;
 }
 
 static void macb_tx_error_task(struct work_struct *work)
@@ -649,16 +704,17 @@ static void macb_tx_error_task(struct work_struct *work)
 
        /* Set end of TX queue */
        desc = macb_tx_desc(queue, 0);
-       macb_set_addr(desc, 0);
+       macb_set_addr(bp, desc, 0);
        desc->ctrl = MACB_BIT(TX_USED);
 
        /* Make descriptor updates visible to hardware */
        wmb();
 
        /* Reinitialize the TX desc queue */
-       queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma));
+       queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-       queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32));
+       if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+               queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma));
 #endif
        /* Make TX ring reflect state of hardware */
        queue->tx_head = 0;
@@ -750,6 +806,7 @@ static void gem_rx_refill(struct macb *bp)
        unsigned int            entry;
        struct sk_buff          *skb;
        dma_addr_t              paddr;
+       struct macb_dma_desc *desc;
 
        while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail,
                          bp->rx_ring_size) > 0) {
@@ -759,6 +816,7 @@ static void gem_rx_refill(struct macb *bp)
                rmb();
 
                bp->rx_prepared_head++;
+               desc = macb_rx_desc(bp, entry);
 
                if (!bp->rx_skbuff[entry]) {
                        /* allocate sk_buff for this free entry in ring */
@@ -782,14 +840,14 @@ static void gem_rx_refill(struct macb *bp)
 
                        if (entry == bp->rx_ring_size - 1)
                                paddr |= MACB_BIT(RX_WRAP);
-                       macb_set_addr(&(bp->rx_ring[entry]), paddr);
-                       bp->rx_ring[entry].ctrl = 0;
+                       macb_set_addr(bp, desc, paddr);
+                       desc->ctrl = 0;
 
                        /* properly align Ethernet header */
                        skb_reserve(skb, NET_IP_ALIGN);
                } else {
-                       bp->rx_ring[entry].addr &= ~MACB_BIT(RX_USED);
-                       bp->rx_ring[entry].ctrl = 0;
+                       desc->addr &= ~MACB_BIT(RX_USED);
+                       desc->ctrl = 0;
                }
        }
 
@@ -835,16 +893,13 @@ static int gem_rx(struct macb *bp, int budget)
                bool rxused;
 
                entry = macb_rx_ring_wrap(bp, bp->rx_tail);
-               desc = &bp->rx_ring[entry];
+               desc = macb_rx_desc(bp, entry);
 
                /* Make hw descriptor updates visible to CPU */
                rmb();
 
                rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
-               addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-               addr |= ((u64)(desc->addrh) << 32);
-#endif
+               addr = macb_get_addr(bp, desc);
                ctrl = desc->ctrl;
 
                if (!rxused)
@@ -987,15 +1042,17 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag,
 static inline void macb_init_rx_ring(struct macb *bp)
 {
        dma_addr_t addr;
+       struct macb_dma_desc *desc = NULL;
        int i;
 
        addr = bp->rx_buffers_dma;
        for (i = 0; i < bp->rx_ring_size; i++) {
-               bp->rx_ring[i].addr = addr;
-               bp->rx_ring[i].ctrl = 0;
+               desc = macb_rx_desc(bp, i);
+               macb_set_addr(bp, desc, addr);
+               desc->ctrl = 0;
                addr += bp->rx_buffer_size;
        }
-       bp->rx_ring[bp->rx_ring_size - 1].addr |= MACB_BIT(RX_WRAP);
+       desc->addr |= MACB_BIT(RX_WRAP);
        bp->rx_tail = 0;
 }
 
@@ -1008,15 +1065,14 @@ static int macb_rx(struct macb *bp, int budget)
 
        for (tail = bp->rx_tail; budget > 0; tail++) {
                struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
-               u32 addr, ctrl;
+               u32 ctrl;
 
                /* Make hw descriptor updates visible to CPU */
                rmb();
 
-               addr = desc->addr;
                ctrl = desc->ctrl;
 
-               if (!(addr & MACB_BIT(RX_USED)))
+               if (!(desc->addr & MACB_BIT(RX_USED)))
                        break;
 
                if (ctrl & MACB_BIT(RX_SOF)) {
@@ -1336,7 +1392,7 @@ static unsigned int macb_tx_map(struct macb *bp,
        i = tx_head;
        entry = macb_tx_ring_wrap(bp, i);
        ctrl = MACB_BIT(TX_USED);
-       desc = &queue->tx_ring[entry];
+       desc = macb_tx_desc(queue, entry);
        desc->ctrl = ctrl;
 
        if (lso_ctrl) {
@@ -1358,7 +1414,7 @@ static unsigned int macb_tx_map(struct macb *bp,
                i--;
                entry = macb_tx_ring_wrap(bp, i);
                tx_skb = &queue->tx_skb[entry];
-               desc = &queue->tx_ring[entry];
+               desc = macb_tx_desc(queue, entry);
 
                ctrl = (u32)tx_skb->size;
                if (eof) {
@@ -1379,7 +1435,7 @@ static unsigned int macb_tx_map(struct macb *bp,
                        ctrl |= MACB_BF(MSS_MFS, mss_mfs);
 
                /* Set TX buffer descriptor */
-               macb_set_addr(desc, tx_skb->mapping);
+               macb_set_addr(bp, desc, tx_skb->mapping);
                /* desc->addr must be visible to hardware before clearing
                 * 'TX_USED' bit in desc->ctrl.
                 */
@@ -1586,11 +1642,9 @@ static void gem_free_rx_buffers(struct macb *bp)
                if (!skb)
                        continue;
 
-               desc = &bp->rx_ring[i];
-               addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-               addr |= ((u64)(desc->addrh) << 32);
-#endif
+               desc = macb_rx_desc(bp, i);
+               addr = macb_get_addr(bp, desc);
+
                dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size,
                                 DMA_FROM_DEVICE);
                dev_kfree_skb_any(skb);
@@ -1711,15 +1765,17 @@ out_err:
 static void gem_init_rings(struct macb *bp)
 {
        struct macb_queue *queue;
+       struct macb_dma_desc *desc = NULL;
        unsigned int q;
        int i;
 
        for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
                for (i = 0; i < bp->tx_ring_size; i++) {
-                       queue->tx_ring[i].addr = 0;
-                       queue->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+                       desc = macb_tx_desc(queue, i);
+                       macb_set_addr(bp, desc, 0);
+                       desc->ctrl = MACB_BIT(TX_USED);
                }
-               queue->tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP);
+               desc->ctrl |= MACB_BIT(TX_WRAP);
                queue->tx_head = 0;
                queue->tx_tail = 0;
        }
@@ -1733,16 +1789,18 @@ static void gem_init_rings(struct macb *bp)
 static void macb_init_rings(struct macb *bp)
 {
        int i;
+       struct macb_dma_desc *desc = NULL;
 
        macb_init_rx_ring(bp);
 
        for (i = 0; i < bp->tx_ring_size; i++) {
-               bp->queues[0].tx_ring[i].addr = 0;
-               bp->queues[0].tx_ring[i].ctrl = MACB_BIT(TX_USED);
+               desc = macb_tx_desc(&bp->queues[0], i);
+               macb_set_addr(bp, desc, 0);
+               desc->ctrl = MACB_BIT(TX_USED);
        }
        bp->queues[0].tx_head = 0;
        bp->queues[0].tx_tail = 0;
-       bp->queues[0].tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP);
+       desc->ctrl |= MACB_BIT(TX_WRAP);
 }
 
 static void macb_reset_hw(struct macb *bp)
@@ -1863,7 +1921,8 @@ static void macb_configure_dma(struct macb *bp)
                        dmacfg &= ~GEM_BIT(TXCOEN);
 
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-               dmacfg |= GEM_BIT(ADDR64);
+               if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+                       dmacfg |= GEM_BIT(ADDR64);
 #endif
                netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n",
                           dmacfg);
@@ -1910,14 +1969,16 @@ static void macb_init_hw(struct macb *bp)
        macb_configure_dma(bp);
 
        /* Initialize TX and RX buffers */
-       macb_writel(bp, RBQP, (u32)(bp->rx_ring_dma));
+       macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma));
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-       macb_writel(bp, RBQPH, (u32)(bp->rx_ring_dma >> 32));
+       if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+               macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma));
 #endif
        for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
-               queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma));
+               queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-               queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32));
+               if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+                       queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma));
 #endif
 
                /* Enable interrupts */
@@ -2627,7 +2688,8 @@ static int macb_init(struct platform_device *pdev)
                        queue->IMR  = GEM_IMR(hw_q - 1);
                        queue->TBQP = GEM_TBQP(hw_q - 1);
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-                       queue->TBQPH = GEM_TBQPH(hw_q -1);
+                       if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+                               queue->TBQPH = GEM_TBQPH(hw_q - 1);
 #endif
                } else {
                        /* queue0 uses legacy registers */
@@ -2637,7 +2699,8 @@ static int macb_init(struct platform_device *pdev)
                        queue->IMR  = MACB_IMR;
                        queue->TBQP = MACB_TBQP;
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-                       queue->TBQPH = MACB_TBQPH;
+                       if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+                               queue->TBQPH = MACB_TBQPH;
 #endif
                }
 
@@ -2730,13 +2793,14 @@ static int macb_init(struct platform_device *pdev)
 static int at91ether_start(struct net_device *dev)
 {
        struct macb *lp = netdev_priv(dev);
+       struct macb_dma_desc *desc;
        dma_addr_t addr;
        u32 ctl;
        int i;
 
        lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev,
                                         (AT91ETHER_MAX_RX_DESCR *
-                                         sizeof(struct macb_dma_desc)),
+                                         macb_dma_desc_get_size(lp)),
                                         &lp->rx_ring_dma, GFP_KERNEL);
        if (!lp->rx_ring)
                return -ENOMEM;
@@ -2748,7 +2812,7 @@ static int at91ether_start(struct net_device *dev)
        if (!lp->rx_buffers) {
                dma_free_coherent(&lp->pdev->dev,
                                  AT91ETHER_MAX_RX_DESCR *
-                                 sizeof(struct macb_dma_desc),
+                                 macb_dma_desc_get_size(lp),
                                  lp->rx_ring, lp->rx_ring_dma);
                lp->rx_ring = NULL;
                return -ENOMEM;
@@ -2756,13 +2820,14 @@ static int at91ether_start(struct net_device *dev)
 
        addr = lp->rx_buffers_dma;
        for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) {
-               lp->rx_ring[i].addr = addr;
-               lp->rx_ring[i].ctrl = 0;
+               desc = macb_rx_desc(lp, i);
+               macb_set_addr(lp, desc, addr);
+               desc->ctrl = 0;
                addr += AT91ETHER_MAX_RBUFF_SZ;
        }
 
        /* Set the Wrap bit on the last descriptor */
-       lp->rx_ring[AT91ETHER_MAX_RX_DESCR - 1].addr |= MACB_BIT(RX_WRAP);
+       desc->addr |= MACB_BIT(RX_WRAP);
 
        /* Reset buffer index */
        lp->rx_tail = 0;
@@ -2834,7 +2899,7 @@ static int at91ether_close(struct net_device *dev)
 
        dma_free_coherent(&lp->pdev->dev,
                          AT91ETHER_MAX_RX_DESCR *
-                         sizeof(struct macb_dma_desc),
+                         macb_dma_desc_get_size(lp),
                          lp->rx_ring, lp->rx_ring_dma);
        lp->rx_ring = NULL;
 
@@ -2885,13 +2950,15 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
 static void at91ether_rx(struct net_device *dev)
 {
        struct macb *lp = netdev_priv(dev);
+       struct macb_dma_desc *desc;
        unsigned char *p_recv;
        struct sk_buff *skb;
        unsigned int pktlen;
 
-       while (lp->rx_ring[lp->rx_tail].addr & MACB_BIT(RX_USED)) {
+       desc = macb_rx_desc(lp, lp->rx_tail);
+       while (desc->addr & MACB_BIT(RX_USED)) {
                p_recv = lp->rx_buffers + lp->rx_tail * AT91ETHER_MAX_RBUFF_SZ;
-               pktlen = MACB_BF(RX_FRMLEN, lp->rx_ring[lp->rx_tail].ctrl);
+               pktlen = MACB_BF(RX_FRMLEN, desc->ctrl);
                skb = netdev_alloc_skb(dev, pktlen + 2);
                if (skb) {
                        skb_reserve(skb, 2);
@@ -2905,17 +2972,19 @@ static void at91ether_rx(struct net_device *dev)
                        lp->stats.rx_dropped++;
                }
 
-               if (lp->rx_ring[lp->rx_tail].ctrl & MACB_BIT(RX_MHASH_MATCH))
+               if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH))
                        lp->stats.multicast++;
 
                /* reset ownership bit */
-               lp->rx_ring[lp->rx_tail].addr &= ~MACB_BIT(RX_USED);
+               desc->addr &= ~MACB_BIT(RX_USED);
 
                /* wrap after last buffer */
                if (lp->rx_tail == AT91ETHER_MAX_RX_DESCR - 1)
                        lp->rx_tail = 0;
                else
                        lp->rx_tail++;
+
+               desc = macb_rx_desc(lp, lp->rx_tail);
        }
 }
 
@@ -3211,8 +3280,11 @@ static int macb_probe(struct platform_device *pdev)
        device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
 
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-       if (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1)) > GEM_DBW32)
+       if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) {
                dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+               bp->hw_dma_cap = HW_DMA_CAP_64B;
+       } else
+               bp->hw_dma_cap = HW_DMA_CAP_32B;
 #endif
 
        spin_lock_init(&bp->lock);
index d67adad67be1c097a339d993a866597b4d202f4d..fc8550a5d47f75df540521c27f07f5c2d03995f9 100644 (file)
 /* Bitfields in DCFG6. */
 #define GEM_PBUF_LSO_OFFSET                    27
 #define GEM_PBUF_LSO_SIZE                      1
+#define GEM_DAW64_OFFSET                       23
+#define GEM_DAW64_SIZE                         1
 
 /* Constants for CLK */
 #define MACB_CLK_DIV8                          0
 struct macb_dma_desc {
        u32     addr;
        u32     ctrl;
+};
+
 #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
-       u32     addrh;
-       u32     resvd;
-#endif
+enum macb_hw_dma_cap {
+       HW_DMA_CAP_32B,
+       HW_DMA_CAP_64B,
 };
 
+struct macb_dma_desc_64 {
+       u32 addrh;
+       u32 resvd;
+};
+#endif
+
 /* DMA descriptor bitfields */
 #define MACB_RX_USED_OFFSET                    0
 #define MACB_RX_USED_SIZE                      1
@@ -874,6 +884,10 @@ struct macb {
        unsigned int            jumbo_max_len;
 
        u32                     wol;
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+       enum macb_hw_dma_cap hw_dma_cap;
+#endif
 };
 
 static inline bool macb_is_gem(struct macb *bp)
index 67befedef7098ddbde763738eb7940116efa283e..578c7f8f11bf23add2ac4d3c2263e371b4509136 100644 (file)
@@ -116,8 +116,7 @@ void xcv_setup_link(bool link_up, int link_speed)
        int speed = 2;
 
        if (!xcv) {
-               dev_err(&xcv->pdev->dev,
-                       "XCV init not done, probe may have failed\n");
+               pr_err("XCV init not done, probe may have failed\n");
                return;
        }
 
index 1a7f8ad7b9c6111ea2f8839a5d28c82af1ef13a8..cd49a54c538d5202f1bb0cb632b8fdb306a66989 100644 (file)
@@ -362,8 +362,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p)
                status = -EPERM;
                goto err;
        }
-done:
+
+       /* Remember currently programmed MAC */
        ether_addr_copy(adapter->dev_mac, addr->sa_data);
+done:
        ether_addr_copy(netdev->dev_addr, addr->sa_data);
        dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
        return 0;
@@ -3618,8 +3620,10 @@ static void be_disable_if_filters(struct be_adapter *adapter)
 {
        /* Don't delete MAC on BE3 VFs without FILTMGMT privilege  */
        if (!BEx_chip(adapter) || !be_virtfn(adapter) ||
-           check_privilege(adapter, BE_PRIV_FILTMGMT))
+           check_privilege(adapter, BE_PRIV_FILTMGMT)) {
                be_dev_mac_del(adapter, adapter->pmac_id[0]);
+               eth_zero_addr(adapter->dev_mac);
+       }
 
        be_clear_uc_list(adapter);
        be_clear_mc_list(adapter);
@@ -3773,12 +3777,27 @@ static int be_enable_if_filters(struct be_adapter *adapter)
        if (status)
                return status;
 
-       /* Don't add MAC on BE3 VFs without FILTMGMT privilege */
-       if (!BEx_chip(adapter) || !be_virtfn(adapter) ||
-           check_privilege(adapter, BE_PRIV_FILTMGMT)) {
+       /* Normally this condition usually true as the ->dev_mac is zeroed.
+        * But on BE3 VFs the initial MAC is pre-programmed by PF and
+        * subsequent be_dev_mac_add() can fail (after fresh boot)
+        */
+       if (!ether_addr_equal(adapter->dev_mac, adapter->netdev->dev_addr)) {
+               int old_pmac_id = -1;
+
+               /* Remember old programmed MAC if any - can happen on BE3 VF */
+               if (!is_zero_ether_addr(adapter->dev_mac))
+                       old_pmac_id = adapter->pmac_id[0];
+
                status = be_dev_mac_add(adapter, adapter->netdev->dev_addr);
                if (status)
                        return status;
+
+               /* Delete the old programmed MAC as we successfully programmed
+                * a new MAC
+                */
+               if (old_pmac_id >= 0 && old_pmac_id != adapter->pmac_id[0])
+                       be_dev_mac_del(adapter, old_pmac_id);
+
                ether_addr_copy(adapter->dev_mac, adapter->netdev->dev_addr);
        }
 
@@ -4552,6 +4571,10 @@ static int be_mac_setup(struct be_adapter *adapter)
 
                memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
                memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+
+               /* Initial MAC for BE3 VFs is already programmed by PF */
+               if (BEx_chip(adapter) && be_virtfn(adapter))
+                       memcpy(adapter->dev_mac, mac, ETH_ALEN);
        }
 
        return 0;
index c1b6716679208a69bc66f017a68e5b6e35c60064..957bfc220978479a5ccee32b58ae26d4236fe939 100644 (file)
@@ -2010,8 +2010,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue)
                if (!rxb->page)
                        continue;
 
-               dma_unmap_single(rx_queue->dev, rxb->dma,
-                                PAGE_SIZE, DMA_FROM_DEVICE);
+               dma_unmap_page(rx_queue->dev, rxb->dma,
+                              PAGE_SIZE, DMA_FROM_DEVICE);
                __free_page(rxb->page);
 
                rxb->page = NULL;
index c7e939945259dc876b66cfedd0d85f9d7e90a914..53daa6ca5d83b60f7ad8632694658922921f82f5 100644 (file)
@@ -158,7 +158,7 @@ static int mlx4_reset_slave(struct mlx4_dev *dev)
        return -ETIMEDOUT;
 }
 
-static int mlx4_comm_internal_err(u32 slave_read)
+int mlx4_comm_internal_err(u32 slave_read)
 {
        return (u32)COMM_CHAN_EVENT_INTERNAL_ERR ==
                (slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0;
index 0e8b7c44931f907ed881d093077e93b92ae0305d..8258d08acd8c2029a8bcb812dd5efd85d8c7b0f2 100644 (file)
@@ -222,6 +222,18 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
                return;
 
        mlx4_stop_catas_poll(dev);
+       if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION &&
+           mlx4_is_slave(dev)) {
+               /* In mlx4_remove_one on a VF */
+               u32 slave_read =
+                       swab32(readl(&mlx4_priv(dev)->mfunc.comm->slave_read));
+
+               if (mlx4_comm_internal_err(slave_read)) {
+                       mlx4_dbg(dev, "%s: comm channel is down, entering error state.\n",
+                                __func__);
+                       mlx4_enter_error_state(dev->persist);
+               }
+       }
        mutex_lock(&intf_mutex);
 
        list_for_each_entry(intf, &intf_list, list)
index 88ee7d8a59231a47d6b7aca2006f9780dbefa578..086920b615af7180e891893ffd00928c0bd0238f 100644 (file)
@@ -1220,6 +1220,7 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type);
 void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
 
 void mlx4_enter_error_state(struct mlx4_dev_persistent *persist);
+int mlx4_comm_internal_err(u32 slave_read);
 
 int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port,
                    enum mlx4_port_type *type);
index 3797cc7c1288078298ec655921f9fc9f804df97e..caa837e5e2b991fc3666776d2050fe20b1c6c7f6 100644 (file)
@@ -1728,7 +1728,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev)
        if (cmd->cmdif_rev > CMD_IF_REV) {
                dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n",
                        CMD_IF_REV, cmd->cmdif_rev);
-               err = -ENOTSUPP;
+               err = -EOPNOTSUPP;
                goto err_free_page;
        }
 
index 951dbd58594dcd3b32b680f752c1105132d85ba8..d5ecb8f53fd43684f185d590c8dc5553a4f25ab4 100644 (file)
@@ -791,7 +791,8 @@ void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
 int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd);
 
 int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int ix);
-void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);
+void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc,
+                                   enum mlx5e_traffic_types tt);
 
 int mlx5e_open_locked(struct net_device *netdev);
 int mlx5e_close_locked(struct net_device *netdev);
@@ -863,12 +864,12 @@ static inline void mlx5e_arfs_destroy_tables(struct mlx5e_priv *priv) {}
 
 static inline int mlx5e_arfs_enable(struct mlx5e_priv *priv)
 {
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 static inline int mlx5e_arfs_disable(struct mlx5e_priv *priv)
 {
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 #else
 int mlx5e_arfs_create_tables(struct mlx5e_priv *priv);
index f0b460f47f2992caad4eec7ea0d655296a46e99c..0523ed47f597c715296c5ea843245625bf3dac62 100644 (file)
@@ -89,7 +89,7 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
        int i;
 
        if (!MLX5_CAP_GEN(priv->mdev, ets))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        ets->ets_cap = mlx5_max_tc(priv->mdev) + 1;
        for (i = 0; i < ets->ets_cap; i++) {
@@ -236,7 +236,7 @@ static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev,
        int err;
 
        if (!MLX5_CAP_GEN(priv->mdev, ets))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        err = mlx5e_dbcnl_validate_ets(netdev, ets);
        if (err)
@@ -402,7 +402,7 @@ static u8 mlx5e_dcbnl_setall(struct net_device *netdev)
        struct mlx5_core_dev *mdev = priv->mdev;
        struct ieee_ets ets;
        struct ieee_pfc pfc;
-       int err = -ENOTSUPP;
+       int err = -EOPNOTSUPP;
        int i;
 
        if (!MLX5_CAP_GEN(mdev, ets))
@@ -511,6 +511,11 @@ static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev,
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
 
+       if (!MLX5_CAP_GEN(priv->mdev, ets)) {
+               netdev_err(netdev, "%s, ets is not supported\n", __func__);
+               return;
+       }
+
        if (priority >= CEE_DCBX_MAX_PRIO) {
                netdev_err(netdev,
                           "%s, priority is out of range\n", __func__);
index 5197817e4b2f8a6b24af61b4fb08c271e69d1a5f..bb67863aa361168a8566349ef356d9a991d411be 100644 (file)
@@ -595,7 +595,7 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
        if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        coal->rx_coalesce_usecs       = priv->params.rx_cq_moderation.usec;
        coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation.pkts;
@@ -620,7 +620,7 @@ static int mlx5e_set_coalesce(struct net_device *netdev,
        int i;
 
        if (!MLX5_CAP_GEN(mdev, cq_moderation))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        mutex_lock(&priv->state_lock);
 
@@ -980,15 +980,18 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
 
 static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen)
 {
-       struct mlx5_core_dev *mdev = priv->mdev;
        void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx);
-       int i;
+       struct mlx5_core_dev *mdev = priv->mdev;
+       int ctxlen = MLX5_ST_SZ_BYTES(tirc);
+       int tt;
 
        MLX5_SET(modify_tir_in, in, bitmask.hash, 1);
-       mlx5e_build_tir_ctx_hash(tirc, priv);
 
-       for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
-               mlx5_core_modify_tir(mdev, priv->indir_tir[i].tirn, in, inlen);
+       for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
+               memset(tirc, 0, ctxlen);
+               mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt);
+               mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen);
+       }
 }
 
 static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
@@ -996,6 +999,7 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
        int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+       bool hash_changed = false;
        void *in;
 
        if ((hfunc != ETH_RSS_HASH_NO_CHANGE) &&
@@ -1017,14 +1021,21 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
                mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0);
        }
 
-       if (key)
+       if (hfunc != ETH_RSS_HASH_NO_CHANGE &&
+           hfunc != priv->params.rss_hfunc) {
+               priv->params.rss_hfunc = hfunc;
+               hash_changed = true;
+       }
+
+       if (key) {
                memcpy(priv->params.toeplitz_hash_key, key,
                       sizeof(priv->params.toeplitz_hash_key));
+               hash_changed = hash_changed ||
+                              priv->params.rss_hfunc == ETH_RSS_HASH_TOP;
+       }
 
-       if (hfunc != ETH_RSS_HASH_NO_CHANGE)
-               priv->params.rss_hfunc = hfunc;
-
-       mlx5e_modify_tirs_hash(priv, in, inlen);
+       if (hash_changed)
+               mlx5e_modify_tirs_hash(priv, in, inlen);
 
        mutex_unlock(&priv->state_lock);
 
@@ -1296,7 +1307,7 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
        u32 mlx5_wol_mode;
 
        if (!wol_supported)
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        if (wol->wolopts & ~wol_supported)
                return -EINVAL;
@@ -1426,7 +1437,7 @@ static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable)
 
        if (rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE &&
            !MLX5_CAP_GEN(mdev, cq_period_start_from_cqe))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        if (!rx_mode_changed)
                return 0;
@@ -1452,7 +1463,7 @@ static int set_pflag_rx_cqe_compress(struct net_device *netdev,
        bool reset;
 
        if (!MLX5_CAP_GEN(mdev, cqe_compression))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        if (enable && priv->tstamp.hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
                netdev_err(netdev, "Can't enable cqe compression while timestamping is enabled.\n");
index 1fe80de5d68f1f3cf09c6e32530cd32114580051..a0e5a69402b30a349b196eaa72ce1a413b5479b2 100644 (file)
@@ -1089,7 +1089,7 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv)
                                               MLX5_FLOW_NAMESPACE_KERNEL);
 
        if (!priv->fs.ns)
-               return -EINVAL;
+               return -EOPNOTSUPP;
 
        err = mlx5e_arfs_create_tables(priv);
        if (err) {
index d088effd7160355849faacead1326f2198d12e8d..f33f72d0237c1bafc702f4066dab31ab22963a47 100644 (file)
@@ -92,7 +92,7 @@ static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv,
        ns = mlx5_get_flow_namespace(priv->mdev,
                                     MLX5_FLOW_NAMESPACE_ETHTOOL);
        if (!ns)
-               return ERR_PTR(-ENOTSUPP);
+               return ERR_PTR(-EOPNOTSUPP);
 
        table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev,
                                                       flow_table_properties_nic_receive.log_max_ft_size)),
index 2b7dd315020cd9e1a21b28643621122695cd06dd..f14ca3385fdd683b12f434e289cc8e264040c1ed 100644 (file)
@@ -2022,8 +2022,23 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv)
        MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout);
 }
 
-void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
+void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc,
+                                   enum mlx5e_traffic_types tt)
 {
+       void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
+
+#define MLX5_HASH_IP            (MLX5_HASH_FIELD_SEL_SRC_IP   |\
+                                MLX5_HASH_FIELD_SEL_DST_IP)
+
+#define MLX5_HASH_IP_L4PORTS    (MLX5_HASH_FIELD_SEL_SRC_IP   |\
+                                MLX5_HASH_FIELD_SEL_DST_IP   |\
+                                MLX5_HASH_FIELD_SEL_L4_SPORT |\
+                                MLX5_HASH_FIELD_SEL_L4_DPORT)
+
+#define MLX5_HASH_IP_IPSEC_SPI  (MLX5_HASH_FIELD_SEL_SRC_IP   |\
+                                MLX5_HASH_FIELD_SEL_DST_IP   |\
+                                MLX5_HASH_FIELD_SEL_IPSEC_SPI)
+
        MLX5_SET(tirc, tirc, rx_hash_fn,
                 mlx5e_rx_hash_fn(priv->params.rss_hfunc));
        if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
@@ -2035,6 +2050,88 @@ void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
                MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
                memcpy(rss_key, priv->params.toeplitz_hash_key, len);
        }
+
+       switch (tt) {
+       case MLX5E_TT_IPV4_TCP:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV4);
+               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+                        MLX5_L4_PROT_TYPE_TCP);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_L4PORTS);
+               break;
+
+       case MLX5E_TT_IPV6_TCP:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV6);
+               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+                        MLX5_L4_PROT_TYPE_TCP);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_L4PORTS);
+               break;
+
+       case MLX5E_TT_IPV4_UDP:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV4);
+               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+                        MLX5_L4_PROT_TYPE_UDP);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_L4PORTS);
+               break;
+
+       case MLX5E_TT_IPV6_UDP:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV6);
+               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+                        MLX5_L4_PROT_TYPE_UDP);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_L4PORTS);
+               break;
+
+       case MLX5E_TT_IPV4_IPSEC_AH:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV4);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_IPSEC_SPI);
+               break;
+
+       case MLX5E_TT_IPV6_IPSEC_AH:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV6);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_IPSEC_SPI);
+               break;
+
+       case MLX5E_TT_IPV4_IPSEC_ESP:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV4);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_IPSEC_SPI);
+               break;
+
+       case MLX5E_TT_IPV6_IPSEC_ESP:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV6);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP_IPSEC_SPI);
+               break;
+
+       case MLX5E_TT_IPV4:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV4);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP);
+               break;
+
+       case MLX5E_TT_IPV6:
+               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+                        MLX5_L3_PROT_TYPE_IPV6);
+               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+                        MLX5_HASH_IP);
+               break;
+       default:
+               WARN_ONCE(true, "%s: bad traffic type!\n", __func__);
+       }
 }
 
 static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
@@ -2404,110 +2501,13 @@ void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv)
 static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
                                      enum mlx5e_traffic_types tt)
 {
-       void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
-
        MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn);
 
-#define MLX5_HASH_IP            (MLX5_HASH_FIELD_SEL_SRC_IP   |\
-                                MLX5_HASH_FIELD_SEL_DST_IP)
-
-#define MLX5_HASH_IP_L4PORTS    (MLX5_HASH_FIELD_SEL_SRC_IP   |\
-                                MLX5_HASH_FIELD_SEL_DST_IP   |\
-                                MLX5_HASH_FIELD_SEL_L4_SPORT |\
-                                MLX5_HASH_FIELD_SEL_L4_DPORT)
-
-#define MLX5_HASH_IP_IPSEC_SPI  (MLX5_HASH_FIELD_SEL_SRC_IP   |\
-                                MLX5_HASH_FIELD_SEL_DST_IP   |\
-                                MLX5_HASH_FIELD_SEL_IPSEC_SPI)
-
        mlx5e_build_tir_ctx_lro(tirc, priv);
 
        MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
        MLX5_SET(tirc, tirc, indirect_table, priv->indir_rqt.rqtn);
-       mlx5e_build_tir_ctx_hash(tirc, priv);
-
-       switch (tt) {
-       case MLX5E_TT_IPV4_TCP:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV4);
-               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-                        MLX5_L4_PROT_TYPE_TCP);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_L4PORTS);
-               break;
-
-       case MLX5E_TT_IPV6_TCP:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV6);
-               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-                        MLX5_L4_PROT_TYPE_TCP);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_L4PORTS);
-               break;
-
-       case MLX5E_TT_IPV4_UDP:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV4);
-               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-                        MLX5_L4_PROT_TYPE_UDP);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_L4PORTS);
-               break;
-
-       case MLX5E_TT_IPV6_UDP:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV6);
-               MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
-                        MLX5_L4_PROT_TYPE_UDP);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_L4PORTS);
-               break;
-
-       case MLX5E_TT_IPV4_IPSEC_AH:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV4);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_IPSEC_SPI);
-               break;
-
-       case MLX5E_TT_IPV6_IPSEC_AH:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV6);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_IPSEC_SPI);
-               break;
-
-       case MLX5E_TT_IPV4_IPSEC_ESP:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV4);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_IPSEC_SPI);
-               break;
-
-       case MLX5E_TT_IPV6_IPSEC_ESP:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV6);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP_IPSEC_SPI);
-               break;
-
-       case MLX5E_TT_IPV4:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV4);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP);
-               break;
-
-       case MLX5E_TT_IPV6:
-               MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
-                        MLX5_L3_PROT_TYPE_IPV6);
-               MLX5_SET(rx_hash_field_select, hfso, selected_fields,
-                        MLX5_HASH_IP);
-               break;
-       default:
-               WARN_ONCE(true,
-                         "mlx5e_build_indir_tir_ctx: bad traffic type!\n");
-       }
+       mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt);
 }
 
 static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
@@ -3331,7 +3331,7 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
 static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
 {
        if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        if (!MLX5_CAP_GEN(mdev, eth_net_offloads) ||
            !MLX5_CAP_GEN(mdev, nic_flow_table) ||
            !MLX5_CAP_ETH(mdev, csum_cap) ||
@@ -3343,7 +3343,7 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
                               < 3) {
                mlx5_core_warn(mdev,
                               "Not creating net device, some required device capabilities are missing\n");
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
        if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
                mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
index 46bef6a26a8cdbebf268b6275271367c4109a77d..c5282b6aba8baf6a3c8f345c55764110cdfd6ff5 100644 (file)
@@ -663,6 +663,7 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
                                   __be32 *saddr,
                                   int *out_ttl)
 {
+       struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        struct rtable *rt;
        struct neighbour *n = NULL;
        int ttl;
@@ -677,12 +678,11 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
 #else
        return -EOPNOTSUPP;
 #endif
-
-       if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) {
-               pr_warn("%s: can't offload, devices not on same HW e-switch\n", __func__);
-               ip_rt_put(rt);
-               return -EOPNOTSUPP;
-       }
+       /* if the egress device isn't on the same HW e-switch, we use the uplink */
+       if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev))
+               *out_dev = mlx5_eswitch_get_uplink_netdev(esw);
+       else
+               *out_dev = rt->dst.dev;
 
        ttl = ip4_dst_hoplimit(&rt->dst);
        n = dst_neigh_lookup(&rt->dst, &fl4->daddr);
@@ -693,7 +693,6 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv,
        *out_n = n;
        *saddr = fl4->saddr;
        *out_ttl = ttl;
-       *out_dev = rt->dst.dev;
 
        return 0;
 }
index f14d9c9ba77394b83aea50564afd3c762613467a..d0c8bf014453ea38736182c03ba7b2d9c5bcd4d7 100644 (file)
@@ -133,7 +133,7 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
 
        if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
            !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n",
                  vport, vlan, qos, set_flags);
@@ -353,7 +353,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw, int nvports)
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
        if (!root_ns) {
                esw_warn(dev, "Failed to get FDB flow namespace\n");
-               return -ENOMEM;
+               return -EOPNOTSUPP;
        }
 
        flow_group_in = mlx5_vzalloc(inlen);
@@ -962,7 +962,7 @@ static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS);
        if (!root_ns) {
                esw_warn(dev, "Failed to get E-Switch egress flow namespace\n");
-               return -EIO;
+               return -EOPNOTSUPP;
        }
 
        flow_group_in = mlx5_vzalloc(inlen);
@@ -1079,7 +1079,7 @@ static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw,
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS);
        if (!root_ns) {
                esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n");
-               return -EIO;
+               return -EOPNOTSUPP;
        }
 
        flow_group_in = mlx5_vzalloc(inlen);
@@ -1630,7 +1630,7 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
        if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
            !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
                esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
        if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
index 03293ed1cc22d2716ff5708dc2312b7291cc1899..595f7c7383b399440aedec593ae0fb0c37bb6748 100644 (file)
@@ -166,7 +166,7 @@ static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
        return 0;
 
 out_notsupp:
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
@@ -424,6 +424,7 @@ static int esw_create_offloads_fdb_table(struct mlx5_eswitch *esw, int nvports)
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
        if (!root_ns) {
                esw_warn(dev, "Failed to get FDB flow namespace\n");
+               err = -EOPNOTSUPP;
                goto ns_err;
        }
 
@@ -535,7 +536,7 @@ static int esw_create_offloads_table(struct mlx5_eswitch *esw)
        ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
        if (!ns) {
                esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
-               return -ENOMEM;
+               return -EOPNOTSUPP;
        }
 
        ft_offloads = mlx5_create_flow_table(ns, 0, dev->priv.sriov.num_vfs + 2, 0, 0);
@@ -655,7 +656,7 @@ static int esw_offloads_start(struct mlx5_eswitch *esw)
                esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
                err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
                if (err1)
-                       esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err);
+                       esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
        }
        if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
                if (mlx5_eswitch_inline_mode_get(esw,
@@ -674,9 +675,14 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
        int vport;
        int err;
 
+       /* disable PF RoCE so missed packets don't go through RoCE steering */
+       mlx5_dev_list_lock();
+       mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+       mlx5_dev_list_unlock();
+
        err = esw_create_offloads_fdb_table(esw, nvports);
        if (err)
-               return err;
+               goto create_fdb_err;
 
        err = esw_create_offloads_table(esw);
        if (err)
@@ -696,11 +702,6 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
                        goto err_reps;
        }
 
-       /* disable PF RoCE so missed packets don't go through RoCE steering */
-       mlx5_dev_list_lock();
-       mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
-       mlx5_dev_list_unlock();
-
        return 0;
 
 err_reps:
@@ -717,6 +718,13 @@ create_fg_err:
 
 create_ft_err:
        esw_destroy_offloads_fdb_table(esw);
+
+create_fdb_err:
+       /* enable back PF RoCE */
+       mlx5_dev_list_lock();
+       mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+       mlx5_dev_list_unlock();
+
        return err;
 }
 
@@ -724,11 +732,6 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw)
 {
        int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
 
-       /* enable back PF RoCE */
-       mlx5_dev_list_lock();
-       mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
-       mlx5_dev_list_unlock();
-
        mlx5_eswitch_disable_sriov(esw);
        err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
        if (err) {
@@ -738,6 +741,11 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw)
                        esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
        }
 
+       /* enable back PF RoCE */
+       mlx5_dev_list_lock();
+       mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+       mlx5_dev_list_unlock();
+
        return err;
 }
 
index c4478ecd8056e42de2c359eb7a2abfd9e6400090..b53fc85a2375778ddd02ac07d21d88b56c49e432 100644 (file)
@@ -322,7 +322,7 @@ int mlx5_cmd_update_fte(struct mlx5_core_dev *dev,
                                                flow_table_properties_nic_receive.
                                                flow_modify_en);
        if (!atomic_mod_cap)
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        opmod = 1;
 
        return  mlx5_cmd_set_fte(dev, opmod, modify_mask, ft, group_id, fte);
index 0ac7a2fc916c438bc535b20d45964009747f0b33..6346a8f5883bcc911ef422cf572fd1891ddf73c9 100644 (file)
@@ -1822,7 +1822,7 @@ static int create_anchor_flow_table(struct mlx5_flow_steering *steering)
        struct mlx5_flow_table *ft;
 
        ns = mlx5_get_flow_namespace(steering->dev, MLX5_FLOW_NAMESPACE_ANCHOR);
-       if (!ns)
+       if (WARN_ON(!ns))
                return -EINVAL;
        ft = mlx5_create_flow_table(ns, ANCHOR_PRIO, ANCHOR_SIZE, ANCHOR_LEVEL, 0);
        if (IS_ERR(ft)) {
index d01e9f21d4691ea497aa7ea0666c83e330c078bb..3c315eb8d270f6f94ecaea2c8ee4d78ed1244658 100644 (file)
@@ -807,7 +807,7 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev)
                return 0;
        }
 
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 
index d2ec9d232a70727df71d0c733f60c78a55415392..fd12e0a377a567c693c7f174d7762dd6071ff925 100644 (file)
@@ -620,7 +620,7 @@ static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in,
        u32 out[MLX5_ST_SZ_DW(qtct_reg)];
 
        if (!MLX5_CAP_GEN(mdev, ets))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
                                    MLX5_REG_QETCR, 0, 1);
@@ -632,7 +632,7 @@ static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out,
        u32 in[MLX5_ST_SZ_DW(qtct_reg)];
 
        if (!MLX5_CAP_GEN(mdev, ets))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        memset(in, 0, sizeof(in));
        return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
index 269e4401c342d1375e70a40ba9905dddf9b65cef..7129c30a2ab477d23be1b8b8d34e7190618e0f9f 100644 (file)
@@ -532,7 +532,7 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev,
        if (!MLX5_CAP_GEN(mdev, vport_group_manager))
                return -EACCES;
        if (!MLX5_CAP_ESW(mdev, nic_vport_node_guid_modify))
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
 
        in = mlx5_vzalloc(inlen);
        if (!in)
index be3c91c7f211d94ad7386b77de73676933a46dcd..5484fd726d5af7f5f10708c57d062b9992be655d 100644 (file)
@@ -305,8 +305,12 @@ static int dwmac1000_irq_status(struct mac_device_info *hw,
 {
        void __iomem *ioaddr = hw->pcsr;
        u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+       u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
        int ret = 0;
 
+       /* Discard masked bits */
+       intr_status &= ~intr_mask;
+
        /* Not used events (e.g. MMC interrupts) are not handled. */
        if ((intr_status & GMAC_INT_STATUS_MMCTIS))
                x->mmc_tx_irq_n++;
index 5a1cc089acb7fd2e79c18876cd7951f6dfb6e747..86e5749226ef4cf65d6070bca1ab0d4be35bf2e0 100644 (file)
@@ -1295,6 +1295,9 @@ void netvsc_channel_cb(void *context)
        ndev = hv_get_drvdata(device);
        buffer = get_per_channel_state(channel);
 
+       /* commit_rd_index() -> hv_signal_on_read() needs this. */
+       init_cached_read_index(channel);
+
        do {
                desc = get_next_pkt_raw(channel);
                if (desc != NULL) {
@@ -1347,6 +1350,9 @@ void netvsc_channel_cb(void *context)
 
                        bufferlen = bytes_recvd;
                }
+
+               init_cached_read_index(channel);
+
        } while (1);
 
        if (bufferlen > NETVSC_PACKET_SIZE)
index e55809c5beb71a6c1a3a0a60420cb3c263f6a33b..6742070ca676f57694a9a6cb11364941deb520a0 100644 (file)
@@ -1012,7 +1012,7 @@ static struct phy_driver ksphy_driver[] = {
        .phy_id         = PHY_ID_KSZ8795,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
        .name           = "Micrel KSZ8795",
-       .features       = (SUPPORTED_Pause | SUPPORTED_Asym_Pause),
+       .features       = PHY_BASIC_FEATURES,
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .config_init    = kszphy_config_init,
        .config_aneg    = ksz8873mll_config_aneg,
index d02ca1491d16cede66389540f8cb92dda5749ff3..8d3e53fac1dabc01ed875b6f8c2863bb908f770c 100644 (file)
@@ -91,7 +91,7 @@
 
 #define IWL8000_FW_PRE "iwlwifi-8000C-"
 #define IWL8000_MODULE_FIRMWARE(api) \
-       IWL8000_FW_PRE "-" __stringify(api) ".ucode"
+       IWL8000_FW_PRE __stringify(api) ".ucode"
 
 #define IWL8265_FW_PRE "iwlwifi-8265-"
 #define IWL8265_MODULE_FIRMWARE(api) \
index 636c8b03e31892bd30e3a3d7a6b1e9b8a8eb02ea..09e9e2e3ed040202f0cb40c1e326584b0fa7465a 100644 (file)
@@ -1164,9 +1164,10 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm,
                .frame_limit = IWL_FRAME_LIMIT,
        };
 
-       /* Make sure reserved queue is still marked as such (or allocated) */
-       mvm->queue_info[mvm_sta->reserved_queue].status =
-               IWL_MVM_QUEUE_RESERVED;
+       /* Make sure reserved queue is still marked as such (if allocated) */
+       if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE)
+               mvm->queue_info[mvm_sta->reserved_queue].status =
+                       IWL_MVM_QUEUE_RESERVED;
 
        for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
                struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i];
index 63a051be832ed44b30978b4d031464b15765df20..bec7d9c46087d3c8fed48d5858f4f116797eceed 100644 (file)
@@ -843,8 +843,10 @@ static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm)
                return;
 
        IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
-       thermal_zone_device_unregister(mvm->tz_device.tzone);
-       mvm->tz_device.tzone = NULL;
+       if (mvm->tz_device.tzone) {
+               thermal_zone_device_unregister(mvm->tz_device.tzone);
+               mvm->tz_device.tzone = NULL;
+       }
 }
 
 static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
@@ -853,8 +855,10 @@ static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
                return;
 
        IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
-       thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
-       mvm->cooling_dev.cdev = NULL;
+       if (mvm->cooling_dev.cdev) {
+               thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
+               mvm->cooling_dev.cdev = NULL;
+       }
 }
 #endif /* CONFIG_THERMAL */
 
index 17ac1dce32867051298a5489841de8b636835a68..3dd8bcbb3011babd4ad4271d6f6f64733bd9b3f1 100644 (file)
@@ -532,25 +532,32 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
        link = kzalloc(sizeof(*link), GFP_KERNEL);
        if (!link)
                return NULL;
+
        INIT_LIST_HEAD(&link->sibling);
        INIT_LIST_HEAD(&link->children);
        INIT_LIST_HEAD(&link->link);
        link->pdev = pdev;
-       if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) {
+
+       /*
+        * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
+        * hierarchies.
+        */
+       if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
+           pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) {
+               link->root = link;
+       } else {
                struct pcie_link_state *parent;
+
                parent = pdev->bus->parent->self->link_state;
                if (!parent) {
                        kfree(link);
                        return NULL;
                }
+
                link->parent = parent;
+               link->root = link->parent->root;
                list_add(&link->link, &parent->children);
        }
-       /* Setup a pointer to the root port link */
-       if (!link->parent)
-               link->root = link;
-       else
-               link->root = link->parent->root;
 
        list_add(&link->sibling, &link_list);
        pdev->link_state = link;
index 09172043d5890735127b0f79275a98704cdbd2b6..c617ec49e9edeeebb1f33b78fa6b7214fb23207c 100644 (file)
@@ -217,7 +217,7 @@ static const struct berlin_desc_group berlin4ct_soc_pinctrl_groups[] = {
        BERLIN_PINCTRL_GROUP("SCRD0_CRD_PRES", 0xc, 0x3, 0x15,
                        BERLIN_PINCTRL_FUNCTION(0x0, "gpio"), /* GPIO20 */
                        BERLIN_PINCTRL_FUNCTION(0x1, "scrd0"), /* crd pres */
-                       BERLIN_PINCTRL_FUNCTION(0x1, "sd1a")), /* DAT3 */
+                       BERLIN_PINCTRL_FUNCTION(0x3, "sd1a")), /* DAT3 */
        BERLIN_PINCTRL_GROUP("SPI1_SS0n", 0xc, 0x3, 0x18,
                        BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */
                        BERLIN_PINCTRL_FUNCTION(0x1, "gpio"), /* GPIO37 */
index c123488266ce74883ed8ba972b43103d136bb66e..d94aef17348b4b88f3952670886b863b952cfc60 100644 (file)
@@ -731,16 +731,23 @@ static void __iomem *byt_gpio_reg(struct byt_gpio *vg, unsigned int offset,
                                  int reg)
 {
        struct byt_community *comm = byt_get_community(vg, offset);
-       u32 reg_offset = 0;
+       u32 reg_offset;
 
        if (!comm)
                return NULL;
 
        offset -= comm->pin_base;
-       if (reg == BYT_INT_STAT_REG)
+       switch (reg) {
+       case BYT_INT_STAT_REG:
                reg_offset = (offset / 32) * 4;
-       else
+               break;
+       case BYT_DEBOUNCE_REG:
+               reg_offset = 0;
+               break;
+       default:
                reg_offset = comm->pad_map[offset] * 16;
+               break;
+       }
 
        return comm->reg_base + reg_offset + reg;
 }
@@ -1243,10 +1250,12 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
                        debounce = readl(db_reg);
                        debounce &= ~BYT_DEBOUNCE_PULSE_MASK;
 
+                       if (arg)
+                               conf |= BYT_DEBOUNCE_EN;
+                       else
+                               conf &= ~BYT_DEBOUNCE_EN;
+
                        switch (arg) {
-                       case 0:
-                               conf &= BYT_DEBOUNCE_EN;
-                               break;
                        case 375:
                                debounce |= BYT_DEBOUNCE_PULSE_375US;
                                break;
@@ -1269,7 +1278,9 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev,
                                debounce |= BYT_DEBOUNCE_PULSE_24MS;
                                break;
                        default:
-                               ret = -EINVAL;
+                               if (arg)
+                                       ret = -EINVAL;
+                               break;
                        }
 
                        if (!ret)
@@ -1612,7 +1623,9 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
                        continue;
                }
 
+               raw_spin_lock(&vg->lock);
                pending = readl(reg);
+               raw_spin_unlock(&vg->lock);
                for_each_set_bit(pin, &pending, 32) {
                        virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
                        generic_handle_irq(virq);
index b21896126f760a5cbae044ab13cba527e9dbfeff..4d4ef42a39b5faaa1969d20a5aeeedffef90074c 100644 (file)
@@ -794,6 +794,9 @@ static int mrfld_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
        unsigned int i;
        int ret;
 
+       if (!mrfld_buf_available(mp, pin))
+               return -ENOTSUPP;
+
        for (i = 0; i < nconfigs; i++) {
                switch (pinconf_to_config_param(configs[i])) {
                case PIN_CONFIG_BIAS_DISABLE:
index 0eb51e33cb1be5412ab11d10e7cdb474a2faa061..207a8de4e1ed851cf542aa4af008e8f74102cad3 100644 (file)
@@ -564,8 +564,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev,
                        val = arg / 10 - 1;
                        break;
                case PIN_CONFIG_BIAS_DISABLE:
-                       val = 0;
-                       break;
+                       continue;
                case PIN_CONFIG_BIAS_PULL_UP:
                        if (arg == 0)
                                return -EINVAL;
index e6a512ebeae2762812212ac5b9264f92bb8252be..a3ade9e4ef478ed90311365a4e86db0cbbc394d5 100644 (file)
@@ -272,7 +272,7 @@ static const struct regulator_desc axp806_regulators[] = {
                        64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1,
                        BIT(3)),
        AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100,
-                AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
+                AXP806_DCDCE_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
        AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
                 AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)),
        AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100,
index a43b0e8a438d305a959d3d745c7c65bf796ca9f9..988a7472c2ab568c3d1c03d1092c0713073a6d28 100644 (file)
@@ -30,9 +30,6 @@
 #include <linux/of_gpio.h>
 #include <linux/regulator/of_regulator.h>
 #include <linux/regulator/machine.h>
-#include <linux/acpi.h>
-#include <linux/property.h>
-#include <linux/gpio/consumer.h>
 
 struct fixed_voltage_data {
        struct regulator_desc desc;
@@ -97,44 +94,6 @@ of_get_fixed_voltage_config(struct device *dev,
        return config;
 }
 
-/**
- * acpi_get_fixed_voltage_config - extract fixed_voltage_config structure info
- * @dev: device requesting for fixed_voltage_config
- * @desc: regulator description
- *
- * Populates fixed_voltage_config structure by extracting data through ACPI
- * interface, returns a pointer to the populated structure of NULL if memory
- * alloc fails.
- */
-static struct fixed_voltage_config *
-acpi_get_fixed_voltage_config(struct device *dev,
-                             const struct regulator_desc *desc)
-{
-       struct fixed_voltage_config *config;
-       const char *supply_name;
-       struct gpio_desc *gpiod;
-       int ret;
-
-       config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
-       if (!config)
-               return ERR_PTR(-ENOMEM);
-
-       ret = device_property_read_string(dev, "supply-name", &supply_name);
-       if (!ret)
-               config->supply_name = supply_name;
-
-       gpiod = gpiod_get(dev, "gpio", GPIOD_ASIS);
-       if (IS_ERR(gpiod))
-               return ERR_PTR(-ENODEV);
-
-       config->gpio = desc_to_gpio(gpiod);
-       config->enable_high = device_property_read_bool(dev,
-                                                       "enable-active-high");
-       gpiod_put(gpiod);
-
-       return config;
-}
-
 static struct regulator_ops fixed_voltage_ops = {
 };
 
@@ -155,11 +114,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
                                                     &drvdata->desc);
                if (IS_ERR(config))
                        return PTR_ERR(config);
-       } else if (ACPI_HANDLE(&pdev->dev)) {
-               config = acpi_get_fixed_voltage_config(&pdev->dev,
-                                                      &drvdata->desc);
-               if (IS_ERR(config))
-                       return PTR_ERR(config);
        } else {
                config = dev_get_platdata(&pdev->dev);
        }
index 4864b9d742c0f7915cc792aaacd692c2a7f305b0..716191046a70782b0007033dda6e1402c0d68ea3 100644 (file)
@@ -452,7 +452,7 @@ static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV,
                        vsel = 62;
                else if ((min_uV > 1800000) && (min_uV <= 1900000))
                        vsel = 61;
-               else if ((min_uV > 1350000) && (min_uV <= 1800000))
+               else if ((min_uV > 1500000) && (min_uV <= 1800000))
                        vsel = 60;
                else if ((min_uV > 1350000) && (min_uV <= 1500000))
                        vsel = 59;
index c93c5a8fba32925584dbc28c60610786328d09ff..5dc673dc948785a79da8d070954323b9357385c1 100644 (file)
@@ -1551,12 +1551,15 @@ config RTC_DRV_MPC5121
          will be called rtc-mpc5121.
 
 config RTC_DRV_JZ4740
-       bool "Ingenic JZ4740 SoC"
+       tristate "Ingenic JZ4740 SoC"
        depends on MACH_INGENIC || COMPILE_TEST
        help
          If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
          controllers.
 
+         This driver can also be buillt as a module. If so, the module
+         will be called rtc-jz4740.
+
 config RTC_DRV_LPC24XX
        tristate "NXP RTC for LPC178x/18xx/408x/43xx"
        depends on ARCH_LPC18XX || COMPILE_TEST
index 72918c1ba0928d4fc78d921db621c489fafb9701..64989afffa3daada4b062321c527f18bca142bbb 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/reboot.h>
@@ -294,7 +295,7 @@ static void jz4740_rtc_power_off(void)
                             JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks);
 
        jz4740_rtc_poweroff(dev_for_power_off);
-       machine_halt();
+       kernel_halt();
 }
 
 static const struct of_device_id jz4740_rtc_of_match[] = {
@@ -302,6 +303,7 @@ static const struct of_device_id jz4740_rtc_of_match[] = {
        { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
        {},
 };
+MODULE_DEVICE_TABLE(of, jz4740_rtc_of_match);
 
 static int jz4740_rtc_probe(struct platform_device *pdev)
 {
@@ -429,6 +431,7 @@ static const struct platform_device_id jz4740_rtc_ids[] = {
        { "jz4780-rtc", ID_JZ4780 },
        {}
 };
+MODULE_DEVICE_TABLE(platform, jz4740_rtc_ids);
 
 static struct platform_driver jz4740_rtc_driver = {
        .probe   = jz4740_rtc_probe,
@@ -440,4 +443,9 @@ static struct platform_driver jz4740_rtc_driver = {
        .id_table = jz4740_rtc_ids,
 };
 
-builtin_platform_driver(jz4740_rtc_driver);
+module_platform_driver(jz4740_rtc_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
+MODULE_ALIAS("platform:jz4740-rtc");
index ec91bd07f00a307337283cbea6f72c6e370a0170..c680d76413116c00b80193f5e7db9de2e13441b1 100644 (file)
@@ -534,7 +534,9 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
 {
        struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
        struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
+       unsigned long flags;
        int req_size;
+       int ret;
 
        BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
 
@@ -562,8 +564,15 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
                req_size = sizeof(cmd->req.cmd);
        }
 
-       if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0)
+       ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd));
+       if (ret == -EIO) {
+               cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
+               spin_lock_irqsave(&req_vq->vq_lock, flags);
+               virtscsi_complete_cmd(vscsi, cmd);
+               spin_unlock_irqrestore(&req_vq->vq_lock, flags);
+       } else if (ret != 0) {
                return SCSI_MLQUEUE_HOST_BUSY;
+       }
        return 0;
 }
 
index 113f3d6c4b3a6cdeda3fce3abe729fbc927fd9d9..27f75b17679b8f19a5f6100a769dd7b1b0f77455 100644 (file)
@@ -45,12 +45,18 @@ u32 gb_timesync_platform_get_clock_rate(void)
 
 int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata)
 {
+       if (!arche_platform_change_state_cb)
+               return 0;
+
        return arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_TIME_SYNC,
                                              pdata);
 }
 
 void gb_timesync_platform_unlock_bus(void)
 {
+       if (!arche_platform_change_state_cb)
+               return;
+
        arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_ACTIVE, NULL);
 }
 
index d2e50a27140c9254be2a80b6c6ae69bc71a93b4a..24f9f98968a5d860f83920287a5b7deb4c98bed6 100644 (file)
@@ -37,6 +37,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        /* CBM - Flash disk */
        { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* WORLDE easy key (easykey.25) MIDI controller  */
+       { USB_DEVICE(0x0218, 0x0401), .driver_info =
+                       USB_QUIRK_CONFIG_INTF_STRINGS },
+
        /* HP 5300/5370C scanner */
        { USB_DEVICE(0x03f0, 0x0701), .driver_info =
                        USB_QUIRK_STRING_FETCH_255 },
index 5490fc51638ede3c565eff9036ff3beaf884d3a9..fd80c1b9c8234cf4de8371c7ca4e528bc4712fc3 100644 (file)
@@ -2269,6 +2269,8 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
                if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
                        return -EINVAL;
                length = le32_to_cpu(d->dwSize);
+               if (len < length)
+                       return -EINVAL;
                type = le32_to_cpu(d->dwPropertyDataType);
                if (type < USB_EXT_PROP_UNICODE ||
                    type > USB_EXT_PROP_UNICODE_MULTI) {
@@ -2277,6 +2279,11 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type,
                        return -EINVAL;
                }
                pnl = le16_to_cpu(d->wPropertyNameLength);
+               if (length < 14 + pnl) {
+                       pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
+                                 length, pnl, type);
+                       return -EINVAL;
+               }
                pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
                if (length != 14 + pnl + pdl) {
                        pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
@@ -2363,6 +2370,9 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
                }
        }
        if (flags & (1 << i)) {
+               if (len < 4) {
+                       goto error;
+               }
                os_descs_count = get_unaligned_le32(data);
                data += 4;
                len -= 4;
@@ -2435,7 +2445,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,
 
        ENTER();
 
-       if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+       if (unlikely(len < 16 ||
+                    get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
                     get_unaligned_le32(data + 4) != len))
                goto error;
        str_count  = get_unaligned_le32(data + 8);
index fca288bbc8009580ba96198ce1a2a49330074d20..772f1582124255d749ab470a42394498af8f9741 100644 (file)
@@ -594,11 +594,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                                                | MUSB_PORT_STAT_RESUME;
                                musb->rh_timer = jiffies
                                        + msecs_to_jiffies(USB_RESUME_TIMEOUT);
-                               musb->need_finish_resume = 1;
-
                                musb->xceiv->otg->state = OTG_STATE_A_HOST;
                                musb->is_active = 1;
                                musb_host_resume_root_hub(musb);
+                               schedule_delayed_work(&musb->finish_resume_work,
+                                       msecs_to_jiffies(USB_RESUME_TIMEOUT));
                                break;
                        case OTG_STATE_B_WAIT_ACON:
                                musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
@@ -1925,6 +1925,14 @@ static void musb_pm_runtime_check_session(struct musb *musb)
 static void musb_irq_work(struct work_struct *data)
 {
        struct musb *musb = container_of(data, struct musb, irq_work.work);
+       int error;
+
+       error = pm_runtime_get_sync(musb->controller);
+       if (error < 0) {
+               dev_err(musb->controller, "Could not enable: %i\n", error);
+
+               return;
+       }
 
        musb_pm_runtime_check_session(musb);
 
@@ -1932,6 +1940,9 @@ static void musb_irq_work(struct work_struct *data)
                musb->xceiv_old_state = musb->xceiv->otg->state;
                sysfs_notify(&musb->controller->kobj, NULL, "mode");
        }
+
+       pm_runtime_mark_last_busy(musb->controller);
+       pm_runtime_put_autosuspend(musb->controller);
 }
 
 static void musb_recover_from_babble(struct musb *musb)
@@ -2710,11 +2721,6 @@ static int musb_resume(struct device *dev)
        mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV;
        if ((devctl & mask) != (musb->context.devctl & mask))
                musb->port1_status = 0;
-       if (musb->need_finish_resume) {
-               musb->need_finish_resume = 0;
-               schedule_delayed_work(&musb->finish_resume_work,
-                                     msecs_to_jiffies(USB_RESUME_TIMEOUT));
-       }
 
        /*
         * The USB HUB code expects the device to be in RPM_ACTIVE once it came
@@ -2766,12 +2772,6 @@ static int musb_runtime_resume(struct device *dev)
 
        musb_restore_context(musb);
 
-       if (musb->need_finish_resume) {
-               musb->need_finish_resume = 0;
-               schedule_delayed_work(&musb->finish_resume_work,
-                               msecs_to_jiffies(USB_RESUME_TIMEOUT));
-       }
-
        spin_lock_irqsave(&musb->lock, flags);
        error = musb_run_resume_work(musb);
        if (error)
index ade902ea1221e18543de05a5188c715d86af7398..ce5a18c98c6d1134231a29fa9229cf6804a0ae6e 100644 (file)
@@ -410,7 +410,6 @@ struct musb {
 
        /* is_suspended means USB B_PERIPHERAL suspend */
        unsigned                is_suspended:1;
-       unsigned                need_finish_resume :1;
 
        /* may_wakeup means remote wakeup is enabled */
        unsigned                may_wakeup:1;
index 7ce31a4c7e7fd3d186e8e05b20b9a3ca52700b6c..42cc72e54c051b2115c358bcee8bfc534258d206 100644 (file)
@@ -2007,6 +2007,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) }, /* HP lt2523 (Novatel E371) */
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 46fca6b7584686744a9e79aae0bd78db08192813..1db4b61bdf7bd710d7be6e3ff81b97102d76fbe9 100644 (file)
@@ -49,6 +49,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
        { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+       { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
        { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
        { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
        { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
index e3b7af8adfb73ccefa92d4ba3c2c927a044dfa43..09d9be88209e1ce6b1f53dc052a53c5e4c491336 100644 (file)
@@ -27,6 +27,7 @@
 #define ATEN_VENDOR_ID         0x0557
 #define ATEN_VENDOR_ID2                0x0547
 #define ATEN_PRODUCT_ID                0x2008
+#define ATEN_PRODUCT_ID2       0x2118
 
 #define IODATA_VENDOR_ID       0x04bb
 #define IODATA_PRODUCT_ID      0x0a03
index 1bc6089b90083a05e0ef3e4ff71c0ef752e3831a..696458db7e3c45e661a9825d05df0fe25dc0a832 100644 (file)
@@ -124,6 +124,7 @@ static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x1410, 0xa021)},   /* Novatel Gobi 3000 Composite */
        {USB_DEVICE(0x413c, 0x8193)},   /* Dell Gobi 3000 QDL */
        {USB_DEVICE(0x413c, 0x8194)},   /* Dell Gobi 3000 Composite */
+       {USB_DEVICE(0x413c, 0x81a6)},   /* Dell DW5570 QDL (MC8805) */
        {USB_DEVICE(0x1199, 0x68a4)},   /* Sierra Wireless QDL */
        {USB_DEVICE(0x1199, 0x68a5)},   /* Sierra Wireless Modem */
        {USB_DEVICE(0x1199, 0x68a8)},   /* Sierra Wireless QDL */
index 128d10282d1632693dc40819ff8b39485ba1e1de..7690e5bf3cf134fc56a0a17d07e57d397d293346 100644 (file)
@@ -1123,12 +1123,11 @@ static long tce_iommu_ioctl(void *iommu_data,
                mutex_lock(&container->lock);
 
                ret = tce_iommu_create_default_window(container);
-               if (ret)
-                       return ret;
-
-               ret = tce_iommu_create_window(container, create.page_shift,
-                               create.window_size, create.levels,
-                               &create.start_addr);
+               if (!ret)
+                       ret = tce_iommu_create_window(container,
+                                       create.page_shift,
+                                       create.window_size, create.levels,
+                                       &create.start_addr);
 
                mutex_unlock(&container->lock);
 
index d6432603880c1343ea2451eba6df1973e6d61822..8f99fe08de02e7b48725a99d682055c03056b82a 100644 (file)
@@ -130,14 +130,14 @@ static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx,
 
 static void vhost_init_is_le(struct vhost_virtqueue *vq)
 {
-       if (vhost_has_feature(vq, VIRTIO_F_VERSION_1))
-               vq->is_le = true;
+       vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1)
+               || virtio_legacy_is_little_endian();
 }
 #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */
 
 static void vhost_reset_is_le(struct vhost_virtqueue *vq)
 {
-       vq->is_le = virtio_legacy_is_little_endian();
+       vhost_init_is_le(vq);
 }
 
 struct vhost_flush_struct {
@@ -1714,10 +1714,8 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq)
        int r;
        bool is_le = vq->is_le;
 
-       if (!vq->private_data) {
-               vhost_reset_is_le(vq);
+       if (!vq->private_data)
                return 0;
-       }
 
        vhost_init_is_le(vq);
 
index 7e38ed79c3fc0f2c095164d480f75b31630a6694..409aeaa49246a0edd7c6da07ca38b58c3f876109 100644 (file)
@@ -159,13 +159,6 @@ static bool vring_use_dma_api(struct virtio_device *vdev)
        if (xen_domain())
                return true;
 
-       /*
-        * On ARM-based machines, the DMA ops will do the right thing,
-        * so always use them with legacy devices.
-        */
-       if (IS_ENABLED(CONFIG_ARM) || IS_ENABLED(CONFIG_ARM64))
-               return !virtio_has_feature(vdev, VIRTIO_F_VERSION_1);
-
        return false;
 }
 
index 8f6a2a5863b9d9275bfb6afb00fc16b867101275..a27fc8791551cc86ca14d2d65e7870990a393f1e 100644 (file)
@@ -285,6 +285,7 @@ initiate_cifs_search(const unsigned int xid, struct file *file)
                        rc = -ENOMEM;
                        goto error_exit;
                }
+               spin_lock_init(&cifsFile->file_info_lock);
                file->private_data = cifsFile;
                cifsFile->tlink = cifs_get_tlink(tlink);
                tcon = tlink_tcon(tlink);
index 3af2da5e64ce77fa8ae4b3f294c82882d350120f..c45598b912e14c981fdeb002b01c1535218c0ff2 100644 (file)
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -1031,6 +1031,11 @@ dax_iomap_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
                struct blk_dax_ctl dax = { 0 };
                ssize_t map_len;
 
+               if (fatal_signal_pending(current)) {
+                       ret = -EINTR;
+                       break;
+               }
+
                dax.sector = dax_iomap_sector(iomap, pos);
                dax.size = (length + offset + PAGE_SIZE - 1) & PAGE_MASK;
                map_len = dax_map_atomic(iomap->bdev, &dax);
index 4304072161aa08c14d24291bf24eb2481c567874..40d61077bead88e39abff93bcdb185941462bfcb 100644 (file)
@@ -542,6 +542,7 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate)
                hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) {
                        if (invalidate)
                                set_bit(FSCACHE_OBJECT_RETIRED, &object->flags);
+                       clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
                        fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
                }
        } else {
@@ -560,6 +561,10 @@ void __fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate)
                wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t,
                                 TASK_UNINTERRUPTIBLE);
 
+       /* Make sure any pending writes are cancelled. */
+       if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
+               fscache_invalidate_writes(cookie);
+
        /* Reset the cookie state if it wasn't relinquished */
        if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) {
                atomic_inc(&cookie->n_active);
index 9b28649df3a1fdc6f0f0c23b58b03db94dd69eb2..a8aa00be44442f59d6cf08516ab7403d0c02ab9e 100644 (file)
@@ -48,6 +48,7 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
        cookie->flags           = 1 << FSCACHE_COOKIE_ENABLED;
 
        spin_lock_init(&cookie->lock);
+       spin_lock_init(&cookie->stores_lock);
        INIT_HLIST_HEAD(&cookie->backing_objects);
 
        /* check the netfs type is not already present */
index 9e792e30f4db47b38c6db644487c440a2e12febb..7a182c87f37805f1a5fa6719f5cc06cf3dd38552 100644 (file)
@@ -30,6 +30,7 @@ static const struct fscache_state *fscache_look_up_object(struct fscache_object
 static const struct fscache_state *fscache_object_available(struct fscache_object *, int);
 static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int);
 static const struct fscache_state *fscache_update_object(struct fscache_object *, int);
+static const struct fscache_state *fscache_object_dead(struct fscache_object *, int);
 
 #define __STATE_NAME(n) fscache_osm_##n
 #define STATE(n) (&__STATE_NAME(n))
@@ -91,7 +92,7 @@ static WORK_STATE(LOOKUP_FAILURE,     "LCFL", fscache_lookup_failure);
 static WORK_STATE(KILL_OBJECT,         "KILL", fscache_kill_object);
 static WORK_STATE(KILL_DEPENDENTS,     "KDEP", fscache_kill_dependents);
 static WORK_STATE(DROP_OBJECT,         "DROP", fscache_drop_object);
-static WORK_STATE(OBJECT_DEAD,         "DEAD", (void*)2UL);
+static WORK_STATE(OBJECT_DEAD,         "DEAD", fscache_object_dead);
 
 static WAIT_STATE(WAIT_FOR_INIT,       "?INI",
                  TRANSIT_TO(INIT_OBJECT,       1 << FSCACHE_OBJECT_EV_NEW_CHILD));
@@ -229,6 +230,10 @@ execute_work_state:
        event = -1;
        if (new_state == NO_TRANSIT) {
                _debug("{OBJ%x} %s notrans", object->debug_id, state->name);
+               if (unlikely(state == STATE(OBJECT_DEAD))) {
+                       _leave(" [dead]");
+                       return;
+               }
                fscache_enqueue_object(object);
                event_mask = object->oob_event_mask;
                goto unmask_events;
@@ -239,7 +244,7 @@ execute_work_state:
        object->state = state = new_state;
 
        if (state->work) {
-               if (unlikely(state->work == ((void *)2UL))) {
+               if (unlikely(state == STATE(OBJECT_DEAD))) {
                        _leave(" [dead]");
                        return;
                }
@@ -645,6 +650,12 @@ static const struct fscache_state *fscache_kill_object(struct fscache_object *ob
        fscache_mark_object_dead(object);
        object->oob_event_mask = 0;
 
+       if (test_bit(FSCACHE_OBJECT_RETIRED, &object->flags)) {
+               /* Reject any new read/write ops and abort any that are pending. */
+               clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+               fscache_cancel_all_ops(object);
+       }
+
        if (list_empty(&object->dependents) &&
            object->n_ops == 0 &&
            object->n_children == 0)
@@ -1077,3 +1088,20 @@ void fscache_object_mark_killed(struct fscache_object *object,
        }
 }
 EXPORT_SYMBOL(fscache_object_mark_killed);
+
+/*
+ * The object is dead.  We can get here if an object gets queued by an event
+ * that would lead to its death (such as EV_KILL) when the dispatcher is
+ * already running (and so can be requeued) but hasn't yet cleared the event
+ * mask.
+ */
+static const struct fscache_state *fscache_object_dead(struct fscache_object *object,
+                                                      int event)
+{
+       if (!test_and_set_bit(FSCACHE_OBJECT_RUN_AFTER_DEAD,
+                             &object->flags))
+               return NO_TRANSIT;
+
+       WARN(true, "FS-Cache object redispatched after death");
+       return NO_TRANSIT;
+}
index 354a123f170e534a016f74ca7006458e3b823ef8..a51cb4c07d4d8cd3a09715361c84126cecae2ca2 100644 (file)
@@ -114,6 +114,9 @@ iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags,
 
        BUG_ON(pos + len > iomap->offset + iomap->length);
 
+       if (fatal_signal_pending(current))
+               return -EINTR;
+
        page = grab_cache_page_write_begin(inode->i_mapping, index, flags);
        if (!page)
                return -ENOMEM;
index 596205d939a1f43f1faa292d31680377045a8589..1fc07a9c70e9c6028342e8c97d183dfe914a343b 100644 (file)
@@ -223,10 +223,11 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
        struct nfs4_layout_stateid *ls;
        struct nfs4_stid *stp;
 
-       stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache);
+       stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
+                                       nfsd4_free_layout_stateid);
        if (!stp)
                return NULL;
-       stp->sc_free = nfsd4_free_layout_stateid;
+
        get_nfs4_file(fp);
        stp->sc_file = fp;
 
index 4b4beaaa4eaac01233f874c7dfdb8d1a6d7cd3d6..a0dee8ae9f97f16a18e40ba19f8e84a45ad1a02b 100644 (file)
@@ -633,8 +633,8 @@ out:
        return co;
 }
 
-struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
-                                        struct kmem_cache *slab)
+struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
+                                 void (*sc_free)(struct nfs4_stid *))
 {
        struct nfs4_stid *stid;
        int new_id;
@@ -650,6 +650,8 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
        idr_preload_end();
        if (new_id < 0)
                goto out_free;
+
+       stid->sc_free = sc_free;
        stid->sc_client = cl;
        stid->sc_stateid.si_opaque.so_id = new_id;
        stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
@@ -675,15 +677,12 @@ out_free:
 static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
 {
        struct nfs4_stid *stid;
-       struct nfs4_ol_stateid *stp;
 
-       stid = nfs4_alloc_stid(clp, stateid_slab);
+       stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
        if (!stid)
                return NULL;
 
-       stp = openlockstateid(stid);
-       stp->st_stid.sc_free = nfs4_free_ol_stateid;
-       return stp;
+       return openlockstateid(stid);
 }
 
 static void nfs4_free_deleg(struct nfs4_stid *stid)
@@ -781,11 +780,10 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh,
                goto out_dec;
        if (delegation_blocked(&current_fh->fh_handle))
                goto out_dec;
-       dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
+       dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
        if (dp == NULL)
                goto out_dec;
 
-       dp->dl_stid.sc_free = nfs4_free_deleg;
        /*
         * delegation seqid's are never incremented.  The 4.1 special
         * meaning of seqid 0 isn't meaningful, really, but let's avoid
@@ -5580,7 +5578,6 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
        stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
        get_nfs4_file(fp);
        stp->st_stid.sc_file = fp;
-       stp->st_stid.sc_free = nfs4_free_lock_stateid;
        stp->st_access_bmap = 0;
        stp->st_deny_bmap = open_stp->st_deny_bmap;
        stp->st_openstp = open_stp;
@@ -5623,7 +5620,7 @@ find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi,
        lst = find_lock_stateid(lo, fi);
        if (lst == NULL) {
                spin_unlock(&clp->cl_lock);
-               ns = nfs4_alloc_stid(clp, stateid_slab);
+               ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
                if (ns == NULL)
                        return NULL;
 
index c9399366f9dfc73b343d079fbad2dc2127927aae..4516e8b7d776305d94fb89f86256ee3fc54dec27 100644 (file)
@@ -603,8 +603,8 @@ extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
 __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
                     stateid_t *stateid, unsigned char typemask,
                     struct nfs4_stid **s, struct nfsd_net *nn);
-struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
-               struct kmem_cache *slab);
+struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
+                                 void (*sc_free)(struct nfs4_stid *));
 void nfs4_unhash_stid(struct nfs4_stid *s);
 void nfs4_put_stid(struct nfs4_stid *s);
 void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
index 26c6fdb4bf67cf1e3e3a843e8e816d7a76eae265..ca13236dbb1f33afb1c6664c030d63a5bfcfacc5 100644 (file)
@@ -332,37 +332,6 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
        }
 }
 
-static __be32
-nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               struct iattr *iap)
-{
-       struct inode *inode = d_inode(fhp->fh_dentry);
-       int host_err;
-
-       if (iap->ia_size < inode->i_size) {
-               __be32 err;
-
-               err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
-                               NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
-               if (err)
-                       return err;
-       }
-
-       host_err = get_write_access(inode);
-       if (host_err)
-               goto out_nfserrno;
-
-       host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
-       if (host_err)
-               goto out_put_write_access;
-       return 0;
-
-out_put_write_access:
-       put_write_access(inode);
-out_nfserrno:
-       return nfserrno(host_err);
-}
-
 /*
  * Set various file attributes.  After this call fhp needs an fh_put.
  */
@@ -377,7 +346,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        __be32          err;
        int             host_err;
        bool            get_write_count;
-       int             size_change = 0;
 
        if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
                accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
@@ -390,11 +358,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        /* Get inode */
        err = fh_verify(rqstp, fhp, ftype, accmode);
        if (err)
-               goto out;
+               return err;
        if (get_write_count) {
                host_err = fh_want_write(fhp);
                if (host_err)
-                       return nfserrno(host_err);
+                       goto out_host_err;
        }
 
        dentry = fhp->fh_dentry;
@@ -405,50 +373,59 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                iap->ia_valid &= ~ATTR_MODE;
 
        if (!iap->ia_valid)
-               goto out;
+               return 0;
 
        nfsd_sanitize_attrs(inode, iap);
 
+       if (check_guard && guardtime != inode->i_ctime.tv_sec)
+               return nfserr_notsync;
+
        /*
         * The size case is special, it changes the file in addition to the
-        * attributes.
+        * attributes, and file systems don't expect it to be mixed with
+        * "random" attribute changes.  We thus split out the size change
+        * into a separate call for vfs_truncate, and do the rest as a
+        * a separate setattr call.
         */
        if (iap->ia_valid & ATTR_SIZE) {
-               err = nfsd_get_write_access(rqstp, fhp, iap);
-               if (err)
-                       goto out;
-               size_change = 1;
+               struct path path = {
+                       .mnt    = fhp->fh_export->ex_path.mnt,
+                       .dentry = dentry,
+               };
+               bool implicit_mtime = false;
 
                /*
-                * RFC5661, Section 18.30.4:
-                *   Changing the size of a file with SETATTR indirectly
-                *   changes the time_modify and change attributes.
-                *
-                * (and similar for the older RFCs)
+                * vfs_truncate implicity updates the mtime IFF the file size
+                * actually changes.  Avoid the additional seattr call below if
+                * the only other attribute that the client sends is the mtime.
                 */
-               if (iap->ia_size != i_size_read(inode))
-                       iap->ia_valid |= ATTR_MTIME;
-       }
+               if (iap->ia_size != i_size_read(inode) &&
+                   ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0))
+                       implicit_mtime = true;
 
-       iap->ia_valid |= ATTR_CTIME;
+               host_err = vfs_truncate(&path, iap->ia_size);
+               if (host_err)
+                       goto out_host_err;
 
-       if (check_guard && guardtime != inode->i_ctime.tv_sec) {
-               err = nfserr_notsync;
-               goto out_put_write_access;
+               iap->ia_valid &= ~ATTR_SIZE;
+               if (implicit_mtime)
+                       iap->ia_valid &= ~ATTR_MTIME;
+               if (!iap->ia_valid)
+                       goto done;
        }
 
+       iap->ia_valid |= ATTR_CTIME;
+
        fh_lock(fhp);
        host_err = notify_change(dentry, iap, NULL);
        fh_unlock(fhp);
-       err = nfserrno(host_err);
+       if (host_err)
+               goto out_host_err;
 
-out_put_write_access:
-       if (size_change)
-               put_write_access(inode);
-       if (!err)
-               err = nfserrno(commit_metadata(fhp));
-out:
-       return err;
+done:
+       host_err = commit_metadata(fhp);
+out_host_err:
+       return nfserrno(host_err);
 }
 
 #if defined(CONFIG_NFSD_V4)
index 63554e9f6e0c68595943e27d2734ad4fa8271007..719db1968d8177a91028fd5e8bd6068f5d71c491 100644 (file)
@@ -9,18 +9,15 @@
 #ifndef KSYM_ALIGN
 #define KSYM_ALIGN 8
 #endif
-#ifndef KCRC_ALIGN
-#define KCRC_ALIGN 8
-#endif
 #else
 #define __put .long
 #ifndef KSYM_ALIGN
 #define KSYM_ALIGN 4
 #endif
+#endif
 #ifndef KCRC_ALIGN
 #define KCRC_ALIGN 4
 #endif
-#endif
 
 #ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
 #define KSYM(name) _##name
@@ -52,7 +49,11 @@ KSYM(__kstrtab_\name):
        .section ___kcrctab\sec+\name,"a"
        .balign KCRC_ALIGN
 KSYM(__kcrctab_\name):
-       __put KSYM(__crc_\name)
+#if defined(CONFIG_MODULE_REL_CRCS)
+       .long KSYM(__crc_\name) - .
+#else
+       .long KSYM(__crc_\name)
+#endif
        .weak KSYM(__crc_\name)
        .previous
 #endif
index 192016e2b5183c7a22fd13fd21372de5862f44d8..9c4ee144b5f6b799baf92a9722cddcaee3eb2b4f 100644 (file)
@@ -517,6 +517,7 @@ struct drm_device {
        struct drm_minor *control;              /**< Control node */
        struct drm_minor *primary;              /**< Primary node */
        struct drm_minor *render;               /**< Render node */
+       bool registered;
 
        /* currently active master for this device. Protected by master_mutex */
        struct drm_master *master;
index a9b95246e26efcf3d44cd5afc85f7031f0fa77fe..045a97cbeba24f44eb1b1d5582b4145801fcafdd 100644 (file)
@@ -381,6 +381,8 @@ struct drm_connector_funcs {
         * core drm connector interfaces. Everything added from this callback
         * should be unregistered in the early_unregister callback.
         *
+        * This is called while holding drm_connector->mutex.
+        *
         * Returns:
         *
         * 0 on success, or a negative error code on failure.
@@ -395,6 +397,8 @@ struct drm_connector_funcs {
         * late_register(). It is called from drm_connector_unregister(),
         * early in the driver unload sequence to disable userspace access
         * before data structures are torndown.
+        *
+        * This is called while holding drm_connector->mutex.
         */
        void (*early_unregister)(struct drm_connector *connector);
 
@@ -559,7 +563,6 @@ struct drm_cmdline_mode {
  * @interlace_allowed: can this connector handle interlaced modes?
  * @doublescan_allowed: can this connector handle doublescan?
  * @stereo_allowed: can this connector handle stereo modes?
- * @registered: is this connector exposed (registered) with userspace?
  * @modes: modes available on this connector (from fill_modes() + user)
  * @status: one of the drm_connector_status enums (connected, not, or unknown)
  * @probed_modes: list of modes derived directly from the display
@@ -607,6 +610,13 @@ struct drm_connector {
 
        char *name;
 
+       /**
+        * @mutex: Lock for general connector state, but currently only protects
+        * @registered. Most of the connector state is still protected by the
+        * mutex in &drm_mode_config.
+        */
+       struct mutex mutex;
+
        /**
         * @index: Compacted connector index, which matches the position inside
         * the mode_config.list for drivers not supporting hot-add/removing. Can
@@ -620,6 +630,10 @@ struct drm_connector {
        bool interlace_allowed;
        bool doublescan_allowed;
        bool stereo_allowed;
+       /**
+        * @registered: Is this connector exposed (registered) with userspace?
+        * Protected by @mutex.
+        */
        bool registered;
        struct list_head modes; /* list of modes on this connector */
 
diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h
new file mode 100644 (file)
index 0000000..e9892b4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright Â© 2016 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _INTEL_LPE_AUDIO_H_
+#define _INTEL_LPE_AUDIO_H_
+
+#include <linux/types.h>
+#include <linux/spinlock_types.h>
+
+struct platform_device;
+
+#define HDMI_MAX_ELD_BYTES     128
+
+struct intel_hdmi_lpe_audio_eld {
+       int port_id;
+       int pipe_id;
+       unsigned char eld_data[HDMI_MAX_ELD_BYTES];
+};
+
+struct intel_hdmi_lpe_audio_pdata {
+       bool notify_pending;
+       int tmds_clock_speed;
+       bool hdmi_connected;
+       bool dp_output;
+       int link_rate;
+       struct intel_hdmi_lpe_audio_eld eld;
+       void (*notify_audio_lpe)(struct platform_device *pdev);
+       spinlock_t lpe_audio_slock;
+};
+
+#endif /* _I915_LPE_AUDIO_H_ */
index a0875001b13c84ad70a9b2909654e9ffb6824c58..df08a41d5be5f26cfa4cdc74935f5eae7fa51385 100644 (file)
@@ -45,10 +45,9 @@ struct can_proto {
 extern int  can_proto_register(const struct can_proto *cp);
 extern void can_proto_unregister(const struct can_proto *cp);
 
-extern int  can_rx_register(struct net_device *dev, canid_t can_id,
-                           canid_t mask,
-                           void (*func)(struct sk_buff *, void *),
-                           void *data, char *ident);
+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
+                   void (*func)(struct sk_buff *, void *),
+                   void *data, char *ident, struct sock *sk);
 
 extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
                              canid_t mask,
index d936a0021839cca651e19ec43e71b8f21cb69cf0..921acaaa16017979df0722fb9803b204d77c0be0 100644 (file)
@@ -8,9 +8,7 @@ enum cpuhp_state {
        CPUHP_CREATE_THREADS,
        CPUHP_PERF_PREPARE,
        CPUHP_PERF_X86_PREPARE,
-       CPUHP_PERF_X86_UNCORE_PREP,
        CPUHP_PERF_X86_AMD_UNCORE_PREP,
-       CPUHP_PERF_X86_RAPL_PREP,
        CPUHP_PERF_BFIN,
        CPUHP_PERF_POWER,
        CPUHP_PERF_SUPERH,
@@ -86,7 +84,6 @@ enum cpuhp_state {
        CPUHP_AP_IRQ_ARMADA_XP_STARTING,
        CPUHP_AP_IRQ_BCM2836_STARTING,
        CPUHP_AP_ARM_MVEBU_COHERENCY,
-       CPUHP_AP_PERF_X86_UNCORE_STARTING,
        CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
        CPUHP_AP_PERF_X86_STARTING,
        CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
index 2a0f61fbc7310e61f5927c31250e208d217c3e26..1a1dfdb2a5c6d8806d11e2cd58722e304f293054 100644 (file)
@@ -43,12 +43,19 @@ extern struct module __this_module;
 #ifdef CONFIG_MODVERSIONS
 /* Mark the CRC weak since genksyms apparently decides not to
  * generate a checksums for some symbols */
+#if defined(CONFIG_MODULE_REL_CRCS)
 #define __CRC_SYMBOL(sym, sec)                                         \
-       extern __visible void *__crc_##sym __attribute__((weak));       \
-       static const unsigned long __kcrctab_##sym                      \
-       __used                                                          \
-       __attribute__((section("___kcrctab" sec "+" #sym), used))       \
-       = (unsigned long) &__crc_##sym;
+       asm("   .section \"___kcrctab" sec "+" #sym "\", \"a\"  \n"     \
+           "   .weak   " VMLINUX_SYMBOL_STR(__crc_##sym) "     \n"     \
+           "   .long   " VMLINUX_SYMBOL_STR(__crc_##sym) " - . \n"     \
+           "   .previous                                       \n");
+#else
+#define __CRC_SYMBOL(sym, sec)                                         \
+       asm("   .section \"___kcrctab" sec "+" #sym "\", \"a\"  \n"     \
+           "   .weak   " VMLINUX_SYMBOL_STR(__crc_##sym) "     \n"     \
+           "   .long   " VMLINUX_SYMBOL_STR(__crc_##sym) "     \n"     \
+           "   .previous                                       \n");
+#endif
 #else
 #define __CRC_SYMBOL(sym, sec)
 #endif
index 13ba552e6c094e82ee8b952b26d9f0bf5eeebc39..4c467ef50159db533ecb567a86eeaf6e1e81e632 100644 (file)
@@ -360,6 +360,7 @@ struct fscache_object {
 #define FSCACHE_OBJECT_IS_AVAILABLE    5       /* T if object has become active */
 #define FSCACHE_OBJECT_RETIRED         6       /* T if object was retired on relinquishment */
 #define FSCACHE_OBJECT_KILLED_BY_CACHE 7       /* T if object was killed by the cache */
+#define FSCACHE_OBJECT_RUN_AFTER_DEAD  8       /* T if object has been dispatched after death */
 
        struct list_head        cache_link;     /* link in cache->object_list */
        struct hlist_node       cookie_link;    /* link in cookie->backing_objects */
index 42fe43fb0c80605f9553c746f04310f43914f683..183efde54269e18c5d4d1eda7dc448717fe85800 100644 (file)
@@ -128,6 +128,7 @@ struct hv_ring_buffer_info {
        u32 ring_data_startoffset;
        u32 priv_write_index;
        u32 priv_read_index;
+       u32 cached_read_index;
 };
 
 /*
@@ -180,6 +181,19 @@ static inline u32 hv_get_bytes_to_write(struct hv_ring_buffer_info *rbi)
        return write;
 }
 
+static inline u32 hv_get_cached_bytes_to_write(
+       const struct hv_ring_buffer_info *rbi)
+{
+       u32 read_loc, write_loc, dsize, write;
+
+       dsize = rbi->ring_datasize;
+       read_loc = rbi->cached_read_index;
+       write_loc = rbi->ring_buffer->write_index;
+
+       write = write_loc >= read_loc ? dsize - (write_loc - read_loc) :
+               read_loc - write_loc;
+       return write;
+}
 /*
  * VMBUS version is 32 bit entity broken up into
  * two 16 bit quantities: major_number. minor_number.
@@ -1488,7 +1502,7 @@ hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info)
 
 static inline  void hv_signal_on_read(struct vmbus_channel *channel)
 {
-       u32 cur_write_sz;
+       u32 cur_write_sz, cached_write_sz;
        u32 pending_sz;
        struct hv_ring_buffer_info *rbi = &channel->inbound;
 
@@ -1512,12 +1526,24 @@ static inline  void hv_signal_on_read(struct vmbus_channel *channel)
 
        cur_write_sz = hv_get_bytes_to_write(rbi);
 
-       if (cur_write_sz >= pending_sz)
+       if (cur_write_sz < pending_sz)
+               return;
+
+       cached_write_sz = hv_get_cached_bytes_to_write(rbi);
+       if (cached_write_sz < pending_sz)
                vmbus_setevent(channel);
 
        return;
 }
 
+static inline void
+init_cached_read_index(struct vmbus_channel *channel)
+{
+       struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+       rbi->cached_read_index = rbi->ring_buffer->read_index;
+}
+
 /*
  * An API to support in-place processing of incoming VMBUS packets.
  */
@@ -1569,6 +1595,8 @@ static inline void put_pkt_raw(struct vmbus_channel *channel,
  * This call commits the read index and potentially signals the host.
  * Here is the pattern for using the "in-place" consumption APIs:
  *
+ * init_cached_read_index();
+ *
  * while (get_next_pkt_raw() {
  *     process the packet "in-place";
  *     put_pkt_raw();
index e79875574b393f33ed183fdc8f44277a49c26ba8..39e3254e5769d7da1d0f74cdfdf90bd9b40cfc8a 100644 (file)
@@ -184,6 +184,7 @@ struct irq_data {
  *
  * IRQD_TRIGGER_MASK           - Mask for the trigger type bits
  * IRQD_SETAFFINITY_PENDING    - Affinity setting is pending
+ * IRQD_ACTIVATED              - Interrupt has already been activated
  * IRQD_NO_BALANCING           - Balancing disabled for this IRQ
  * IRQD_PER_CPU                        - Interrupt is per cpu
  * IRQD_AFFINITY_SET           - Interrupt affinity was set
@@ -202,6 +203,7 @@ struct irq_data {
 enum {
        IRQD_TRIGGER_MASK               = 0xf,
        IRQD_SETAFFINITY_PENDING        = (1 <<  8),
+       IRQD_ACTIVATED                  = (1 <<  9),
        IRQD_NO_BALANCING               = (1 << 10),
        IRQD_PER_CPU                    = (1 << 11),
        IRQD_AFFINITY_SET               = (1 << 12),
@@ -312,6 +314,21 @@ static inline bool irqd_affinity_is_managed(struct irq_data *d)
        return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED;
 }
 
+static inline bool irqd_is_activated(struct irq_data *d)
+{
+       return __irqd_to_state(d) & IRQD_ACTIVATED;
+}
+
+static inline void irqd_set_activated(struct irq_data *d)
+{
+       __irqd_to_state(d) |= IRQD_ACTIVATED;
+}
+
+static inline void irqd_clr_activated(struct irq_data *d)
+{
+       __irqd_to_state(d) &= ~IRQD_ACTIVATED;
+}
+
 #undef __irqd_to_state
 
 static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
index fd7ff3d91e6a920ff084beca09d10b5b9abba981..ef3d4f67118ce0f60789e6e749a4773754e01e87 100644 (file)
@@ -203,6 +203,17 @@ unsigned long __rounddown_pow_of_two(unsigned long n)
  *  ... and so on.
  */
 
-#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+static inline __attribute_const__
+int __order_base_2(unsigned long n)
+{
+       return n > 1 ? ilog2(n - 1) + 1 : 0;
+}
 
+#define order_base_2(n)                                \
+(                                              \
+       __builtin_constant_p(n) ? (             \
+               ((n) == 0 || (n) == 1) ? 0 :    \
+               ilog2((n) - 1) + 1) :           \
+       __order_base_2(n)                       \
+)
 #endif /* _LINUX_LOG2_H */
index c1784c0b4f3585e0d20ca8253813c31d47f11c04..134a2f69c21abf7921181af0adff033bb459edc5 100644 (file)
@@ -85,7 +85,8 @@ extern int zone_grow_waitqueues(struct zone *zone, unsigned long nr_pages);
 extern int add_one_highpage(struct page *page, int pfn, int bad_ppro);
 /* VM interface that may be used by firmware interface */
 extern int online_pages(unsigned long, unsigned long, int);
-extern int test_pages_in_a_zone(unsigned long, unsigned long);
+extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
+       unsigned long *valid_start, unsigned long *valid_end);
 extern void __offline_isolated_pages(unsigned long, unsigned long);
 
 typedef void (*online_page_callback_t)(struct page *page);
index 7c84273d60b963d44c032761cac62194e82d1198..cc7cba219b207de5536f6f9e9353d1a20201e4af 100644 (file)
@@ -346,7 +346,7 @@ struct module {
 
        /* Exported symbols */
        const struct kernel_symbol *syms;
-       const unsigned long *crcs;
+       const s32 *crcs;
        unsigned int num_syms;
 
        /* Kernel parameters. */
@@ -359,18 +359,18 @@ struct module {
        /* GPL-only exported symbols. */
        unsigned int num_gpl_syms;
        const struct kernel_symbol *gpl_syms;
-       const unsigned long *gpl_crcs;
+       const s32 *gpl_crcs;
 
 #ifdef CONFIG_UNUSED_SYMBOLS
        /* unused exported symbols. */
        const struct kernel_symbol *unused_syms;
-       const unsigned long *unused_crcs;
+       const s32 *unused_crcs;
        unsigned int num_unused_syms;
 
        /* GPL-only, unused exported symbols. */
        unsigned int num_unused_gpl_syms;
        const struct kernel_symbol *unused_gpl_syms;
-       const unsigned long *unused_gpl_crcs;
+       const s32 *unused_gpl_crcs;
 #endif
 
 #ifdef CONFIG_MODULE_SIG
@@ -382,7 +382,7 @@ struct module {
 
        /* symbols that will be GPL-only in the near future. */
        const struct kernel_symbol *gpl_future_syms;
-       const unsigned long *gpl_future_crcs;
+       const s32 *gpl_future_crcs;
        unsigned int num_gpl_future_syms;
 
        /* Exception table */
@@ -523,7 +523,7 @@ struct module *find_module(const char *name);
 
 struct symsearch {
        const struct kernel_symbol *start, *stop;
-       const unsigned long *crcs;
+       const s32 *crcs;
        enum {
                NOT_GPL_ONLY,
                GPL_ONLY,
@@ -539,7 +539,7 @@ struct symsearch {
  */
 const struct kernel_symbol *find_symbol(const char *name,
                                        struct module **owner,
-                                       const unsigned long **crc,
+                                       const s32 **crc,
                                        bool gplok,
                                        bool warn);
 
index 9bde9558b59672a866bd763039d326bde2af0f81..70ad0291d517b41cd1d4a3c2c7fc046f13e27980 100644 (file)
@@ -866,11 +866,15 @@ struct netdev_xdp {
  *     of useless work if you return NETDEV_TX_BUSY.
  *     Required; cannot be NULL.
  *
- * netdev_features_t (*ndo_fix_features)(struct net_device *dev,
- *             netdev_features_t features);
- *     Adjusts the requested feature flags according to device-specific
- *     constraints, and returns the resulting flags. Must not modify
- *     the device state.
+ * netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
+ *                                        struct net_device *dev
+ *                                        netdev_features_t features);
+ *     Called by core transmit path to determine if device is capable of
+ *     performing offload operations on a given packet. This is to give
+ *     the device an opportunity to implement any restrictions that cannot
+ *     be otherwise expressed by feature flags. The check is called with
+ *     the set of features that the stack has calculated and it returns
+ *     those the driver believes to be appropriate.
  *
  * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb,
  *                         void *accel_priv, select_queue_fallback_t fallback);
@@ -1028,6 +1032,12 @@ struct netdev_xdp {
  *     Called to release previously enslaved netdev.
  *
  *      Feature/offload setting functions.
+ * netdev_features_t (*ndo_fix_features)(struct net_device *dev,
+ *             netdev_features_t features);
+ *     Adjusts the requested feature flags according to device-specific
+ *     constraints, and returns the resulting flags. Must not modify
+ *     the device state.
+ *
  * int (*ndo_set_features)(struct net_device *dev, netdev_features_t features);
  *     Called to update device configuration to new features. Passed
  *     feature set might be less than what was returned by ndo_fix_features()).
@@ -1100,15 +1110,6 @@ struct netdev_xdp {
  *     Callback to use for xmit over the accelerated station. This
  *     is used in place of ndo_start_xmit on accelerated net
  *     devices.
- * netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
- *                                        struct net_device *dev
- *                                        netdev_features_t features);
- *     Called by core transmit path to determine if device is capable of
- *     performing offload operations on a given packet. This is to give
- *     the device an opportunity to implement any restrictions that cannot
- *     be otherwise expressed by feature flags. The check is called with
- *     the set of features that the stack has calculated and it returns
- *     those the driver believes to be appropriate.
  * int (*ndo_set_tx_maxrate)(struct net_device *dev,
  *                          int queue_index, u32 maxrate);
  *     Called when a user wants to set a max-rate limitation of specific
index 1c7eec09e5eba7ae8c0cc8e82172791f992bb361..3a481a49546ef1c85d8f88bf7668f8a2c8e8c0f1 100644 (file)
@@ -204,7 +204,7 @@ static inline void percpu_ref_get(struct percpu_ref *ref)
 static inline bool percpu_ref_tryget(struct percpu_ref *ref)
 {
        unsigned long __percpu *percpu_count;
-       int ret;
+       bool ret;
 
        rcu_read_lock_sched();
 
@@ -238,7 +238,7 @@ static inline bool percpu_ref_tryget(struct percpu_ref *ref)
 static inline bool percpu_ref_tryget_live(struct percpu_ref *ref)
 {
        unsigned long __percpu *percpu_count;
-       int ret = false;
+       bool ret = false;
 
        rcu_read_lock_sched();
 
index 7afe991e900e25838c3e66f2ff185a5226f790ff..dbf0abba33b8da21be05abf6e719f69542da80fc 100644 (file)
@@ -776,6 +776,11 @@ static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb,
 {
        u32 hash;
 
+       /* @flowlabel may include more than a flow label, eg, the traffic class.
+        * Here we want only the flow label value.
+        */
+       flowlabel &= IPV6_FLOWLABEL_MASK;
+
        if (flowlabel ||
            net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
            (!autolabel &&
index af1fb37c6b265cf20de58dee1e0d7490669a9bf1..361749e607991b742b1ddc62be1e7bb22b2c18eb 100644 (file)
@@ -570,6 +570,15 @@ int snd_pcm_stop_xrun(struct snd_pcm_substream *substream);
 #ifdef CONFIG_PM
 int snd_pcm_suspend(struct snd_pcm_substream *substream);
 int snd_pcm_suspend_all(struct snd_pcm *pcm);
+#else
+static inline int snd_pcm_suspend(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+static inline int snd_pcm_suspend_all(struct snd_pcm *pcm)
+{
+       return 0;
+}
 #endif
 int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, unsigned int cmd, void *arg);
 int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, struct file *file,
index f730b91e472f19f97b15ec8982443fe099dd5db4..492a3ca7f17bd0ba210ac57f6d7109d31ee841cd 100644 (file)
@@ -103,7 +103,7 @@ struct snd_rawmidi_substream {
        struct snd_rawmidi_runtime *runtime;
        struct pid *pid;
        /* hardware layer */
-       struct snd_rawmidi_ops *ops;
+       const struct snd_rawmidi_ops *ops;
 };
 
 struct snd_rawmidi_file {
@@ -155,7 +155,7 @@ int snd_rawmidi_new(struct snd_card *card, char *id, int device,
                    int output_count, int input_count,
                    struct snd_rawmidi **rmidi);
 void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
-                        struct snd_rawmidi_ops *ops);
+                        const struct snd_rawmidi_ops *ops);
 
 /* callbacks */
 
index 35e94b3d1ec7fa3a5f848bb3a1ad33c8f09d9e7e..cd0bab1ef6f125f016cc6e4c6d06eeec0b563fb9 100644 (file)
@@ -37,8 +37,8 @@ struct _snd_wavefront_midi {
 #define        MPU_ACK         0xFE
 #define        UART_MODE_ON    0x3F
 
-extern struct snd_rawmidi_ops snd_wavefront_midi_output;
-extern struct snd_rawmidi_ops snd_wavefront_midi_input;
+extern const struct snd_rawmidi_ops snd_wavefront_midi_output;
+extern const struct snd_rawmidi_ops snd_wavefront_midi_input;
 
 extern void   snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *);
 extern void   snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *);
index f0db7788f887b9947e0e1aa78d48a9980e80bddf..3dc91a46e8b8da0b243a12a168bbf205e5a87916 100644 (file)
@@ -1384,6 +1384,8 @@ enum ethtool_link_mode_bit_indices {
        ETHTOOL_LINK_MODE_10000baseLR_Full_BIT  = 44,
        ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT = 45,
        ETHTOOL_LINK_MODE_10000baseER_Full_BIT  = 46,
+       ETHTOOL_LINK_MODE_2500baseT_Full_BIT    = 47,
+       ETHTOOL_LINK_MODE_5000baseT_Full_BIT    = 48,
 
 
        /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
@@ -1393,7 +1395,7 @@ enum ethtool_link_mode_bit_indices {
         */
 
        __ETHTOOL_LINK_MODE_LAST
-         = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+         = ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
 };
 
 #define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name)     \
index e1a937348a3ed2bb3a76820e1ffa6a542f6aa9fb..4dd8bd232a1d4efd012fab8757887426ece9c0aa 100644 (file)
@@ -1987,6 +1987,10 @@ config MODVERSIONS
          make them incompatible with the kernel you are running.  If
          unsure, say N.
 
+config MODULE_REL_CRCS
+       bool
+       depends on MODVERSIONS
+
 config MODULE_SRCVERSION_ALL
        bool "Source checksum for all modules"
        help
index 2ee9ec3051b20774b118a57e4609f30e87bf82be..688dd02af9857e6fe739e0b4258060820acb41e3 100644 (file)
@@ -5221,6 +5221,11 @@ err_free_css:
        return ERR_PTR(err);
 }
 
+/*
+ * The returned cgroup is fully initialized including its control mask, but
+ * it isn't associated with its kernfs_node and doesn't have the control
+ * mask applied.
+ */
 static struct cgroup *cgroup_create(struct cgroup *parent)
 {
        struct cgroup_root *root = parent->root;
@@ -5288,11 +5293,6 @@ static struct cgroup *cgroup_create(struct cgroup *parent)
 
        cgroup_propagate_control(cgrp);
 
-       /* @cgrp doesn't have dir yet so the following will only create csses */
-       ret = cgroup_apply_control_enable(cgrp);
-       if (ret)
-               goto out_destroy;
-
        return cgrp;
 
 out_cancel_ref:
@@ -5300,9 +5300,6 @@ out_cancel_ref:
 out_free_cgrp:
        kfree(cgrp);
        return ERR_PTR(ret);
-out_destroy:
-       cgroup_destroy_locked(cgrp);
-       return ERR_PTR(ret);
 }
 
 static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
index 110b38a58493ee4ba4c19763d2678dae8815e1af..e5aaa806702de888b63a82bdcb72766f7a317563 100644 (file)
@@ -1469,7 +1469,6 @@ ctx_group_list(struct perf_event *event, struct perf_event_context *ctx)
 static void
 list_add_event(struct perf_event *event, struct perf_event_context *ctx)
 {
-
        lockdep_assert_held(&ctx->lock);
 
        WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT);
@@ -1624,6 +1623,8 @@ static void perf_group_attach(struct perf_event *event)
 {
        struct perf_event *group_leader = event->group_leader, *pos;
 
+       lockdep_assert_held(&event->ctx->lock);
+
        /*
         * We can have double attach due to group movement in perf_event_open.
         */
@@ -1697,6 +1698,8 @@ static void perf_group_detach(struct perf_event *event)
        struct perf_event *sibling, *tmp;
        struct list_head *list = NULL;
 
+       lockdep_assert_held(&event->ctx->lock);
+
        /*
         * We can have double detach due to exit/hot-unplug + close.
         */
@@ -1895,9 +1898,29 @@ __perf_remove_from_context(struct perf_event *event,
  */
 static void perf_remove_from_context(struct perf_event *event, unsigned long flags)
 {
-       lockdep_assert_held(&event->ctx->mutex);
+       struct perf_event_context *ctx = event->ctx;
+
+       lockdep_assert_held(&ctx->mutex);
 
        event_function_call(event, __perf_remove_from_context, (void *)flags);
+
+       /*
+        * The above event_function_call() can NO-OP when it hits
+        * TASK_TOMBSTONE. In that case we must already have been detached
+        * from the context (by perf_event_exit_event()) but the grouping
+        * might still be in-tact.
+        */
+       WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT);
+       if ((flags & DETACH_GROUP) &&
+           (event->attach_state & PERF_ATTACH_GROUP)) {
+               /*
+                * Since in that case we cannot possibly be scheduled, simply
+                * detach now.
+                */
+               raw_spin_lock_irq(&ctx->lock);
+               perf_group_detach(event);
+               raw_spin_unlock_irq(&ctx->lock);
+       }
 }
 
 /*
@@ -6609,6 +6632,27 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
        char *buf = NULL;
        char *name;
 
+       if (vma->vm_flags & VM_READ)
+               prot |= PROT_READ;
+       if (vma->vm_flags & VM_WRITE)
+               prot |= PROT_WRITE;
+       if (vma->vm_flags & VM_EXEC)
+               prot |= PROT_EXEC;
+
+       if (vma->vm_flags & VM_MAYSHARE)
+               flags = MAP_SHARED;
+       else
+               flags = MAP_PRIVATE;
+
+       if (vma->vm_flags & VM_DENYWRITE)
+               flags |= MAP_DENYWRITE;
+       if (vma->vm_flags & VM_MAYEXEC)
+               flags |= MAP_EXECUTABLE;
+       if (vma->vm_flags & VM_LOCKED)
+               flags |= MAP_LOCKED;
+       if (vma->vm_flags & VM_HUGETLB)
+               flags |= MAP_HUGETLB;
+
        if (file) {
                struct inode *inode;
                dev_t dev;
@@ -6635,27 +6679,6 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
                maj = MAJOR(dev);
                min = MINOR(dev);
 
-               if (vma->vm_flags & VM_READ)
-                       prot |= PROT_READ;
-               if (vma->vm_flags & VM_WRITE)
-                       prot |= PROT_WRITE;
-               if (vma->vm_flags & VM_EXEC)
-                       prot |= PROT_EXEC;
-
-               if (vma->vm_flags & VM_MAYSHARE)
-                       flags = MAP_SHARED;
-               else
-                       flags = MAP_PRIVATE;
-
-               if (vma->vm_flags & VM_DENYWRITE)
-                       flags |= MAP_DENYWRITE;
-               if (vma->vm_flags & VM_MAYEXEC)
-                       flags |= MAP_EXECUTABLE;
-               if (vma->vm_flags & VM_LOCKED)
-                       flags |= MAP_LOCKED;
-               if (vma->vm_flags & VM_HUGETLB)
-                       flags |= MAP_HUGETLB;
-
                goto got_name;
        } else {
                if (vma->vm_ops && vma->vm_ops->name) {
index 8c0a0ae43521c7f8b9e97964912cc3ab5e10fd15..b59e6768c5e94ad831e78b539437cfd99576e780 100644 (file)
@@ -1346,6 +1346,30 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain,
 }
 EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
 
+static void __irq_domain_activate_irq(struct irq_data *irq_data)
+{
+       if (irq_data && irq_data->domain) {
+               struct irq_domain *domain = irq_data->domain;
+
+               if (irq_data->parent_data)
+                       __irq_domain_activate_irq(irq_data->parent_data);
+               if (domain->ops->activate)
+                       domain->ops->activate(domain, irq_data);
+       }
+}
+
+static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
+{
+       if (irq_data && irq_data->domain) {
+               struct irq_domain *domain = irq_data->domain;
+
+               if (domain->ops->deactivate)
+                       domain->ops->deactivate(domain, irq_data);
+               if (irq_data->parent_data)
+                       __irq_domain_deactivate_irq(irq_data->parent_data);
+       }
+}
+
 /**
  * irq_domain_activate_irq - Call domain_ops->activate recursively to activate
  *                          interrupt
@@ -1356,13 +1380,9 @@ EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
  */
 void irq_domain_activate_irq(struct irq_data *irq_data)
 {
-       if (irq_data && irq_data->domain) {
-               struct irq_domain *domain = irq_data->domain;
-
-               if (irq_data->parent_data)
-                       irq_domain_activate_irq(irq_data->parent_data);
-               if (domain->ops->activate)
-                       domain->ops->activate(domain, irq_data);
+       if (!irqd_is_activated(irq_data)) {
+               __irq_domain_activate_irq(irq_data);
+               irqd_set_activated(irq_data);
        }
 }
 
@@ -1376,13 +1396,9 @@ void irq_domain_activate_irq(struct irq_data *irq_data)
  */
 void irq_domain_deactivate_irq(struct irq_data *irq_data)
 {
-       if (irq_data && irq_data->domain) {
-               struct irq_domain *domain = irq_data->domain;
-
-               if (domain->ops->deactivate)
-                       domain->ops->deactivate(domain, irq_data);
-               if (irq_data->parent_data)
-                       irq_domain_deactivate_irq(irq_data->parent_data);
+       if (irqd_is_activated(irq_data)) {
+               __irq_domain_deactivate_irq(irq_data);
+               irqd_clr_activated(irq_data);
        }
 }
 
index 38d4270925d4d13619d725052aa3f9844f23bc96..3d8f126208e3ae04eeff3fd1b1e00044c0e3d0d2 100644 (file)
@@ -389,16 +389,16 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __start___ksymtab_gpl_future[];
 extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
-extern const unsigned long __start___kcrctab[];
-extern const unsigned long __start___kcrctab_gpl[];
-extern const unsigned long __start___kcrctab_gpl_future[];
+extern const s32 __start___kcrctab[];
+extern const s32 __start___kcrctab_gpl[];
+extern const s32 __start___kcrctab_gpl_future[];
 #ifdef CONFIG_UNUSED_SYMBOLS
 extern const struct kernel_symbol __start___ksymtab_unused[];
 extern const struct kernel_symbol __stop___ksymtab_unused[];
 extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
-extern const unsigned long __start___kcrctab_unused[];
-extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const s32 __start___kcrctab_unused[];
+extern const s32 __start___kcrctab_unused_gpl[];
 #endif
 
 #ifndef CONFIG_MODVERSIONS
@@ -497,7 +497,7 @@ struct find_symbol_arg {
 
        /* Output */
        struct module *owner;
-       const unsigned long *crc;
+       const s32 *crc;
        const struct kernel_symbol *sym;
 };
 
@@ -563,7 +563,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
  * (optional) module which owns it.  Needs preempt disabled or module_mutex. */
 const struct kernel_symbol *find_symbol(const char *name,
                                        struct module **owner,
-                                       const unsigned long **crc,
+                                       const s32 **crc,
                                        bool gplok,
                                        bool warn)
 {
@@ -1249,23 +1249,17 @@ static int try_to_force_load(struct module *mod, const char *reason)
 }
 
 #ifdef CONFIG_MODVERSIONS
-/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
-static unsigned long maybe_relocated(unsigned long crc,
-                                    const struct module *crc_owner)
+
+static u32 resolve_rel_crc(const s32 *crc)
 {
-#ifdef ARCH_RELOCATES_KCRCTAB
-       if (crc_owner == NULL)
-               return crc - (unsigned long)reloc_start;
-#endif
-       return crc;
+       return *(u32 *)((void *)crc + *crc);
 }
 
 static int check_version(Elf_Shdr *sechdrs,
                         unsigned int versindex,
                         const char *symname,
                         struct module *mod,
-                        const unsigned long *crc,
-                        const struct module *crc_owner)
+                        const s32 *crc)
 {
        unsigned int i, num_versions;
        struct modversion_info *versions;
@@ -1283,13 +1277,19 @@ static int check_version(Elf_Shdr *sechdrs,
                / sizeof(struct modversion_info);
 
        for (i = 0; i < num_versions; i++) {
+               u32 crcval;
+
                if (strcmp(versions[i].name, symname) != 0)
                        continue;
 
-               if (versions[i].crc == maybe_relocated(*crc, crc_owner))
+               if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
+                       crcval = resolve_rel_crc(crc);
+               else
+                       crcval = *crc;
+               if (versions[i].crc == crcval)
                        return 1;
-               pr_debug("Found checksum %lX vs module %lX\n",
-                      maybe_relocated(*crc, crc_owner), versions[i].crc);
+               pr_debug("Found checksum %X vs module %lX\n",
+                        crcval, versions[i].crc);
                goto bad_version;
        }
 
@@ -1307,7 +1307,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
                                          unsigned int versindex,
                                          struct module *mod)
 {
-       const unsigned long *crc;
+       const s32 *crc;
 
        /*
         * Since this should be found in kernel (which can't be removed), no
@@ -1321,8 +1321,7 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
        }
        preempt_enable();
        return check_version(sechdrs, versindex,
-                            VMLINUX_SYMBOL_STR(module_layout), mod, crc,
-                            NULL);
+                            VMLINUX_SYMBOL_STR(module_layout), mod, crc);
 }
 
 /* First part is kernel version, which we ignore if module has crcs. */
@@ -1340,8 +1339,7 @@ static inline int check_version(Elf_Shdr *sechdrs,
                                unsigned int versindex,
                                const char *symname,
                                struct module *mod,
-                               const unsigned long *crc,
-                               const struct module *crc_owner)
+                               const s32 *crc)
 {
        return 1;
 }
@@ -1368,7 +1366,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
 {
        struct module *owner;
        const struct kernel_symbol *sym;
-       const unsigned long *crc;
+       const s32 *crc;
        int err;
 
        /*
@@ -1383,8 +1381,7 @@ static const struct kernel_symbol *resolve_symbol(struct module *mod,
        if (!sym)
                goto unlock;
 
-       if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
-                          owner)) {
+       if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
                sym = ERR_PTR(-EINVAL);
                goto getname;
        }
index 775569ec50d03fbf0ca4f755f79d106a63acaf1a..af344a1bf0d0e6270e5e659ffa160753e148cdd9 100644 (file)
@@ -266,7 +266,7 @@ out:
 static struct cpumask save_cpumask;
 static bool disable_migrate;
 
-static void move_to_next_cpu(void)
+static void move_to_next_cpu(bool initmask)
 {
        static struct cpumask *current_mask;
        int next_cpu;
@@ -275,7 +275,7 @@ static void move_to_next_cpu(void)
                return;
 
        /* Just pick the first CPU on first iteration */
-       if (!current_mask) {
+       if (initmask) {
                current_mask = &save_cpumask;
                get_online_cpus();
                cpumask_and(current_mask, cpu_online_mask, tracing_buffer_mask);
@@ -330,10 +330,12 @@ static void move_to_next_cpu(void)
 static int kthread_fn(void *data)
 {
        u64 interval;
+       bool initmask = true;
 
        while (!kthread_should_stop()) {
 
-               move_to_next_cpu();
+               move_to_next_cpu(initmask);
+               initmask = false;
 
                local_irq_disable();
                get_sample();
index a133ecd741e437d938ca377cf5e4358bcb586aa4..7ad9e53ad174bc6cdb0f99490f87e419e9381b02 100644 (file)
@@ -1372,7 +1372,7 @@ kprobe_trace_selftest_target(int a1, int a2, int a3, int a4, int a5, int a6)
        return a1 + a2 + a3 + a4 + a5 + a6;
 }
 
-static struct __init trace_event_file *
+static __init struct trace_event_file *
 find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr)
 {
        struct trace_event_file *file;
index b772a33ef640ab0d6770bb3d249a6fe6f16eeebc..3f9afded581be1a013bda4db2c0ec3a721323364 100644 (file)
@@ -1791,6 +1791,11 @@ static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos,
 
                cond_resched();
 find_page:
+               if (fatal_signal_pending(current)) {
+                       error = -EINTR;
+                       goto out;
+               }
+
                page = find_get_page(mapping, index);
                if (!page) {
                        page_cache_sync_readahead(mapping,
index b82b3e2151574ae1abbb2cd57624114727975410..f479365530b6484bbd5cae42064521fed362961e 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 
+#include <linux/ftrace.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/printk.h>
@@ -300,6 +301,8 @@ void kasan_report(unsigned long addr, size_t size,
        if (likely(!kasan_report_enabled()))
                return;
 
+       disable_trace_on_warning();
+
        info.access_addr = (void *)addr;
        info.access_size = size;
        info.is_write = is_write;
index ca2723d4733849eab01b323a50e6b1bc609e308c..b8c11e063ff0746316fb792f4fe1dde0094cb828 100644 (file)
@@ -1483,17 +1483,20 @@ bool is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
 }
 
 /*
- * Confirm all pages in a range [start, end) is belongs to the same zone.
+ * Confirm all pages in a range [start, end) belong to the same zone.
+ * When true, return its valid [start, end).
  */
-int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
+int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
+                        unsigned long *valid_start, unsigned long *valid_end)
 {
        unsigned long pfn, sec_end_pfn;
+       unsigned long start, end;
        struct zone *zone = NULL;
        struct page *page;
        int i;
-       for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
+       for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn + 1);
             pfn < end_pfn;
-            pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+            pfn = sec_end_pfn, sec_end_pfn += PAGES_PER_SECTION) {
                /* Make sure the memory section is present first */
                if (!present_section_nr(pfn_to_section_nr(pfn)))
                        continue;
@@ -1509,10 +1512,20 @@ int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
                        page = pfn_to_page(pfn + i);
                        if (zone && page_zone(page) != zone)
                                return 0;
+                       if (!zone)
+                               start = pfn + i;
                        zone = page_zone(page);
+                       end = pfn + MAX_ORDER_NR_PAGES;
                }
        }
-       return 1;
+
+       if (zone) {
+               *valid_start = start;
+               *valid_end = end;
+               return 1;
+       } else {
+               return 0;
+       }
 }
 
 /*
@@ -1839,6 +1852,7 @@ static int __ref __offline_pages(unsigned long start_pfn,
        long offlined_pages;
        int ret, drain, retry_max, node;
        unsigned long flags;
+       unsigned long valid_start, valid_end;
        struct zone *zone;
        struct memory_notify arg;
 
@@ -1849,10 +1863,10 @@ static int __ref __offline_pages(unsigned long start_pfn,
                return -EINVAL;
        /* This makes hotplug much easier...and readable.
           we assume this for now. .*/
-       if (!test_pages_in_a_zone(start_pfn, end_pfn))
+       if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
                return -EINVAL;
 
-       zone = page_zone(pfn_to_page(start_pfn));
+       zone = page_zone(pfn_to_page(valid_start));
        node = zone_to_nid(zone);
        nr_pages = end_pfn - start_pfn;
 
index bb53285a1d99666676e85697330f1a052f7c3cc0..3a7587a0314dc73fb4929a824a74f9b8948ea502 100644 (file)
@@ -415,6 +415,7 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
                struct shrink_control *sc, unsigned long nr_to_split)
 {
        LIST_HEAD(list), *pos, *next;
+       LIST_HEAD(to_remove);
        struct inode *inode;
        struct shmem_inode_info *info;
        struct page *page;
@@ -441,9 +442,8 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
                /* Check if there's anything to gain */
                if (round_up(inode->i_size, PAGE_SIZE) ==
                                round_up(inode->i_size, HPAGE_PMD_SIZE)) {
-                       list_del_init(&info->shrinklist);
+                       list_move(&info->shrinklist, &to_remove);
                        removed++;
-                       iput(inode);
                        goto next;
                }
 
@@ -454,6 +454,13 @@ next:
        }
        spin_unlock(&sbinfo->shrinklist_lock);
 
+       list_for_each_safe(pos, next, &to_remove) {
+               info = list_entry(pos, struct shmem_inode_info, shrinklist);
+               inode = &info->vfs_inode;
+               list_del_init(&info->shrinklist);
+               iput(inode);
+       }
+
        list_for_each_safe(pos, next, &list) {
                int ret;
 
index 067a0d62f31841d16913d36e38531a277ab59b01..cabf09e0128beebdee2b8a959361fe6464fb3469 100644 (file)
@@ -78,7 +78,13 @@ static u64 zswap_duplicate_entry;
 
 /* Enable/disable zswap (disabled by default) */
 static bool zswap_enabled;
-module_param_named(enabled, zswap_enabled, bool, 0644);
+static int zswap_enabled_param_set(const char *,
+                                  const struct kernel_param *);
+static struct kernel_param_ops zswap_enabled_param_ops = {
+       .set =          zswap_enabled_param_set,
+       .get =          param_get_bool,
+};
+module_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644);
 
 /* Crypto compressor to use */
 #define ZSWAP_COMPRESSOR_DEFAULT "lzo"
@@ -176,6 +182,9 @@ static atomic_t zswap_pools_count = ATOMIC_INIT(0);
 /* used by param callback function */
 static bool zswap_init_started;
 
+/* fatal error during init */
+static bool zswap_init_failed;
+
 /*********************************
 * helpers and fwd declarations
 **********************************/
@@ -624,6 +633,11 @@ static int __zswap_param_set(const char *val, const struct kernel_param *kp,
        char *s = strstrip((char *)val);
        int ret;
 
+       if (zswap_init_failed) {
+               pr_err("can't set param, initialization failed\n");
+               return -ENODEV;
+       }
+
        /* no change required */
        if (!strcmp(s, *(char **)kp->arg))
                return 0;
@@ -703,6 +717,17 @@ static int zswap_zpool_param_set(const char *val,
        return __zswap_param_set(val, kp, NULL, zswap_compressor);
 }
 
+static int zswap_enabled_param_set(const char *val,
+                                  const struct kernel_param *kp)
+{
+       if (zswap_init_failed) {
+               pr_err("can't enable, initialization failed\n");
+               return -ENODEV;
+       }
+
+       return param_set_bool(val, kp);
+}
+
 /*********************************
 * writeback code
 **********************************/
@@ -1201,6 +1226,9 @@ hp_fail:
 dstmem_fail:
        zswap_entry_cache_destroy();
 cache_fail:
+       /* if built-in, we aren't unloaded on failure; don't allow use */
+       zswap_init_failed = true;
+       zswap_enabled = false;
        return -ENOMEM;
 }
 /* must be late so crypto has time to come up */
index 1108079d934f8383a599d7997b08100fca0465e9..5488e4a6ccd062e6f6e7e2b841dde5ef055d4337 100644 (file)
@@ -445,6 +445,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
  * @func: callback function on filter match
  * @data: returned parameter for callback function
  * @ident: string for calling module identification
+ * @sk: socket pointer (might be NULL)
  *
  * Description:
  *  Invokes the callback function with the received sk_buff and the given
@@ -468,7 +469,7 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
  */
 int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
                    void (*func)(struct sk_buff *, void *), void *data,
-                   char *ident)
+                   char *ident, struct sock *sk)
 {
        struct receiver *r;
        struct hlist_head *rl;
@@ -496,6 +497,7 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
                r->func    = func;
                r->data    = data;
                r->ident   = ident;
+               r->sk      = sk;
 
                hlist_add_head_rcu(&r->list, rl);
                d->entries++;
@@ -520,8 +522,11 @@ EXPORT_SYMBOL(can_rx_register);
 static void can_rx_delete_receiver(struct rcu_head *rp)
 {
        struct receiver *r = container_of(rp, struct receiver, rcu);
+       struct sock *sk = r->sk;
 
        kmem_cache_free(rcv_cache, r);
+       if (sk)
+               sock_put(sk);
 }
 
 /**
@@ -596,8 +601,11 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
        spin_unlock(&can_rcvlists_lock);
 
        /* schedule the receiver item for deletion */
-       if (r)
+       if (r) {
+               if (r->sk)
+                       sock_hold(r->sk);
                call_rcu(&r->rcu, can_rx_delete_receiver);
+       }
 }
 EXPORT_SYMBOL(can_rx_unregister);
 
index fca0fe9fc45a497cdf3da82d5414e846e7cc61b7..b86f5129e8385fe84ef671bb914e8e05c2977ca0 100644 (file)
 
 struct receiver {
        struct hlist_node list;
-       struct rcu_head rcu;
        canid_t can_id;
        canid_t mask;
        unsigned long matches;
        void (*func)(struct sk_buff *, void *);
        void *data;
        char *ident;
+       struct sock *sk;
+       struct rcu_head rcu;
 };
 
 #define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
index 21ac75390e3d64f795faad074b515d34ce0bbfa3..95d13b233c65161cf3595a8b0036207f5c2892e3 100644 (file)
@@ -734,14 +734,23 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
 
 static void bcm_remove_op(struct bcm_op *op)
 {
-       hrtimer_cancel(&op->timer);
-       hrtimer_cancel(&op->thrtimer);
-
-       if (op->tsklet.func)
-               tasklet_kill(&op->tsklet);
+       if (op->tsklet.func) {
+               while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) ||
+                      test_bit(TASKLET_STATE_RUN, &op->tsklet.state) ||
+                      hrtimer_active(&op->timer)) {
+                       hrtimer_cancel(&op->timer);
+                       tasklet_kill(&op->tsklet);
+               }
+       }
 
-       if (op->thrtsklet.func)
-               tasklet_kill(&op->thrtsklet);
+       if (op->thrtsklet.func) {
+               while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) ||
+                      test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) ||
+                      hrtimer_active(&op->thrtimer)) {
+                       hrtimer_cancel(&op->thrtimer);
+                       tasklet_kill(&op->thrtsklet);
+               }
+       }
 
        if ((op->frames) && (op->frames != &op->sframe))
                kfree(op->frames);
@@ -1216,7 +1225,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                                err = can_rx_register(dev, op->can_id,
                                                      REGMASK(op->can_id),
                                                      bcm_rx_handler, op,
-                                                     "bcm");
+                                                     "bcm", sk);
 
                                op->rx_reg_dev = dev;
                                dev_put(dev);
@@ -1225,7 +1234,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
                } else
                        err = can_rx_register(NULL, op->can_id,
                                              REGMASK(op->can_id),
-                                             bcm_rx_handler, op, "bcm");
+                                             bcm_rx_handler, op, "bcm", sk);
                if (err) {
                        /* this bcm rx op is broken -> remove it */
                        list_del(&op->list);
index a54ab0c821048ab2034bf32cef3c1f35e0dc82a5..7056a1a2bb70098e691ce557f05e5bc1f27cb42f 100644 (file)
@@ -442,7 +442,7 @@ static inline int cgw_register_filter(struct cgw_job *gwj)
 {
        return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
                               gwj->ccgw.filter.can_mask, can_can_gw_rcv,
-                              gwj, "gw");
+                              gwj, "gw", NULL);
 }
 
 static inline void cgw_unregister_filter(struct cgw_job *gwj)
index b075f028d7e23958e9433a4b19f4475ad930b547..6dc546a06673ff41fc121c546ebd0567bb0da05f 100644 (file)
@@ -190,7 +190,7 @@ static int raw_enable_filters(struct net_device *dev, struct sock *sk,
        for (i = 0; i < count; i++) {
                err = can_rx_register(dev, filter[i].can_id,
                                      filter[i].can_mask,
-                                     raw_rcv, sk, "raw");
+                                     raw_rcv, sk, "raw", sk);
                if (err) {
                        /* clean up successfully registered filters */
                        while (--i >= 0)
@@ -211,7 +211,7 @@ static int raw_enable_errfilter(struct net_device *dev, struct sock *sk,
 
        if (err_mask)
                err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
-                                     raw_rcv, sk, "raw");
+                                     raw_rcv, sk, "raw", sk);
 
        return err;
 }
index 1d5331a1b1dc2677316148ba9852c191e7ed0fd4..8ce50dc3ab8cac821b8a2c3e0d31f0aa42f5c9d5 100644 (file)
@@ -2518,9 +2518,11 @@ u32 __tcp_select_window(struct sock *sk)
        int full_space = min_t(int, tp->window_clamp, allowed_space);
        int window;
 
-       if (mss > full_space)
+       if (unlikely(mss > full_space)) {
                mss = full_space;
-
+               if (mss <= 0)
+                       return 0;
+       }
        if (free_space < (full_space >> 1)) {
                icsk->icsk_ack.quick = 0;
 
index 2c0df09e90365ad38b5362f77c6e33a24fc062f0..b6a94ff0bbd0d5f42c78b7bcd6ea9fbe5ac9a595 100644 (file)
@@ -1344,7 +1344,7 @@ emsgsize:
         */
        if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
            headersize == sizeof(struct ipv6hdr) &&
-           length < mtu - headersize &&
+           length <= mtu - headersize &&
            !(flags & MSG_MORE) &&
            rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
                csummode = CHECKSUM_PARTIAL;
index ff8ee06491c335d209e86bb15f2526ab1915df3b..75fac933c209a0f430279dea10b5dd2426a7ed31 100644 (file)
@@ -441,7 +441,7 @@ __u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
                                if (i + sizeof(*tel) > optlen)
                                        break;
 
-                               tel = (struct ipv6_tlv_tnl_enc_lim *) skb->data + off + i;
+                               tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
                                /* return index of option if found and valid */
                                if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
                                    tel->length == 1)
index 970db7a41684aa2a494b97663f91ca932308de05..5752789acc135250c312199c2d6e5e15d05fdea0 100644 (file)
@@ -568,9 +568,9 @@ static int fl_set_key(struct net *net, struct nlattr **tb,
                               &mask->icmp.type,
                               TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
                               sizeof(key->icmp.type));
-               fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
+               fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
                               &mask->icmp.code,
-                              TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
+                              TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
                               sizeof(key->icmp.code));
        }
 
index f935429bd5ef1fcbe6a4272876b76e2ebb574c4b..b12bc2abea931a7defd1e23eb86a20fe09e76388 100644 (file)
 #include <net/sch_generic.h>
 #include <net/pkt_cls.h>
 
-struct cls_mall_filter {
+struct cls_mall_head {
        struct tcf_exts exts;
        struct tcf_result res;
        u32 handle;
-       struct rcu_head rcu;
        u32 flags;
-};
-
-struct cls_mall_head {
-       struct cls_mall_filter *filter;
        struct rcu_head rcu;
 };
 
@@ -33,38 +28,29 @@ static int mall_classify(struct sk_buff *skb, const struct tcf_proto *tp,
                         struct tcf_result *res)
 {
        struct cls_mall_head *head = rcu_dereference_bh(tp->root);
-       struct cls_mall_filter *f = head->filter;
 
-       if (tc_skip_sw(f->flags))
+       if (tc_skip_sw(head->flags))
                return -1;
 
-       return tcf_exts_exec(skb, &f->exts, res);
+       return tcf_exts_exec(skb, &head->exts, res);
 }
 
 static int mall_init(struct tcf_proto *tp)
 {
-       struct cls_mall_head *head;
-
-       head = kzalloc(sizeof(*head), GFP_KERNEL);
-       if (!head)
-               return -ENOBUFS;
-
-       rcu_assign_pointer(tp->root, head);
-
        return 0;
 }
 
-static void mall_destroy_filter(struct rcu_head *head)
+static void mall_destroy_rcu(struct rcu_head *rcu)
 {
-       struct cls_mall_filter *f = container_of(head, struct cls_mall_filter, rcu);
+       struct cls_mall_head *head = container_of(rcu, struct cls_mall_head,
+                                                 rcu);
 
-       tcf_exts_destroy(&f->exts);
-
-       kfree(f);
+       tcf_exts_destroy(&head->exts);
+       kfree(head);
 }
 
 static int mall_replace_hw_filter(struct tcf_proto *tp,
-                                 struct cls_mall_filter *f,
+                                 struct cls_mall_head *head,
                                  unsigned long cookie)
 {
        struct net_device *dev = tp->q->dev_queue->dev;
@@ -74,7 +60,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
        offload.type = TC_SETUP_MATCHALL;
        offload.cls_mall = &mall_offload;
        offload.cls_mall->command = TC_CLSMATCHALL_REPLACE;
-       offload.cls_mall->exts = &f->exts;
+       offload.cls_mall->exts = &head->exts;
        offload.cls_mall->cookie = cookie;
 
        return dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
@@ -82,7 +68,7 @@ static int mall_replace_hw_filter(struct tcf_proto *tp,
 }
 
 static void mall_destroy_hw_filter(struct tcf_proto *tp,
-                                  struct cls_mall_filter *f,
+                                  struct cls_mall_head *head,
                                   unsigned long cookie)
 {
        struct net_device *dev = tp->q->dev_queue->dev;
@@ -103,29 +89,20 @@ static bool mall_destroy(struct tcf_proto *tp, bool force)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
        struct net_device *dev = tp->q->dev_queue->dev;
-       struct cls_mall_filter *f = head->filter;
 
-       if (!force && f)
-               return false;
+       if (!head)
+               return true;
 
-       if (f) {
-               if (tc_should_offload(dev, tp, f->flags))
-                       mall_destroy_hw_filter(tp, f, (unsigned long) f);
+       if (tc_should_offload(dev, tp, head->flags))
+               mall_destroy_hw_filter(tp, head, (unsigned long) head);
 
-               call_rcu(&f->rcu, mall_destroy_filter);
-       }
-       kfree_rcu(head, rcu);
+       call_rcu(&head->rcu, mall_destroy_rcu);
        return true;
 }
 
 static unsigned long mall_get(struct tcf_proto *tp, u32 handle)
 {
-       struct cls_mall_head *head = rtnl_dereference(tp->root);
-       struct cls_mall_filter *f = head->filter;
-
-       if (f && f->handle == handle)
-               return (unsigned long) f;
-       return 0;
+       return 0UL;
 }
 
 static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
@@ -134,7 +111,7 @@ static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
 };
 
 static int mall_set_parms(struct net *net, struct tcf_proto *tp,
-                         struct cls_mall_filter *f,
+                         struct cls_mall_head *head,
                          unsigned long base, struct nlattr **tb,
                          struct nlattr *est, bool ovr)
 {
@@ -147,11 +124,11 @@ static int mall_set_parms(struct net *net, struct tcf_proto *tp,
                return err;
 
        if (tb[TCA_MATCHALL_CLASSID]) {
-               f->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
-               tcf_bind_filter(tp, &f->res, base);
+               head->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
+               tcf_bind_filter(tp, &head->res, base);
        }
 
-       tcf_exts_change(tp, &f->exts, &e);
+       tcf_exts_change(tp, &head->exts, &e);
 
        return 0;
 }
@@ -162,21 +139,17 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
                       unsigned long *arg, bool ovr)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
-       struct cls_mall_filter *fold = (struct cls_mall_filter *) *arg;
        struct net_device *dev = tp->q->dev_queue->dev;
-       struct cls_mall_filter *f;
        struct nlattr *tb[TCA_MATCHALL_MAX + 1];
+       struct cls_mall_head *new;
        u32 flags = 0;
        int err;
 
        if (!tca[TCA_OPTIONS])
                return -EINVAL;
 
-       if (head->filter)
-               return -EBUSY;
-
-       if (fold)
-               return -EINVAL;
+       if (head)
+               return -EEXIST;
 
        err = nla_parse_nested(tb, TCA_MATCHALL_MAX,
                               tca[TCA_OPTIONS], mall_policy);
@@ -189,23 +162,23 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
                        return -EINVAL;
        }
 
-       f = kzalloc(sizeof(*f), GFP_KERNEL);
-       if (!f)
+       new = kzalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
                return -ENOBUFS;
 
-       tcf_exts_init(&f->exts, TCA_MATCHALL_ACT, 0);
+       tcf_exts_init(&new->exts, TCA_MATCHALL_ACT, 0);
 
        if (!handle)
                handle = 1;
-       f->handle = handle;
-       f->flags = flags;
+       new->handle = handle;
+       new->flags = flags;
 
-       err = mall_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
+       err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr);
        if (err)
                goto errout;
 
        if (tc_should_offload(dev, tp, flags)) {
-               err = mall_replace_hw_filter(tp, f, (unsigned long) f);
+               err = mall_replace_hw_filter(tp, new, (unsigned long) new);
                if (err) {
                        if (tc_skip_sw(flags))
                                goto errout;
@@ -214,39 +187,29 @@ static int mall_change(struct net *net, struct sk_buff *in_skb,
                }
        }
 
-       *arg = (unsigned long) f;
-       rcu_assign_pointer(head->filter, f);
-
+       *arg = (unsigned long) head;
+       rcu_assign_pointer(tp->root, new);
+       if (head)
+               call_rcu(&head->rcu, mall_destroy_rcu);
        return 0;
 
 errout:
-       kfree(f);
+       kfree(new);
        return err;
 }
 
 static int mall_delete(struct tcf_proto *tp, unsigned long arg)
 {
-       struct cls_mall_head *head = rtnl_dereference(tp->root);
-       struct cls_mall_filter *f = (struct cls_mall_filter *) arg;
-       struct net_device *dev = tp->q->dev_queue->dev;
-
-       if (tc_should_offload(dev, tp, f->flags))
-               mall_destroy_hw_filter(tp, f, (unsigned long) f);
-
-       RCU_INIT_POINTER(head->filter, NULL);
-       tcf_unbind_filter(tp, &f->res);
-       call_rcu(&f->rcu, mall_destroy_filter);
-       return 0;
+       return -EOPNOTSUPP;
 }
 
 static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
 {
        struct cls_mall_head *head = rtnl_dereference(tp->root);
-       struct cls_mall_filter *f = head->filter;
 
        if (arg->count < arg->skip)
                goto skip;
-       if (arg->fn(tp, (unsigned long) f, arg) < 0)
+       if (arg->fn(tp, (unsigned long) head, arg) < 0)
                arg->stop = 1;
 skip:
        arg->count++;
@@ -255,28 +218,28 @@ skip:
 static int mall_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
                     struct sk_buff *skb, struct tcmsg *t)
 {
-       struct cls_mall_filter *f = (struct cls_mall_filter *) fh;
+       struct cls_mall_head *head = (struct cls_mall_head *) fh;
        struct nlattr *nest;
 
-       if (!f)
+       if (!head)
                return skb->len;
 
-       t->tcm_handle = f->handle;
+       t->tcm_handle = head->handle;
 
        nest = nla_nest_start(skb, TCA_OPTIONS);
        if (!nest)
                goto nla_put_failure;
 
-       if (f->res.classid &&
-           nla_put_u32(skb, TCA_MATCHALL_CLASSID, f->res.classid))
+       if (head->res.classid &&
+           nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid))
                goto nla_put_failure;
 
-       if (tcf_exts_dump(skb, &f->exts))
+       if (tcf_exts_dump(skb, &head->exts))
                goto nla_put_failure;
 
        nla_nest_end(skb, nest);
 
-       if (tcf_exts_dump_stats(skb, &f->exts) < 0)
+       if (tcf_exts_dump_stats(skb, &head->exts) < 0)
                goto nla_put_failure;
 
        return skb->len;
index dc6fb79a361f1ca3ab9869fc02ba05c1a533ad9b..25d9a9cf7b66b7f4e501d38d91f6a1908830972e 100644 (file)
@@ -260,7 +260,7 @@ static int gssx_dec_option_array(struct xdr_stream *xdr,
        if (!oa->data)
                return -ENOMEM;
 
-       creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
+       creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
        if (!creds) {
                kfree(oa->data);
                return -ENOMEM;
index eadcd4d359d91fc7823a75263c44c520e05f900b..d883116ebaa452d9c2f6c657de53121ebd9d50bd 100644 (file)
@@ -164,6 +164,7 @@ cmd_gensymtypes_c =                                                         \
     $(CPP) -D__GENKSYMS__ $(c_flags) $< |                                   \
     $(GENKSYMS) $(if $(1), -T $(2))                                         \
      $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))             \
+     $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS))                             \
      $(if $(KBUILD_PRESERVE),-p)                                            \
      -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
 
@@ -337,6 +338,7 @@ cmd_gensymtypes_S =                                                         \
     $(CPP) -D__GENKSYMS__ $(c_flags) -xc - |                                \
     $(GENKSYMS) $(if $(1), -T $(2))                                         \
      $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))             \
+     $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS))                             \
      $(if $(KBUILD_PRESERVE),-p)                                            \
      -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
 
index 06121ce524a76006072459d352d727b4aebdf203..c9235d8340f1e7ba33eacfaee94642c18f5fd211 100644 (file)
@@ -44,7 +44,7 @@ char *cur_filename, *source_file;
 int in_source_file;
 
 static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
-          flag_preserve, flag_warnings;
+          flag_preserve, flag_warnings, flag_rel_crcs;
 static const char *mod_prefix = "";
 
 static int errors;
@@ -693,7 +693,10 @@ void export_symbol(const char *name)
                        fputs(">\n", debugfile);
 
                /* Used as a linker script. */
-               printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
+               printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
+                      "SECTIONS { .rodata : ALIGN(4) { "
+                      "%s__crc_%s = .; LONG(0x%08lx); } }\n",
+                      mod_prefix, name, crc);
        }
 }
 
@@ -730,7 +733,7 @@ void error_with_pos(const char *fmt, ...)
 
 static void genksyms_usage(void)
 {
-       fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
+       fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
 #ifdef __GNU_LIBRARY__
              "  -s, --symbol-prefix   Select symbol prefix\n"
              "  -d, --debug           Increment the debug level (repeatable)\n"
@@ -742,6 +745,7 @@ static void genksyms_usage(void)
              "  -q, --quiet           Disable warnings (default)\n"
              "  -h, --help            Print this message\n"
              "  -V, --version         Print the release version\n"
+             "  -R, --relative-crc    Emit section relative symbol CRCs\n"
 #else                          /* __GNU_LIBRARY__ */
              "  -s                    Select symbol prefix\n"
              "  -d                    Increment the debug level (repeatable)\n"
@@ -753,6 +757,7 @@ static void genksyms_usage(void)
              "  -q                    Disable warnings (default)\n"
              "  -h                    Print this message\n"
              "  -V                    Print the release version\n"
+             "  -R                    Emit section relative symbol CRCs\n"
 #endif                         /* __GNU_LIBRARY__ */
              , stderr);
 }
@@ -774,13 +779,14 @@ int main(int argc, char **argv)
                {"preserve", 0, 0, 'p'},
                {"version", 0, 0, 'V'},
                {"help", 0, 0, 'h'},
+               {"relative-crc", 0, 0, 'R'},
                {0, 0, 0, 0}
        };
 
-       while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
+       while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
                                &long_opts[0], NULL)) != EOF)
 #else                          /* __GNU_LIBRARY__ */
-       while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
+       while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
 #endif                         /* __GNU_LIBRARY__ */
                switch (o) {
                case 's':
@@ -823,6 +829,9 @@ int main(int argc, char **argv)
                case 'h':
                        genksyms_usage();
                        return 0;
+               case 'R':
+                       flag_rel_crcs = 1;
+                       break;
                default:
                        genksyms_usage();
                        return 1;
index 299b92ca1ae092d82e9a0e3bffaec45988ebcc37..5d554419170b7d54ec82ddb1d31093d3eab0aa7d 100644 (file)
@@ -219,6 +219,10 @@ static int symbol_valid(struct sym_entry *s)
                "_SDA2_BASE_",          /* ppc */
                NULL };
 
+       static char *special_prefixes[] = {
+               "__crc_",               /* modversions */
+               NULL };
+
        static char *special_suffixes[] = {
                "_veneer",              /* arm */
                "_from_arm",            /* arm */
@@ -259,6 +263,14 @@ static int symbol_valid(struct sym_entry *s)
                if (strcmp(sym_name, special_symbols[i]) == 0)
                        return 0;
 
+       for (i = 0; special_prefixes[i]; i++) {
+               int l = strlen(special_prefixes[i]);
+
+               if (l <= strlen(sym_name) &&
+                   strncmp(sym_name, special_prefixes[i], l) == 0)
+                       return 0;
+       }
+
        for (i = 0; special_suffixes[i]; i++) {
                int l = strlen(sym_name) - strlen(special_suffixes[i]);
 
index 29c89a6bad3d3ac34e539189e83769f1c63ddab3..4dedd0d3d3a7fda58af2bc6150b9f6b6195d2cac 100644 (file)
@@ -621,6 +621,16 @@ static void handle_modversions(struct module *mod, struct elf_info *info,
        if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
                is_crc = true;
                crc = (unsigned int) sym->st_value;
+               if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
+                       unsigned int *crcp;
+
+                       /* symbol points to the CRC in the ELF object */
+                       crcp = (void *)info->hdr + sym->st_value +
+                              info->sechdrs[sym->st_shndx].sh_offset -
+                              (info->hdr->e_type != ET_REL ?
+                               info->sechdrs[sym->st_shndx].sh_addr : 0);
+                       crc = *crcp;
+               }
                sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
                                export);
        }
index 5a240e050ae669965a19a79ed1c2d1fa7b916ffd..ee2e69a9ecd14ecd9fef1107c7a803f0b1a836de 100644 (file)
@@ -108,6 +108,8 @@ source "sound/parisc/Kconfig"
 
 source "sound/soc/Kconfig"
 
+source "sound/x86/Kconfig"
+
 endif # SND
 
 menuconfig SOUND_PRIME
index c41bdf5fdf24d14c7bae790aebf4bdb81f104f4c..6de45d2c32f759b752e5ec03384915af596bcad4 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_SOUND) += soundcore.o
 obj-$(CONFIG_SOUND_PRIME) += oss/
 obj-$(CONFIG_DMASOUND) += oss/
 obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \
-       firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/
+       firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/
 obj-$(CONFIG_SND_AOA) += aoa/
 
 # This one must be compilable even if sound is configured out
index 2096bb0835c8a85e557fa40f0c15212018ada5c6..8da9cb245d01509d3c84429743d43ffa15e321d9 100644 (file)
@@ -1749,7 +1749,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
  * Sets the rawmidi operators for the given stream direction.
  */
 void snd_rawmidi_set_ops(struct snd_rawmidi *rmidi, int stream,
-                        struct snd_rawmidi_ops *ops)
+                        const struct snd_rawmidi_ops *ops)
 {
        struct snd_rawmidi_substream *substream;
        
index c850345c43b53dd5616b155f34f741d0ca30701c..dfa5156f35856324d86f05315edfb2ef9cf4e74e 100644 (file)
@@ -419,7 +419,6 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
 {
        unsigned long flags;
        struct snd_seq_event_cell *ptr;
-       int max_count = 5 * HZ;
 
        if (snd_BUG_ON(!pool))
                return -EINVAL;
@@ -432,14 +431,8 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
        if (waitqueue_active(&pool->output_sleep))
                wake_up(&pool->output_sleep);
 
-       while (atomic_read(&pool->counter) > 0) {
-               if (max_count == 0) {
-                       pr_warn("ALSA: snd_seq_pool_done timeout: %d cells remain\n", atomic_read(&pool->counter));
-                       break;
-               }
+       while (atomic_read(&pool->counter) > 0)
                schedule_timeout_uninterruptible(1);
-               max_count--;
-       }
        
        /* release all resources */
        spin_lock_irqsave(&pool->lock, flags);
index 0bec02e89d5118b3dffe1e22e88e423baa037491..450c5187eecb6bb083736d2d2a1aad43b98c7c3f 100644 (file)
@@ -181,6 +181,8 @@ void __exit snd_seq_queues_delete(void)
        }
 }
 
+static void queue_use(struct snd_seq_queue *queue, int client, int use);
+
 /* allocate a new queue -
  * return queue index value or negative value for error
  */
@@ -192,11 +194,11 @@ int snd_seq_queue_alloc(int client, int locked, unsigned int info_flags)
        if (q == NULL)
                return -ENOMEM;
        q->info_flags = info_flags;
+       queue_use(q, client, 1);
        if (queue_list_add(q) < 0) {
                queue_delete(q);
                return -ENOMEM;
        }
-       snd_seq_queue_use(q->queue, client, 1); /* use this queue */
        return q->queue;
 }
 
@@ -502,19 +504,9 @@ int snd_seq_queue_timer_set_tempo(int queueid, int client,
        return result;
 }
 
-
-/* use or unuse this queue -
- * if it is the first client, starts the timer.
- * if it is not longer used by any clients, stop the timer.
- */
-int snd_seq_queue_use(int queueid, int client, int use)
+/* use or unuse this queue */
+static void queue_use(struct snd_seq_queue *queue, int client, int use)
 {
-       struct snd_seq_queue *queue;
-
-       queue = queueptr(queueid);
-       if (queue == NULL)
-               return -EINVAL;
-       mutex_lock(&queue->timer_mutex);
        if (use) {
                if (!test_and_set_bit(client, queue->clients_bitmap))
                        queue->clients++;
@@ -529,6 +521,21 @@ int snd_seq_queue_use(int queueid, int client, int use)
        } else {
                snd_seq_timer_close(queue);
        }
+}
+
+/* use or unuse this queue -
+ * if it is the first client, starts the timer.
+ * if it is not longer used by any clients, stop the timer.
+ */
+int snd_seq_queue_use(int queueid, int client, int use)
+{
+       struct snd_seq_queue *queue;
+
+       queue = queueptr(queueid);
+       if (queue == NULL)
+               return -EINVAL;
+       mutex_lock(&queue->timer_mutex);
+       queue_use(queue, client, use);
        mutex_unlock(&queue->timer_mutex);
        queuefree(queue);
        return 0;
index c82ed3e70506db65adcbd48f6bdd55bd9628633d..52f31f1498f968df3a76776fc65bd551f691bfc5 100644 (file)
@@ -349,13 +349,13 @@ static int snd_virmidi_unuse(void *private_data,
  *  Register functions
  */
 
-static struct snd_rawmidi_ops snd_virmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_virmidi_input_ops = {
        .open = snd_virmidi_input_open,
        .close = snd_virmidi_input_close,
        .trigger = snd_virmidi_input_trigger,
 };
 
-static struct snd_rawmidi_ops snd_virmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_virmidi_output_ops = {
        .open = snd_virmidi_output_open,
        .close = snd_virmidi_output_close,
        .trigger = snd_virmidi_output_trigger,
index 776596b5ee0570975eb5df3761cf33cc8baf0f9c..3a7c317ae012ab18e1172d5cc795f64db7afb953 100644 (file)
@@ -481,14 +481,14 @@ snd_mpu401_uart_output_trigger(struct snd_rawmidi_substream *substream, int up)
 
  */
 
-static struct snd_rawmidi_ops snd_mpu401_uart_output =
+static const struct snd_rawmidi_ops snd_mpu401_uart_output =
 {
        .open =         snd_mpu401_uart_output_open,
        .close =        snd_mpu401_uart_output_close,
        .trigger =      snd_mpu401_uart_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_mpu401_uart_input =
+static const struct snd_rawmidi_ops snd_mpu401_uart_input =
 {
        .open =         snd_mpu401_uart_input_open,
        .close =        snd_mpu401_uart_input_close,
index 30e8a1d5bc87116db97e19cd1c1e718a69f19d39..00b31f92c504ddf7c7a9810b38d6b411a66a22a3 100644 (file)
@@ -600,13 +600,13 @@ static int snd_mtpav_get_ISA(struct mtpav *mcard)
 /*
  */
 
-static struct snd_rawmidi_ops snd_mtpav_output = {
+static const struct snd_rawmidi_ops snd_mtpav_output = {
        .open =         snd_mtpav_output_open,
        .close =        snd_mtpav_output_close,
        .trigger =      snd_mtpav_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_mtpav_input = {
+static const struct snd_rawmidi_ops snd_mtpav_input = {
        .open =         snd_mtpav_input_open,
        .close =        snd_mtpav_input_close,
        .trigger =      snd_mtpav_input_trigger,
index fd4d18df84d3666c62482c07da0a6cf694f61e47..f32e813422474320551b843f2cff708594930743 100644 (file)
@@ -749,13 +749,13 @@ static void snd_mts64_rawmidi_input_trigger(struct snd_rawmidi_substream *substr
        spin_unlock_irqrestore(&mts->lock, flags);
 }
 
-static struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_mts64_rawmidi_output_ops = {
        .open    = snd_mts64_rawmidi_open,
        .close   = snd_mts64_rawmidi_close,
        .trigger = snd_mts64_rawmidi_output_trigger
 };
 
-static struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_mts64_rawmidi_input_ops = {
        .open    = snd_mts64_rawmidi_open,
        .close   = snd_mts64_rawmidi_close,
        .trigger = snd_mts64_rawmidi_input_trigger
index 189e3e7028af4d8aa6637f57d122d3f7e23fa40b..ec8a94325ef628fe9a036ccaeccaa7ffc969d0c5 100644 (file)
@@ -546,13 +546,13 @@ static void snd_portman_midi_output_trigger(struct snd_rawmidi_substream *substr
        spin_unlock_irqrestore(&pm->reg_lock, flags);
 }
 
-static struct snd_rawmidi_ops snd_portman_midi_output = {
+static const struct snd_rawmidi_ops snd_portman_midi_output = {
        .open =         snd_portman_midi_open,
        .close =        snd_portman_midi_close,
        .trigger =      snd_portman_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_portman_midi_input = {
+static const struct snd_rawmidi_ops snd_portman_midi_input = {
        .open =         snd_portman_midi_open,
        .close =        snd_portman_midi_close,
        .trigger =      snd_portman_midi_input_trigger,
index 1927b89e1d1f6b2e302da1e4fc7337850906f689..60d51ac4ccfebded6c55e47812fdd16c67ae4359 100644 (file)
@@ -752,14 +752,14 @@ static void snd_uart16550_output_trigger(struct snd_rawmidi_substream *substream
                snd_uart16550_output_write(substream);
 }
 
-static struct snd_rawmidi_ops snd_uart16550_output =
+static const struct snd_rawmidi_ops snd_uart16550_output =
 {
        .open =         snd_uart16550_output_open,
        .close =        snd_uart16550_output_close,
        .trigger =      snd_uart16550_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_uart16550_input =
+static const struct snd_rawmidi_ops snd_uart16550_input =
 {
        .open =         snd_uart16550_input_open,
        .close =        snd_uart16550_input_close,
index 11467272089e45632935912c4e2b94f8cb604978..ea7b377f03787cdb3ba5b21266b5df57b5b41340 100644 (file)
@@ -1015,7 +1015,7 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
        int size, space, count;
        struct snd_pcm_runtime *runtime = subs->runtime;
 
-       if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
+       if (!pipe->running || (chip->chip_status & VX_STAT_IS_STALE))
                return;
 
        size = runtime->buffer_size - snd_pcm_capture_avail(runtime);
@@ -1048,8 +1048,10 @@ static void vx_pcm_capture_update(struct vx_core *chip, struct snd_pcm_substream
                /* ok, let's accelerate! */
                int align = pipe->align * 3;
                space = (count / align) * align;
-               vx_pseudo_dma_read(chip, runtime, pipe, space);
-               count -= space;
+               if (space > 0) {
+                       vx_pseudo_dma_read(chip, runtime, pipe, space);
+                       count -= space;
+               }
        }
        /* read the rest of bytes */
        while (count > 0) {
index ab894ed1ff6717a8acde6581fef9842dbb8d5c35..9f00696c4e4a1dc1b1ec8204ca680871c3341ce3 100644 (file)
@@ -34,6 +34,7 @@ config SND_OXFW
           * LaCie Firewire Speakers
           * Behringer F-Control Audio 202
           * Mackie(Loud) Onyx-i series (former models)
+          * Mackie(Loud) Onyx 1640i (former model)
           * Mackie(Loud) Onyx Satellite
           * Mackie(Loud) Tapco Link.Firewire
           * Mackie(Loud) d.2 pro/d.4 pro
index ce731f4d8b4f58fc1137a67fc75744e201a5658b..2b367c21b80c36e25ea105c8098ce0a9f38da496 100644 (file)
@@ -172,16 +172,15 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
 #define hwdep_compat_ioctl NULL
 #endif
 
-static const struct snd_hwdep_ops hwdep_ops = {
-       .read           = hwdep_read,
-       .release        = hwdep_release,
-       .poll           = hwdep_poll,
-       .ioctl          = hwdep_ioctl,
-       .ioctl_compat   = hwdep_compat_ioctl,
-};
-
 int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
 {
+       static const struct snd_hwdep_ops ops = {
+               .read           = hwdep_read,
+               .release        = hwdep_release,
+               .poll           = hwdep_poll,
+               .ioctl          = hwdep_ioctl,
+               .ioctl_compat   = hwdep_compat_ioctl,
+       };
        struct snd_hwdep *hwdep;
        int err;
 
@@ -190,7 +189,7 @@ int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
                goto end;
        strcpy(hwdep->name, "BeBoB");
        hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB;
-       hwdep->ops = hwdep_ops;
+       hwdep->ops = ops;
        hwdep->private_data = bebob;
        hwdep->exclusive = true;
 end:
index 868eb0decbec00a6c3005417b87b617f342348b3..3befa3eca6ef8068c4b27ede8257d293d259332f 100644 (file)
@@ -106,18 +106,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_unlock_irqrestore(&bebob->lock, flags);
 }
 
-static struct snd_rawmidi_ops midi_capture_ops = {
-       .open           = midi_capture_open,
-       .close          = midi_capture_close,
-       .trigger        = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
-       .open           = midi_playback_open,
-       .close          = midi_playback_close,
-       .trigger        = midi_playback_trigger,
-};
-
 static void set_midi_substream_names(struct snd_bebob *bebob,
                                     struct snd_rawmidi_str *str)
 {
@@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_bebob *bebob,
 
 int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
 {
+       static const struct snd_rawmidi_ops capture_ops = {
+               .open           = midi_capture_open,
+               .close          = midi_capture_close,
+               .trigger        = midi_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops playback_ops = {
+               .open           = midi_playback_open,
+               .close          = midi_playback_close,
+               .trigger        = midi_playback_trigger,
+       };
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *str;
        int err;
@@ -151,7 +149,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 
                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
-                                   &midi_capture_ops);
+                                   &capture_ops);
 
                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 
@@ -162,7 +160,7 @@ int snd_bebob_create_midi_devices(struct snd_bebob *bebob)
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 
                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
-                                   &midi_playback_ops);
+                                   &playback_ops);
 
                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 
index 5d7b9343fa85683268b6f6d6bfdfdeabe58e39cf..9e27eb8e1dd49df4e54241ee0dd64acd6cae5930 100644 (file)
@@ -359,32 +359,31 @@ pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
        return amdtp_stream_pcm_pointer(&bebob->rx_stream);
 }
 
-static const struct snd_pcm_ops pcm_capture_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_capture_hw_params,
-       .hw_free        = pcm_capture_hw_free,
-       .prepare        = pcm_capture_prepare,
-       .trigger        = pcm_capture_trigger,
-       .pointer        = pcm_capture_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-};
-static const struct snd_pcm_ops pcm_playback_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_playback_hw_params,
-       .hw_free        = pcm_playback_hw_free,
-       .prepare        = pcm_playback_prepare,
-       .trigger        = pcm_playback_trigger,
-       .pointer        = pcm_playback_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-       .mmap           = snd_pcm_lib_mmap_vmalloc,
-};
-
 int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
 {
+       static const struct snd_pcm_ops capture_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_capture_hw_params,
+               .hw_free        = pcm_capture_hw_free,
+               .prepare        = pcm_capture_prepare,
+               .trigger        = pcm_capture_trigger,
+               .pointer        = pcm_capture_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+       };
+       static const struct snd_pcm_ops playback_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_playback_hw_params,
+               .hw_free        = pcm_playback_hw_free,
+               .prepare        = pcm_playback_prepare,
+               .trigger        = pcm_playback_trigger,
+               .pointer        = pcm_playback_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+               .mmap           = snd_pcm_lib_mmap_vmalloc,
+       };
        struct snd_pcm *pcm;
        int err;
 
@@ -395,8 +394,8 @@ int snd_bebob_create_pcm_devices(struct snd_bebob *bebob)
        pcm->private_data = bebob;
        snprintf(pcm->name, sizeof(pcm->name),
                 "%s PCM", bebob->card->shortname);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 end:
        return err;
 }
index 27b044f84c816f5b4f15efa9782b7c4fbd1a217d..47f2c0a6f5d9b3b566fdc95757145acadaccec16 100644 (file)
 
 /*
  * The speed at which the packets are sent, SCODE_100-_400; read/write.
+ * SCODE_800 is only available in Dice III.
  */
 #define TX_SPEED                       0x014
 
index a040617505a75df7024508deb1a2909ee9a9e8e9..8ff6da3c51f72c1a3b6d0b0a671eabe43018e5d3 100644 (file)
@@ -78,18 +78,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_unlock_irqrestore(&dice->lock, flags);
 }
 
-static struct snd_rawmidi_ops capture_ops = {
-       .open           = midi_open,
-       .close          = midi_close,
-       .trigger        = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops playback_ops = {
-       .open           = midi_open,
-       .close          = midi_close,
-       .trigger        = midi_playback_trigger,
-};
-
 static void set_midi_substream_names(struct snd_dice *dice,
                                     struct snd_rawmidi_str *str)
 {
@@ -103,6 +91,16 @@ static void set_midi_substream_names(struct snd_dice *dice,
 
 int snd_dice_create_midi(struct snd_dice *dice)
 {
+       static const struct snd_rawmidi_ops capture_ops = {
+               .open           = midi_open,
+               .close          = midi_close,
+               .trigger        = midi_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops playback_ops = {
+               .open           = midi_open,
+               .close          = midi_close,
+               .trigger        = midi_playback_trigger,
+       };
        __be32 reg;
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *str;
index ec4db3a514fce3c4f16c2b8c38a71ad2e9a77d4e..8573289c381ed7314c6e1a08d4b39191756941f9 100644 (file)
@@ -195,6 +195,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
        unsigned int i, pcm_chs, midi_ports;
        struct amdtp_stream *streams;
        struct fw_iso_resources *resources;
+       struct fw_device *fw_dev = fw_parent_device(dice->unit);
        int err = 0;
 
        if (dir == AMDTP_IN_STREAM) {
@@ -237,8 +238,17 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir,
                if (err < 0)
                        return err;
 
+               if (dir == AMDTP_IN_STREAM) {
+                       reg[0] = cpu_to_be32(fw_dev->max_speed);
+                       err = snd_dice_transaction_write_tx(dice,
+                                       params->size * i + TX_SPEED,
+                                       reg, sizeof(reg[0]));
+                       if (err < 0)
+                               return err;
+               }
+
                err = amdtp_stream_start(&streams[i], resources[i].channel,
-                               fw_parent_device(dice->unit)->max_speed);
+                                        fw_dev->max_speed);
                if (err < 0)
                        return err;
        }
index f188e4758fd295ecb9a3db341c1c6606d40d06c4..463c6b8e864d025bae08b931705c0fae2d71d952 100644 (file)
@@ -173,16 +173,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
 #define hwdep_compat_ioctl NULL
 #endif
 
-static const struct snd_hwdep_ops hwdep_ops = {
-       .read           = hwdep_read,
-       .release        = hwdep_release,
-       .poll           = hwdep_poll,
-       .ioctl          = hwdep_ioctl,
-       .ioctl_compat   = hwdep_compat_ioctl,
-};
-
 int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
 {
+       static const struct snd_hwdep_ops ops = {
+               .read           = hwdep_read,
+               .release        = hwdep_release,
+               .poll           = hwdep_poll,
+               .ioctl          = hwdep_ioctl,
+               .ioctl_compat   = hwdep_compat_ioctl,
+       };
        struct snd_hwdep *hwdep;
        int err;
 
@@ -192,7 +191,7 @@ int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
 
        strcpy(hwdep->name, "Digi00x");
        hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
-       hwdep->ops = hwdep_ops;
+       hwdep->ops = ops;
        hwdep->private_data = dg00x;
        hwdep->exclusive = true;
 
index 1a72a382b384beb5b8ab92c3f65c72920c4d510b..915d2a21223e683f1f0f5fb613e0d5a8c7fb886b 100644 (file)
@@ -76,18 +76,6 @@ static void midi_phys_playback_trigger(struct snd_rawmidi_substream *substream,
        spin_unlock_irqrestore(&dg00x->lock, flags);
 }
 
-static struct snd_rawmidi_ops midi_phys_capture_ops = {
-       .open           = midi_phys_open,
-       .close          = midi_phys_close,
-       .trigger        = midi_phys_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_phys_playback_ops = {
-       .open           = midi_phys_open,
-       .close          = midi_phys_close,
-       .trigger        = midi_phys_playback_trigger,
-};
-
 static int midi_ctl_open(struct snd_rawmidi_substream *substream)
 {
        /* Do nothing. */
@@ -139,18 +127,6 @@ static void midi_ctl_playback_trigger(struct snd_rawmidi_substream *substream,
        spin_unlock_irqrestore(&dg00x->lock, flags);
 }
 
-static struct snd_rawmidi_ops midi_ctl_capture_ops = {
-       .open           = midi_ctl_open,
-       .close          = midi_ctl_capture_close,
-       .trigger        = midi_ctl_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_ctl_playback_ops = {
-       .open           = midi_ctl_open,
-       .close          = midi_ctl_playback_close,
-       .trigger        = midi_ctl_playback_trigger,
-};
-
 static void set_midi_substream_names(struct snd_dg00x *dg00x,
                                     struct snd_rawmidi_str *str,
                                     bool is_ctl)
@@ -172,6 +148,26 @@ static void set_midi_substream_names(struct snd_dg00x *dg00x,
 
 int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
 {
+       static const struct snd_rawmidi_ops phys_capture_ops = {
+               .open           = midi_phys_open,
+               .close          = midi_phys_close,
+               .trigger        = midi_phys_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops phys_playback_ops = {
+               .open           = midi_phys_open,
+               .close          = midi_phys_close,
+               .trigger        = midi_phys_playback_trigger,
+       };
+       static const struct snd_rawmidi_ops ctl_capture_ops = {
+               .open           = midi_ctl_open,
+               .close          = midi_ctl_capture_close,
+               .trigger        = midi_ctl_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops ctl_playback_ops = {
+               .open           = midi_ctl_open,
+               .close          = midi_ctl_playback_close,
+               .trigger        = midi_ctl_playback_trigger,
+       };
        struct snd_rawmidi *rmidi[2];
        struct snd_rawmidi_str *str;
        unsigned int i;
@@ -187,9 +183,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
                 "%s MIDI", dg00x->card->shortname);
 
        snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_INPUT,
-                           &midi_phys_capture_ops);
+                           &phys_capture_ops);
        snd_rawmidi_set_ops(rmidi[0], SNDRV_RAWMIDI_STREAM_OUTPUT,
-                           &midi_phys_playback_ops);
+                           &phys_playback_ops);
 
        /* Add a pair of control midi ports. */
        err = snd_rawmidi_new(dg00x->card, dg00x->card->driver, 1,
@@ -201,9 +197,9 @@ int snd_dg00x_create_midi_devices(struct snd_dg00x *dg00x)
                 "%s control", dg00x->card->shortname);
 
        snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_INPUT,
-                           &midi_ctl_capture_ops);
+                           &ctl_capture_ops);
        snd_rawmidi_set_ops(rmidi[1], SNDRV_RAWMIDI_STREAM_OUTPUT,
-                           &midi_ctl_playback_ops);
+                           &ctl_playback_ops);
 
        for (i = 0; i < ARRAY_SIZE(rmidi); i++) {
                rmidi[i]->private_data = dg00x;
index 613f05872770807698a58ad64fb8de8018c43f6f..68d1c52db051f13629aee1a6d291f1061338b954 100644 (file)
@@ -329,33 +329,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
        return amdtp_stream_pcm_pointer(&dg00x->rx_stream);
 }
 
-static const struct snd_pcm_ops pcm_capture_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_capture_hw_params,
-       .hw_free        = pcm_capture_hw_free,
-       .prepare        = pcm_capture_prepare,
-       .trigger        = pcm_capture_trigger,
-       .pointer        = pcm_capture_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_playback_hw_params,
-       .hw_free        = pcm_playback_hw_free,
-       .prepare        = pcm_playback_prepare,
-       .trigger        = pcm_playback_trigger,
-       .pointer        = pcm_playback_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-       .mmap           = snd_pcm_lib_mmap_vmalloc,
-};
-
 int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
 {
+       static const struct snd_pcm_ops capture_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_capture_hw_params,
+               .hw_free        = pcm_capture_hw_free,
+               .prepare        = pcm_capture_prepare,
+               .trigger        = pcm_capture_trigger,
+               .pointer        = pcm_capture_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+       };
+       static const struct snd_pcm_ops playback_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_playback_hw_params,
+               .hw_free        = pcm_playback_hw_free,
+               .prepare        = pcm_playback_prepare,
+               .trigger        = pcm_playback_trigger,
+               .pointer        = pcm_playback_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+               .mmap           = snd_pcm_lib_mmap_vmalloc,
+       };
        struct snd_pcm *pcm;
        int err;
 
@@ -366,8 +364,8 @@ int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x)
        pcm->private_data = dg00x;
        snprintf(pcm->name, sizeof(pcm->name),
                 "%s PCM", dg00x->card->shortname);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 
        return 0;
 }
index 2e1d9a23920c0c3ebf4b6edda5019b672dab4e82..a3a3a16f5e08fccf9fd3b196c5d2a7cd33474756 100644 (file)
@@ -303,17 +303,16 @@ hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
 #define hwdep_compat_ioctl NULL
 #endif
 
-static const struct snd_hwdep_ops hwdep_ops = {
-       .read           = hwdep_read,
-       .write          = hwdep_write,
-       .release        = hwdep_release,
-       .poll           = hwdep_poll,
-       .ioctl          = hwdep_ioctl,
-       .ioctl_compat   = hwdep_compat_ioctl,
-};
-
 int snd_efw_create_hwdep_device(struct snd_efw *efw)
 {
+       static const struct snd_hwdep_ops ops = {
+               .read           = hwdep_read,
+               .write          = hwdep_write,
+               .release        = hwdep_release,
+               .poll           = hwdep_poll,
+               .ioctl          = hwdep_ioctl,
+               .ioctl_compat   = hwdep_compat_ioctl,
+       };
        struct snd_hwdep *hwdep;
        int err;
 
@@ -322,7 +321,7 @@ int snd_efw_create_hwdep_device(struct snd_efw *efw)
                goto end;
        strcpy(hwdep->name, "Fireworks");
        hwdep->iface = SNDRV_HWDEP_IFACE_FW_FIREWORKS;
-       hwdep->ops = hwdep_ops;
+       hwdep->ops = ops;
        hwdep->private_data = efw;
        hwdep->exclusive = true;
 end:
index 3e8c4cf9fe1e0d5ad208e24210b0c89adffb7f13..f5da2cd4ce4219ab7a78519600cdc6dca168f0ff 100644 (file)
@@ -107,18 +107,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_unlock_irqrestore(&efw->lock, flags);
 }
 
-static struct snd_rawmidi_ops midi_capture_ops = {
-       .open           = midi_capture_open,
-       .close          = midi_capture_close,
-       .trigger        = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
-       .open           = midi_playback_open,
-       .close          = midi_playback_close,
-       .trigger        = midi_playback_trigger,
-};
-
 static void set_midi_substream_names(struct snd_efw *efw,
                                     struct snd_rawmidi_str *str)
 {
@@ -132,6 +120,16 @@ static void set_midi_substream_names(struct snd_efw *efw,
 
 int snd_efw_create_midi_devices(struct snd_efw *efw)
 {
+       static const struct snd_rawmidi_ops capture_ops = {
+               .open           = midi_capture_open,
+               .close          = midi_capture_close,
+               .trigger        = midi_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops playback_ops = {
+               .open           = midi_playback_open,
+               .close          = midi_playback_close,
+               .trigger        = midi_playback_trigger,
+       };
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *str;
        int err;
@@ -151,7 +149,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw)
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 
                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
-                                   &midi_capture_ops);
+                                   &capture_ops);
 
                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 
@@ -162,7 +160,7 @@ int snd_efw_create_midi_devices(struct snd_efw *efw)
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 
                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
-                                   &midi_playback_ops);
+                                   &playback_ops);
 
                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 
index f4fbf75ed198170953cbb512f0eea424085f2753..9171702f7d0bed08699aaa274110e9da230f4dbe 100644 (file)
@@ -383,33 +383,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
        return amdtp_stream_pcm_pointer(&efw->rx_stream);
 }
 
-static const struct snd_pcm_ops pcm_capture_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_capture_hw_params,
-       .hw_free        = pcm_capture_hw_free,
-       .prepare        = pcm_capture_prepare,
-       .trigger        = pcm_capture_trigger,
-       .pointer        = pcm_capture_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_playback_hw_params,
-       .hw_free        = pcm_playback_hw_free,
-       .prepare        = pcm_playback_prepare,
-       .trigger        = pcm_playback_trigger,
-       .pointer        = pcm_playback_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-       .mmap           = snd_pcm_lib_mmap_vmalloc,
-};
-
 int snd_efw_create_pcm_devices(struct snd_efw *efw)
 {
+       static const struct snd_pcm_ops capture_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_capture_hw_params,
+               .hw_free        = pcm_capture_hw_free,
+               .prepare        = pcm_capture_prepare,
+               .trigger        = pcm_capture_trigger,
+               .pointer        = pcm_capture_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+       };
+       static const struct snd_pcm_ops playback_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_playback_hw_params,
+               .hw_free        = pcm_playback_hw_free,
+               .prepare        = pcm_playback_prepare,
+               .trigger        = pcm_playback_trigger,
+               .pointer        = pcm_playback_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+               .mmap           = snd_pcm_lib_mmap_vmalloc,
+       };
        struct snd_pcm *pcm;
        int err;
 
@@ -419,8 +417,8 @@ int snd_efw_create_pcm_devices(struct snd_efw *efw)
 
        pcm->private_data = efw;
        snprintf(pcm->name, sizeof(pcm->name), "%s PCM", efw->card->shortname);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 end:
        return err;
 }
index 8665e1043d41fa380a8a94f213098cbca29d87ef..b7bbd77dfff179581120489a2d85a2127fd7773c 100644 (file)
@@ -116,18 +116,6 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_unlock_irqrestore(&oxfw->lock, flags);
 }
 
-static struct snd_rawmidi_ops midi_capture_ops = {
-       .open           = midi_capture_open,
-       .close          = midi_capture_close,
-       .trigger        = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
-       .open           = midi_playback_open,
-       .close          = midi_playback_close,
-       .trigger        = midi_playback_trigger,
-};
-
 static void set_midi_substream_names(struct snd_oxfw *oxfw,
                                     struct snd_rawmidi_str *str)
 {
@@ -142,6 +130,16 @@ static void set_midi_substream_names(struct snd_oxfw *oxfw,
 
 int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
 {
+       static const struct snd_rawmidi_ops capture_ops = {
+               .open           = midi_capture_open,
+               .close          = midi_capture_close,
+               .trigger        = midi_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops playback_ops = {
+               .open           = midi_playback_open,
+               .close          = midi_playback_close,
+               .trigger        = midi_playback_trigger,
+       };
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *str;
        int err;
@@ -164,7 +162,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
 
                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
-                                   &midi_capture_ops);
+                                   &capture_ops);
 
                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 
@@ -175,7 +173,7 @@ int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
                rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
 
                snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
-                                   &midi_playback_ops);
+                                   &playback_ops);
 
                str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 
index f897c9831077c5a49289c385b4aeed263a2aab2c..93209ebd91214ed514a43a42e729f31d68e21855 100644 (file)
@@ -297,7 +297,7 @@ static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up)
        }
 }
 
-static struct snd_rawmidi_ops midi_capture_ops = {
+static const struct snd_rawmidi_ops midi_capture_ops = {
        .open    = midi_capture_open,
        .close   = midi_capture_close,
        .trigger = midi_capture_trigger,
@@ -338,12 +338,6 @@ static void midi_playback_drain(struct snd_rawmidi_substream *stream)
        wait_event(scs->idle_wait, scs->output_idle);
 }
 
-static struct snd_rawmidi_ops midi_playback_ops = {
-       .open    = midi_playback_open,
-       .close   = midi_playback_close,
-       .trigger = midi_playback_trigger,
-       .drain   = midi_playback_drain,
-};
 static int register_address(struct snd_oxfw *oxfw)
 {
        struct fw_scs1x *scs = oxfw->spec;
@@ -369,6 +363,12 @@ void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw)
 
 int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw)
 {
+       static const struct snd_rawmidi_ops midi_playback_ops = {
+               .open    = midi_playback_open,
+               .close   = midi_playback_close,
+               .trigger = midi_playback_trigger,
+               .drain   = midi_playback_drain,
+       };
        struct snd_rawmidi *rmidi;
        struct fw_scs1x *scs;
        int err;
index e629b88f7d933481a70cb72b6c504856c9a57d98..74d7fb6efce6ca8258ece95a83c3460588a3e99e 100644 (file)
@@ -43,6 +43,7 @@ static bool detect_loud_models(struct fw_unit *unit)
        const char *const models[] = {
                "Onyxi",
                "Onyx-i",
+               "Onyx 1640i",
                "d.Pro",
                "Mackie Onyx Satellite",
                "Tapco LINK.firewire 4x6",
index 106406cbfaa3926f294ad0831180472a1e50523d..8c4437d0051d2ae3a17a0ff00ee64fcd431235a7 100644 (file)
@@ -163,16 +163,15 @@ static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
 #define hwdep_compat_ioctl NULL
 #endif
 
-static const struct snd_hwdep_ops hwdep_ops = {
-       .read           = hwdep_read,
-       .release        = hwdep_release,
-       .poll           = hwdep_poll,
-       .ioctl          = hwdep_ioctl,
-       .ioctl_compat   = hwdep_compat_ioctl,
-};
-
 int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
 {
+       static const struct snd_hwdep_ops ops = {
+               .read           = hwdep_read,
+               .release        = hwdep_release,
+               .poll           = hwdep_poll,
+               .ioctl          = hwdep_ioctl,
+               .ioctl_compat   = hwdep_compat_ioctl,
+       };
        struct snd_hwdep *hwdep;
        int err;
 
@@ -182,7 +181,7 @@ int snd_tscm_create_hwdep_device(struct snd_tscm *tscm)
 
        strcpy(hwdep->name, "Tascam");
        hwdep->iface = SNDRV_HWDEP_IFACE_FW_TASCAM;
-       hwdep->ops = hwdep_ops;
+       hwdep->ops = ops;
        hwdep->private_data = tscm;
        hwdep->exclusive = true;
 
index 41f842079d9ddff8b2ab8a41eb470d06c3c1cf2b..df4f95d65925ec36099123f09fb15c27f5ec1b17 100644 (file)
@@ -68,20 +68,18 @@ static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
        spin_unlock_irqrestore(&tscm->lock, flags);
 }
 
-static struct snd_rawmidi_ops midi_capture_ops = {
-       .open           = midi_capture_open,
-       .close          = midi_capture_close,
-       .trigger        = midi_capture_trigger,
-};
-
-static struct snd_rawmidi_ops midi_playback_ops = {
-       .open           = midi_playback_open,
-       .close          = midi_playback_close,
-       .trigger        = midi_playback_trigger,
-};
-
 int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
 {
+       static const struct snd_rawmidi_ops capture_ops = {
+               .open           = midi_capture_open,
+               .close          = midi_capture_close,
+               .trigger        = midi_capture_trigger,
+       };
+       static const struct snd_rawmidi_ops playback_ops = {
+               .open           = midi_playback_open,
+               .close          = midi_playback_close,
+               .trigger        = midi_playback_trigger,
+       };
        struct snd_rawmidi *rmidi;
        struct snd_rawmidi_str *stream;
        struct snd_rawmidi_substream *subs;
@@ -100,7 +98,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
 
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
-                           &midi_capture_ops);
+                           &capture_ops);
        stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
 
        /* Set port names for MIDI input. */
@@ -116,7 +114,7 @@ int snd_tscm_create_midi_devices(struct snd_tscm *tscm)
 
        rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
        snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
-                           &midi_playback_ops);
+                           &playback_ops);
        stream = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
 
        /* Set port names for MIDI ourput. */
index 79db1b651f5c59e2b2af1265eea68e13f14433fe..f5dd6ce6b6f15a039f8f58328a6cf20e20585361 100644 (file)
@@ -268,33 +268,31 @@ static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstrm)
        return amdtp_stream_pcm_pointer(&tscm->rx_stream);
 }
 
-static const struct snd_pcm_ops pcm_capture_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_capture_hw_params,
-       .hw_free        = pcm_capture_hw_free,
-       .prepare        = pcm_capture_prepare,
-       .trigger        = pcm_capture_trigger,
-       .pointer        = pcm_capture_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-};
-
-static const struct snd_pcm_ops pcm_playback_ops = {
-       .open           = pcm_open,
-       .close          = pcm_close,
-       .ioctl          = snd_pcm_lib_ioctl,
-       .hw_params      = pcm_playback_hw_params,
-       .hw_free        = pcm_playback_hw_free,
-       .prepare        = pcm_playback_prepare,
-       .trigger        = pcm_playback_trigger,
-       .pointer        = pcm_playback_pointer,
-       .page           = snd_pcm_lib_get_vmalloc_page,
-       .mmap           = snd_pcm_lib_mmap_vmalloc,
-};
-
 int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
 {
+       static const struct snd_pcm_ops capture_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_capture_hw_params,
+               .hw_free        = pcm_capture_hw_free,
+               .prepare        = pcm_capture_prepare,
+               .trigger        = pcm_capture_trigger,
+               .pointer        = pcm_capture_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+       };
+       static const struct snd_pcm_ops playback_ops = {
+               .open           = pcm_open,
+               .close          = pcm_close,
+               .ioctl          = snd_pcm_lib_ioctl,
+               .hw_params      = pcm_playback_hw_params,
+               .hw_free        = pcm_playback_hw_free,
+               .prepare        = pcm_playback_prepare,
+               .trigger        = pcm_playback_trigger,
+               .pointer        = pcm_playback_pointer,
+               .page           = snd_pcm_lib_get_vmalloc_page,
+               .mmap           = snd_pcm_lib_mmap_vmalloc,
+       };
        struct snd_pcm *pcm;
        int err;
 
@@ -305,8 +303,8 @@ int snd_tscm_create_pcm_devices(struct snd_tscm *tscm)
        pcm->private_data = tscm;
        snprintf(pcm->name, sizeof(pcm->name),
                 "%s PCM", tscm->card->shortname);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
 
        return 0;
 }
index 3992912743f5d3a33cc0a6aa5e027c262f3be55d..ac5f5687d1a31fd93ef7a3f518ac89d738ce71a7 100644 (file)
@@ -227,14 +227,14 @@ static void snd_gf1_uart_output_trigger(struct snd_rawmidi_substream *substream,
        spin_unlock_irqrestore(&gus->uart_cmd_lock, flags);
 }
 
-static struct snd_rawmidi_ops snd_gf1_uart_output =
+static const struct snd_rawmidi_ops snd_gf1_uart_output =
 {
        .open =         snd_gf1_uart_output_open,
        .close =        snd_gf1_uart_output_close,
        .trigger =      snd_gf1_uart_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_gf1_uart_input =
+static const struct snd_rawmidi_ops snd_gf1_uart_input =
 {
        .open =         snd_gf1_uart_input_open,
        .close =        snd_gf1_uart_input_close,
index ffc67fd80c23da47f770042b833b425cabbf5ff6..912b5a9ccbab5468f30e2059523b3ca942605bf5 100644 (file)
@@ -142,7 +142,7 @@ void snd_msndmidi_input_read(void *mpuv)
 }
 EXPORT_SYMBOL(snd_msndmidi_input_read);
 
-static struct snd_rawmidi_ops snd_msndmidi_input = {
+static const struct snd_rawmidi_ops snd_msndmidi_input = {
        .open =         snd_msndmidi_input_open,
        .close =        snd_msndmidi_input_close,
        .trigger =      snd_msndmidi_input_trigger,
index d551c50e549f92d8e954405b96294ee7a83f0ec3..bd672abb4854ecc686ac53ec667c174d1930872f 100644 (file)
@@ -247,14 +247,14 @@ static void snd_sb8dsp_midi_output_trigger(struct snd_rawmidi_substream *substre
                snd_sb8dsp_midi_output_write(substream);
 }
 
-static struct snd_rawmidi_ops snd_sb8dsp_midi_output =
+static const struct snd_rawmidi_ops snd_sb8dsp_midi_output =
 {
        .open =         snd_sb8dsp_midi_output_open,
        .close =        snd_sb8dsp_midi_output_close,
        .trigger =      snd_sb8dsp_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_sb8dsp_midi_input =
+static const struct snd_rawmidi_ops snd_sb8dsp_midi_input =
 {
        .open =         snd_sb8dsp_midi_input_open,
        .close =        snd_sb8dsp_midi_input_close,
index 8a80fc6a616b6ada647a70ccef9f80abd33352e1..2aa05f3aaa382c3f547942424f575ff375e2eb94 100644 (file)
@@ -559,14 +559,14 @@ snd_wavefront_midi_start (snd_wavefront_card_t *card)
        return 0;
 }
 
-struct snd_rawmidi_ops snd_wavefront_midi_output =
+const struct snd_rawmidi_ops snd_wavefront_midi_output =
 {
        .open =         snd_wavefront_midi_output_open,
        .close =        snd_wavefront_midi_output_close,
        .trigger =      snd_wavefront_midi_output_trigger,
 };
 
-struct snd_rawmidi_ops snd_wavefront_midi_input =
+const struct snd_rawmidi_ops snd_wavefront_midi_input =
 {
        .open =         snd_wavefront_midi_input_open,
        .close =        snd_wavefront_midi_input_close,
index ede449f0b50d7f04fc523d1becef71118b423849..00fc9241d2669604e0cd43fa6924758aa8996ed3 100644 (file)
@@ -219,6 +219,8 @@ static int hal2_gain_get(struct snd_kcontrol *kcontrol,
                l = (tmp >> H2I_C2_L_GAIN_SHIFT) & 15;
                r = (tmp >> H2I_C2_R_GAIN_SHIFT) & 15;
                break;
+       default:
+               return -EINVAL;
        }
        ucontrol->value.integer.value[0] = l;
        ucontrol->value.integer.value[1] = r;
@@ -256,6 +258,8 @@ static int hal2_gain_put(struct snd_kcontrol *kcontrol,
                new |= (r << H2I_C2_R_GAIN_SHIFT);
                hal2_i_write32(hal2, H2I_ADC_C2, new);
                break;
+       default:
+               return -EINVAL;
        }
        return old != new;
 }
index 6368e5c7d0ba93328fd83893731f59a314d01be0..f6156d8169d05b259c1fb35219efa7d6e3def735 100644 (file)
@@ -121,11 +121,6 @@ static bool deskpro_xl;
 static bool deskpro_m;
 static bool soundpro;
 
-static volatile signed char irq2dev[17] = {
-       -1, -1, -1, -1, -1, -1, -1, -1,
-       -1, -1, -1, -1, -1, -1, -1, -1, -1
-};
-
 #ifndef EXCLUDE_TIMERS
 static int timer_installed = -1;
 #endif
@@ -2060,7 +2055,7 @@ int ad1848_init (char *name, struct resource *ports, int irq, int dma_playback,
                else
                        devc->irq_ok = 1;       /* Couldn't test. assume it's OK */
        } else if (irq < 0)
-               irq2dev[-irq] = devc->dev_no = my_dev;
+               devc->dev_no = my_dev;
 
 #ifndef EXCLUDE_TIMERS
        if ((capabilities[devc->model].flags & CAP_F_TIMER) &&
index b91c7f6d19f9ee28005a91f3af210c3e60c6ea3d..4d4d385205eb716927040454f099f1885f6a4b0c 100644 (file)
@@ -255,14 +255,14 @@ static void ca_midi_output_trigger(struct snd_rawmidi_substream *substream, int
        }
 }
 
-static struct snd_rawmidi_ops ca_midi_output =
+static const struct snd_rawmidi_ops ca_midi_output =
 {
        .open =         ca_midi_output_open,
        .close =        ca_midi_output_close,
        .trigger =      ca_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops ca_midi_input =
+static const struct snd_rawmidi_ops ca_midi_input =
 {
        .open =         ca_midi_input_open,
        .close =        ca_midi_input_close,
index 8f0f5f24e40e77f477836e653c5fded247cbcf5f..fa7c51684dd23856fb7a8618e75c7e1f9d873002 100644 (file)
@@ -1767,14 +1767,14 @@ static void snd_cs4281_midi_output_trigger(struct snd_rawmidi_substream *substre
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static struct snd_rawmidi_ops snd_cs4281_midi_output =
+static const struct snd_rawmidi_ops snd_cs4281_midi_output =
 {
        .open =         snd_cs4281_midi_output_open,
        .close =        snd_cs4281_midi_output_close,
        .trigger =      snd_cs4281_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_cs4281_midi_input =
+static const struct snd_rawmidi_ops snd_cs4281_midi_input =
 {
        .open =         snd_cs4281_midi_input_open,
        .close =        snd_cs4281_midi_input_close,
index fde3cd48258cec61204217e7d03d160c8a8b3ff4..e4cf3187b4ddb888f8f5676581eaaf721b933f27 100644 (file)
 static void amp_voyetra(struct snd_cs46xx *chip, int change);
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-static struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops;
 #endif
 
-static struct snd_pcm_ops snd_cs46xx_playback_ops;
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
-static struct snd_pcm_ops snd_cs46xx_capture_ops;
-static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_ops;
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops;
+static const struct snd_pcm_ops snd_cs46xx_capture_ops;
+static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops;
 
 static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
                                            unsigned short reg,
@@ -1654,7 +1654,7 @@ static int snd_cs46xx_capture_close(struct snd_pcm_substream *substream)
 }
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
        .open =                 snd_cs46xx_playback_open_rear,
        .close =                snd_cs46xx_playback_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1665,7 +1665,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_rear_ops = {
        .pointer =              snd_cs46xx_playback_direct_pointer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
        .open =                 snd_cs46xx_playback_open_rear,
        .close =                snd_cs46xx_playback_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1677,7 +1677,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_rear_ops = {
        .ack =                  snd_cs46xx_playback_transfer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
        .open =                 snd_cs46xx_playback_open_clfe,
        .close =                snd_cs46xx_playback_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1688,7 +1688,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_clfe_ops = {
        .pointer =              snd_cs46xx_playback_direct_pointer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
        .open =                 snd_cs46xx_playback_open_clfe,
        .close =                snd_cs46xx_playback_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1700,7 +1700,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_clfe_ops = {
        .ack =                  snd_cs46xx_playback_transfer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
        .open =                 snd_cs46xx_playback_open_iec958,
        .close =                snd_cs46xx_playback_close_iec958,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1711,7 +1711,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_iec958_ops = {
        .pointer =              snd_cs46xx_playback_direct_pointer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
        .open =                 snd_cs46xx_playback_open_iec958,
        .close =                snd_cs46xx_playback_close_iec958,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1725,7 +1725,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_iec958_ops = {
 
 #endif
 
-static struct snd_pcm_ops snd_cs46xx_playback_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_ops = {
        .open =                 snd_cs46xx_playback_open,
        .close =                snd_cs46xx_playback_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1736,7 +1736,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_ops = {
        .pointer =              snd_cs46xx_playback_direct_pointer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
+static const struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
        .open =                 snd_cs46xx_playback_open,
        .close =                snd_cs46xx_playback_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1748,7 +1748,7 @@ static struct snd_pcm_ops snd_cs46xx_playback_indirect_ops = {
        .ack =                  snd_cs46xx_playback_transfer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_capture_ops = {
+static const struct snd_pcm_ops snd_cs46xx_capture_ops = {
        .open =                 snd_cs46xx_capture_open,
        .close =                snd_cs46xx_capture_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -1759,7 +1759,7 @@ static struct snd_pcm_ops snd_cs46xx_capture_ops = {
        .pointer =              snd_cs46xx_capture_direct_pointer,
 };
 
-static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
+static const struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = {
        .open =                 snd_cs46xx_capture_open,
        .close =                snd_cs46xx_capture_close,
        .ioctl =                snd_pcm_lib_ioctl,
@@ -2683,14 +2683,14 @@ static void snd_cs46xx_midi_output_trigger(struct snd_rawmidi_substream *substre
        spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
-static struct snd_rawmidi_ops snd_cs46xx_midi_output =
+static const struct snd_rawmidi_ops snd_cs46xx_midi_output =
 {
        .open =         snd_cs46xx_midi_output_open,
        .close =        snd_cs46xx_midi_output_close,
        .trigger =      snd_cs46xx_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_cs46xx_midi_input =
+static const struct snd_rawmidi_ops snd_cs46xx_midi_input =
 {
        .open =         snd_cs46xx_midi_input_open,
        .close =        snd_cs46xx_midi_input_close,
index 06ac5d8da3624c612212b1eb85e7b60c91ec3b30..82bd10b68a77826caeef5a0026c09a354a3808ec 100644 (file)
@@ -55,7 +55,7 @@ static void snd_cs5535audio_stop_hardware(struct cs5535audio *cs5535au)
 
 }
 
-static int snd_cs5535audio_suspend(struct device *dev)
+static int __maybe_unused snd_cs5535audio_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct cs5535audio *cs5535au = card->private_data;
@@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev)
        return 0;
 }
 
-static int snd_cs5535audio_resume(struct device *dev)
+static int __maybe_unused snd_cs5535audio_resume(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
        struct cs5535audio *cs5535au = card->private_data;
index a8fe58335ddc0659aa19113266fc657860618ac5..8c685ddb1a41b8c4f1e7964274ebb0d27e8b35f3 100644 (file)
@@ -288,13 +288,13 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
 
 
 
-static struct snd_rawmidi_ops snd_echo_midi_input = {
+static const struct snd_rawmidi_ops snd_echo_midi_input = {
        .open = snd_echo_midi_input_open,
        .close = snd_echo_midi_input_close,
        .trigger = snd_echo_midi_input_trigger,
 };
 
-static struct snd_rawmidi_ops snd_echo_midi_output = {
+static const struct snd_rawmidi_ops snd_echo_midi_output = {
        .open = snd_echo_midi_output_open,
        .close = snd_echo_midi_output_close,
        .trigger = snd_echo_midi_output_trigger,
index d2c7ea3a7610861a15730bb3a8b0c8764205fd5a..aa2cc27b849166be87c533efb4b66b15ce96fe31 100644 (file)
@@ -61,7 +61,7 @@ static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
 /*
  * set up operators
  */
-static struct snd_emux_operators emu10k1_ops = {
+static const struct snd_emux_operators emu10k1_ops = {
        .owner =        THIS_MODULE,
        .get_voice =    get_voice,
        .prepare =      start_voice,
index 921037ed8468f03a95f80372571f07e3e260893d..32842734ada61bfec55f12deead13e6ddd6cabfd 100644 (file)
@@ -1486,14 +1486,14 @@ static void snd_emu10k1x_midi_output_trigger(struct snd_rawmidi_substream *subst
 
  */
 
-static struct snd_rawmidi_ops snd_emu10k1x_midi_output =
+static const struct snd_rawmidi_ops snd_emu10k1x_midi_output =
 {
        .open =         snd_emu10k1x_midi_output_open,
        .close =        snd_emu10k1x_midi_output_close,
        .trigger =      snd_emu10k1x_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_emu10k1x_midi_input =
+static const struct snd_rawmidi_ops snd_emu10k1x_midi_input =
 {
        .open =         snd_emu10k1x_midi_input_open,
        .close =        snd_emu10k1x_midi_input_close,
index fdf2b0ada48977c9fd58b6e7794883f60a852146..b6650f5c1621906e713e45fac27e816833aef2b0 100644 (file)
@@ -308,14 +308,14 @@ static void snd_emu10k1_midi_output_trigger(struct snd_rawmidi_substream *substr
 
  */
 
-static struct snd_rawmidi_ops snd_emu10k1_midi_output =
+static const struct snd_rawmidi_ops snd_emu10k1_midi_output =
 {
        .open =         snd_emu10k1_midi_output_open,
        .close =        snd_emu10k1_midi_output_close,
        .trigger =      snd_emu10k1_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_emu10k1_midi_input =
+static const struct snd_rawmidi_ops snd_emu10k1_midi_input =
 {
        .open =         snd_emu10k1_midi_input_open,
        .close =        snd_emu10k1_midi_input_close,
index 51736c2b5a00734f5fa55f3b5f437f6e7b5be194..164adad916506cf1b492b45ef59452c3b0079462 100644 (file)
@@ -2317,14 +2317,14 @@ static void snd_ensoniq_midi_output_trigger(struct snd_rawmidi_substream *substr
        spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
 }
 
-static struct snd_rawmidi_ops snd_ensoniq_midi_output =
+static const struct snd_rawmidi_ops snd_ensoniq_midi_output =
 {
        .open =         snd_ensoniq_midi_output_open,
        .close =        snd_ensoniq_midi_output_close,
        .trigger =      snd_ensoniq_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_ensoniq_midi_input =
+static const struct snd_rawmidi_ops snd_ensoniq_midi_input =
 {
        .open =         snd_ensoniq_midi_input_open,
        .close =        snd_ensoniq_midi_input_close,
index 500878556578c2d7c153f33a6785a9482b1f037b..3715a5725613bd8b8bdbcafc79b380044cacb491 100644 (file)
@@ -861,6 +861,10 @@ static int azx_rirb_get_response(struct hdac_bus *bus, unsigned int addr,
                return -EIO;
        }
 
+       /* no fallback mechanism? */
+       if (!chip->fallback_to_single_cmd)
+               return -EIO;
+
        /* a fatal communication error; need either to reset or to fallback
         * to the single_cmd mode
         */
index a50e0532622a180fc7386d2331995df211145068..35a9ab2cac463072dc80911fda3519dbfc99bf3c 100644 (file)
@@ -150,6 +150,7 @@ struct azx {
        int bdl_pos_adj;
        int poll_count;
        unsigned int running:1;
+       unsigned int fallback_to_single_cmd:1;
        unsigned int single_cmd:1;
        unsigned int polling_mode:1;
        unsigned int msi:1;
index c64d986009a9ecf5233464d269a440a0edb6cf23..16108f0eb68848bf189f47f0101273c14443565b 100644 (file)
@@ -128,7 +128,7 @@ static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1};
 static int probe_only[SNDRV_CARDS];
 static int jackpoll_ms[SNDRV_CARDS];
-static bool single_cmd;
+static int single_cmd = -1;
 static int enable_msi = -1;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 static char *patch[SNDRV_CARDS];
@@ -157,7 +157,7 @@ module_param_array(probe_only, int, NULL, 0444);
 MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization.");
 module_param_array(jackpoll_ms, int, NULL, 0444);
 MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)");
-module_param(single_cmd, bool, 0444);
+module_param(single_cmd, bint, 0444);
 MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs "
                 "(for debugging only).");
 module_param(enable_msi, bint, 0444);
@@ -1596,7 +1596,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
 
        check_probe_mask(chip, dev);
 
-       chip->single_cmd = single_cmd;
+       if (single_cmd < 0) /* allow fallback to single_cmd at errors */
+               chip->fallback_to_single_cmd = 1;
+       else /* explicitly set to single_cmd or not */
+               chip->single_cmd = single_cmd;
+
        azx_check_snoop_available(chip);
 
        if (bdl_pos_adj[dev] < 0)
@@ -1774,6 +1778,14 @@ static int azx_first_init(struct azx *chip)
        chip->playback_index_offset = chip->capture_streams;
        chip->num_streams = chip->playback_streams + chip->capture_streams;
 
+       /* sanity check for the SDxCTL.STRM field overflow */
+       if (chip->num_streams > 15 &&
+           (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG) == 0) {
+               dev_warn(chip->card->dev, "number of I/O streams is %d, "
+                        "forcing separate stream tags", chip->num_streams);
+               chip->driver_caps |= AZX_DCAPS_SEPARATE_STREAM_TAG;
+       }
+
        /* initialize streams */
        err = azx_init_streams(chip);
        if (err < 0)
@@ -2155,7 +2167,20 @@ static void azx_remove(struct pci_dev *pci)
                /* cancel the pending probing work */
                chip = card->private_data;
                hda = container_of(chip, struct hda_intel, chip);
+               /* FIXME: below is an ugly workaround.
+                * Both device_release_driver() and driver_probe_device()
+                * take *both* the device's and its parent's lock before
+                * calling the remove() and probe() callbacks.  The codec
+                * probe takes the locks of both the codec itself and its
+                * parent, i.e. the PCI controller dev.  Meanwhile, when
+                * the PCI controller is unbound, it takes its lock, too
+                * ==> ouch, a deadlock!
+                * As a workaround, we unlock temporarily here the controller
+                * device during cancel_work_sync() call.
+                */
+               device_unlock(&pci->dev);
                cancel_work_sync(&hda->probe_work);
+               device_lock(&pci->dev);
 
                snd_card_free(card);
        }
@@ -2197,9 +2222,9 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Lewisburg */
        { PCI_DEVICE(0x8086, 0xa1f0),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        { PCI_DEVICE(0x8086, 0xa270),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        /* Lynx Point-LP */
        { PCI_DEVICE(0x8086, 0x9c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
index 11b9b2f17a2ef66b7555c0bbbde8d31f6ca2a070..9ec4dba8a793bf04294a61423b94d07fedf4f29f 100644 (file)
@@ -1482,6 +1482,9 @@ static int dspio_scp(struct hda_codec *codec,
                } else if (ret_size != reply_data_size) {
                        codec_dbg(codec, "RetLen and HdrLen .NE.\n");
                        return -EINVAL;
+               } else if (!reply) {
+                       codec_dbg(codec, "NULL reply\n");
+                       return -EINVAL;
                } else {
                        *reply_len = ret_size*sizeof(unsigned int);
                        memcpy(reply, scp_reply.data, *reply_len);
index cf9bc042fe966361588b8dc92b66e308fd50e657..3fc201c3b95a33380217950d91285c83d3d7fb8a 100644 (file)
@@ -3639,6 +3639,7 @@ HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",     patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",  patch_nvhdmi),
 HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",      patch_nvhdmi_2ch),
index 7d660ee1d5e84e6f7eaa42404232d9aad461b25c..73a00460b5c113a86af31dfb3f2c94d04f41b562 100644 (file)
@@ -337,6 +337,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
        case 0x10ec0288:
        case 0x10ec0295:
        case 0x10ec0298:
+       case 0x10ec0299:
                alc_update_coef_idx(codec, 0x10, 1<<9, 0);
                break;
        case 0x10ec0285:
@@ -379,6 +380,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec)
                break;
        case 0x10ec0899:
        case 0x10ec0900:
+       case 0x10ec1220:
                alc_update_coef_idx(codec, 0x7, 1<<1, 0);
                break;
        }
@@ -912,6 +914,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
        { 0x10ec0256, 0x1028, 0, "ALC3246" },
        { 0x10ec0225, 0x1028, 0, "ALC3253" },
        { 0x10ec0295, 0x1028, 0, "ALC3254" },
+       { 0x10ec0299, 0x1028, 0, "ALC3271" },
        { 0x10ec0670, 0x1025, 0, "ALC669X" },
        { 0x10ec0676, 0x1025, 0, "ALC679X" },
        { 0x10ec0282, 0x1043, 0, "ALC3229" },
@@ -2309,6 +2312,7 @@ static int patch_alc882(struct hda_codec *codec)
        case 0x10ec0882:
        case 0x10ec0885:
        case 0x10ec0900:
+       case 0x10ec1220:
                break;
        default:
                /* ALC883 and variants */
@@ -3717,6 +3721,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                alc_process_coef_fw(codec, coef0225);
                break;
        case 0x10ec0867:
@@ -3812,6 +3817,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
        case 0x10ec0867:
                alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
                /* fallthru */
+       case 0x10ec0221:
        case 0x10ec0662:
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
                snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
@@ -3824,6 +3830,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
                snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
                alc_process_coef_fw(codec, coef0225);
@@ -3882,6 +3889,7 @@ static void alc_headset_mode_default(struct hda_codec *codec)
        switch (codec->core.vendor_id) {
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                alc_process_coef_fw(codec, coef0225);
                break;
        case 0x10ec0255:
@@ -3997,6 +4005,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                alc_process_coef_fw(codec, coef0225);
                break;
        case 0x10ec0867:
@@ -4090,6 +4099,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec)
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                alc_process_coef_fw(codec, coef0225);
                break;
        }
@@ -4174,6 +4184,7 @@ static void alc_determine_headset_type(struct hda_codec *codec)
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                alc_process_coef_fw(codec, coef0225);
                msleep(800);
                val = alc_read_coef_idx(codec, 0x46);
@@ -4401,7 +4412,7 @@ static void alc_no_shutup(struct hda_codec *codec)
 static void alc_fixup_no_shutup(struct hda_codec *codec,
                                const struct hda_fixup *fix, int action)
 {
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+       if (action == HDA_FIXUP_ACT_PROBE) {
                struct alc_spec *spec = codec->spec;
                spec->shutup = alc_no_shutup;
        }
@@ -4857,6 +4868,8 @@ enum {
        ALC292_FIXUP_TPT460,
        ALC298_FIXUP_SPK_VOLUME,
        ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
+       ALC269_FIXUP_ATIV_BOOK_8,
+       ALC221_FIXUP_HP_MIC_NO_PRESENCE,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5529,6 +5542,22 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
        },
+       [ALC269_FIXUP_ATIV_BOOK_8] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_NO_SHUTUP
+       },
+       [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5639,6 +5668,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
        SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
+       SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5665,6 +5696,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
        SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
        SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
@@ -6065,6 +6097,12 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
        SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC298_STANDARD_PINS,
                {0x17, 0x90170150}),
+       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
+               {0x12, 0xb7a60140},
+               {0x13, 0xb7a60150},
+               {0x17, 0x90170110},
+               {0x1a, 0x03011020},
+               {0x21, 0x03211030}),
        {}
 };
 
@@ -6212,6 +6250,7 @@ static int patch_alc269(struct hda_codec *codec)
                break;
        case 0x10ec0225:
        case 0x10ec0295:
+       case 0x10ec0299:
                spec->codec_variant = ALC269_TYPE_ALC225;
                break;
        case 0x10ec0234:
@@ -7250,6 +7289,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
        HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
        HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
        HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
        HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
        HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
@@ -7281,6 +7321,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = {
        HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
        HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
        HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
        {} /* terminator */
 };
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
index 37b70f8e878f715968c7496e01eeb493f8a2b7a4..faa3d38bac0b7e51ab206440e8d17f4f6d751530 100644 (file)
@@ -166,6 +166,7 @@ enum {
        STAC_D965_VERBS,
        STAC_DELL_3ST,
        STAC_DELL_BIOS,
+       STAC_NEMO_DEFAULT,
        STAC_DELL_BIOS_AMIC,
        STAC_DELL_BIOS_SPDIF,
        STAC_927X_DELL_DMIC,
@@ -1360,6 +1361,27 @@ static const struct hda_pintbl oqo9200_pin_configs[] = {
        {}
 };
 
+/*
+ *  STAC 92HD700
+ *  18881000 Amigaone X1000
+ */
+static const struct hda_pintbl nemo_pin_configs[] = {
+       { 0x0a, 0x02214020 },   /* Front panel HP socket */
+       { 0x0b, 0x02a19080 },   /* Front Mic */
+       { 0x0c, 0x0181304e },   /* Line in */
+       { 0x0d, 0x01014010 },   /* Line out */
+       { 0x0e, 0x01a19040 },   /* Rear Mic */
+       { 0x0f, 0x01011012 },   /* Rear speakers */
+       { 0x10, 0x01016011 },   /* Center speaker */
+       { 0x11, 0x01012014 },   /* Side speakers (7.1) */
+       { 0x12, 0x103301f0 },   /* Motherboard CD line in connector */
+       { 0x13, 0x411111f0 },   /* Unused */
+       { 0x14, 0x411111f0 },   /* Unused */
+       { 0x21, 0x01442170 },   /* S/PDIF line out */
+       { 0x22, 0x411111f0 },   /* Unused */
+       { 0x23, 0x411111f0 },   /* Unused */
+       {}
+};
 
 static void stac9200_fixup_panasonic(struct hda_codec *codec,
                                     const struct hda_fixup *fix, int action)
@@ -3883,6 +3905,10 @@ static const struct hda_fixup stac927x_fixups[] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = d965_5st_no_fp_pin_configs,
        },
+       [STAC_NEMO_DEFAULT] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = nemo_pin_configs,
+       },
        [STAC_DELL_3ST] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = dell_3st_pin_configs,
@@ -3939,6 +3965,7 @@ static const struct hda_model_fixup stac927x_models[] = {
        { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
        { .id = STAC_DELL_3ST, .name = "dell-3stack" },
        { .id = STAC_DELL_BIOS, .name = "dell-bios" },
+       { .id = STAC_NEMO_DEFAULT, .name = "nemo-default" },
        { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
        { .id = STAC_927X_VOLKNOB, .name = "volknob" },
        {}
@@ -3977,6 +4004,8 @@ static const struct snd_pci_quirk stac927x_fixup_tbl[] = {
                           "Intel D965", STAC_D965_5ST),
        SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
                           "Intel D965", STAC_D965_5ST),
+       /* Nemo */
+       SND_PCI_QUIRK(0x1888, 0x1000, "AmigaOne X1000", STAC_NEMO_DEFAULT),
        /* volume-knob fixes */
        SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
        {} /* terminator */
@@ -5036,6 +5065,7 @@ static const struct hda_device_id snd_hda_id_sigmatel[] = {
        HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
        HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
        HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
        HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
        HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
        HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
index e5c52ed9b6747003993d93ff4f1e2f1a760ced3e..842744e7a139bc873ba3b7077a7dcd3ac40f3518 100644 (file)
@@ -367,7 +367,7 @@ static void vt1724_midi_output_drain(struct snd_rawmidi_substream *s)
        } while (time_after(timeout, jiffies));
 }
 
-static struct snd_rawmidi_ops vt1724_midi_output_ops = {
+static const struct snd_rawmidi_ops vt1724_midi_output_ops = {
        .open = vt1724_midi_output_open,
        .close = vt1724_midi_output_close,
        .trigger = vt1724_midi_output_trigger,
@@ -402,7 +402,7 @@ static void vt1724_midi_input_trigger(struct snd_rawmidi_substream *s, int up)
        spin_unlock_irqrestore(&ice->reg_lock, flags);
 }
 
-static struct snd_rawmidi_ops vt1724_midi_input_ops = {
+static const struct snd_rawmidi_ops vt1724_midi_input_ops = {
        .open = vt1724_midi_input_open,
        .close = vt1724_midi_input_close,
        .trigger = vt1724_midi_input_trigger,
index 0cc17e0ea34a4d19b3558ff18b2120b84e659490..4267438715402ce8e62bc10966f3fa6cab16d397 100644 (file)
@@ -86,7 +86,7 @@ struct mixart_mgr {
        u32 msg_fifo[MSG_FIFO_SIZE];
        int msg_fifo_readptr;
        int msg_fifo_writeptr;
-       atomic_t msg_processed;       /* number of messages to be processed in takslet */
+       atomic_t msg_processed;       /* number of messages to be processed in tasklet */
 
        struct mutex lock;              /* interrupt lock */
        struct mutex msg_lock;          /* mailbox lock */
index b94fc6357139e17c207107b18a3dadc6d177ce06..fc0face6cdc681c72836ea96e9e63b6d09ee174c 100644 (file)
@@ -1510,14 +1510,14 @@ static int snd_hdsp_midi_output_close(struct snd_rawmidi_substream *substream)
        return 0;
 }
 
-static struct snd_rawmidi_ops snd_hdsp_midi_output =
+static const struct snd_rawmidi_ops snd_hdsp_midi_output =
 {
        .open =         snd_hdsp_midi_output_open,
        .close =        snd_hdsp_midi_output_close,
        .trigger =      snd_hdsp_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_hdsp_midi_input =
+static const struct snd_rawmidi_ops snd_hdsp_midi_input =
 {
        .open =         snd_hdsp_midi_input_open,
        .close =        snd_hdsp_midi_input_close,
index 14bbf55c1ef9601d87611af3136cf91cf7fca51d..c48acdb0e1868223c164e1236149e13dab160174 100644 (file)
@@ -2043,14 +2043,14 @@ static int snd_hdspm_midi_output_close(struct snd_rawmidi_substream *substream)
        return 0;
 }
 
-static struct snd_rawmidi_ops snd_hdspm_midi_output =
+static const struct snd_rawmidi_ops snd_hdspm_midi_output =
 {
        .open =         snd_hdspm_midi_output_open,
        .close =        snd_hdspm_midi_output_close,
        .trigger =      snd_hdspm_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_hdspm_midi_input =
+static const struct snd_rawmidi_ops snd_hdspm_midi_input =
 {
        .open =         snd_hdspm_midi_input_open,
        .close =        snd_hdspm_midi_input_close,
index af83b3b380523e75c897695a292bfecbdb2734fb..8e457ea27f8918e13a5e949d7ee243503b2f294f 100644 (file)
@@ -269,12 +269,12 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
 
        /* Transfer using pseudo-dma.
         */
-       if (offset + count > pipe->buffer_bytes) {
+       if (offset + count >= pipe->buffer_bytes) {
                int length = pipe->buffer_bytes - offset;
                count -= length;
                length >>= 2; /* in 32bit words */
                /* Transfer using pseudo-dma. */
-               while (length-- > 0) {
+               for (; length > 0; length--) {
                        outl(cpu_to_le32(*addr), port);
                        addr++;
                }
@@ -284,7 +284,7 @@ static void vx2_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        pipe->hw_ptr += count;
        count >>= 2; /* in 32bit words */
        /* Transfer using pseudo-dma. */
-       while (count-- > 0) {
+       for (; count > 0; count--) {
                outl(cpu_to_le32(*addr), port);
                addr++;
        }
@@ -307,12 +307,12 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        vx2_setup_pseudo_dma(chip, 0);
        /* Transfer using pseudo-dma.
         */
-       if (offset + count > pipe->buffer_bytes) {
+       if (offset + count >= pipe->buffer_bytes) {
                int length = pipe->buffer_bytes - offset;
                count -= length;
                length >>= 2; /* in 32bit words */
                /* Transfer using pseudo-dma. */
-               while (length-- > 0)
+               for (; length > 0; length--)
                        *addr++ = le32_to_cpu(inl(port));
                addr = (u32 *)runtime->dma_area;
                pipe->hw_ptr = 0;
@@ -320,7 +320,7 @@ static void vx2_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        pipe->hw_ptr += count;
        count >>= 2; /* in 32bit words */
        /* Transfer using pseudo-dma. */
-       while (count-- > 0)
+       for (; count > 0; count--)
                *addr++ = le32_to_cpu(inl(port));
 
        vx2_release_pseudo_dma(chip);
index 281972913c32140939c087067f4340d6882e6626..56aa1ba73ccc1ccb488bc662aa7ad459213eb696 100644 (file)
@@ -369,12 +369,12 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        unsigned short *addr = (unsigned short *)(runtime->dma_area + offset);
 
        vx_setup_pseudo_dma(chip, 1);
-       if (offset + count > pipe->buffer_bytes) {
+       if (offset + count >= pipe->buffer_bytes) {
                int length = pipe->buffer_bytes - offset;
                count -= length;
                length >>= 1; /* in 16bit words */
                /* Transfer using pseudo-dma. */
-               while (length-- > 0) {
+               for (; length > 0; length--) {
                        outw(cpu_to_le16(*addr), port);
                        addr++;
                }
@@ -384,7 +384,7 @@ static void vxp_dma_write(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        pipe->hw_ptr += count;
        count >>= 1; /* in 16bit words */
        /* Transfer using pseudo-dma. */
-       while (count-- > 0) {
+       for (; count > 0; count--) {
                outw(cpu_to_le16(*addr), port);
                addr++;
        }
@@ -411,12 +411,12 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        if (snd_BUG_ON(count % 2))
                return;
        vx_setup_pseudo_dma(chip, 0);
-       if (offset + count > pipe->buffer_bytes) {
+       if (offset + count >= pipe->buffer_bytes) {
                int length = pipe->buffer_bytes - offset;
                count -= length;
                length >>= 1; /* in 16bit words */
                /* Transfer using pseudo-dma. */
-               while (length-- > 0)
+               for (; length > 0; length--)
                        *addr++ = le16_to_cpu(inw(port));
                addr = (unsigned short *)runtime->dma_area;
                pipe->hw_ptr = 0;
@@ -424,7 +424,7 @@ static void vxp_dma_read(struct vx_core *chip, struct snd_pcm_runtime *runtime,
        pipe->hw_ptr += count;
        count >>= 1; /* in 16bit words */
        /* Transfer using pseudo-dma. */
-       while (count-- > 1)
+       for (; count > 1; count--)
                *addr++ = le16_to_cpu(inw(port));
        /* Disable DMA */
        pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK;
index a0209204ae4892a490877c30eaf056c45cd8043a..55579f6b8cb2ed36566cb0c24685d743489b1a4f 100644 (file)
@@ -33,13 +33,13 @@ static int snd_emux_unuse(void *private_data, struct snd_seq_port_subscribe *inf
  * MIDI emulation operators
  */
 static struct snd_midi_op emux_ops = {
-       snd_emux_note_on,
-       snd_emux_note_off,
-       snd_emux_key_press,
-       snd_emux_terminate_note,
-       snd_emux_control,
-       snd_emux_nrpn,
-       snd_emux_sysex,
+       .note_on = snd_emux_note_on,
+       .note_off = snd_emux_note_off,
+       .key_press = snd_emux_key_press,
+       .note_terminate = snd_emux_terminate_note,
+       .control = snd_emux_control,
+       .nrpn = snd_emux_nrpn,
+       .sysex = snd_emux_sysex,
 };
 
 
index 3d410969553e2da2748b0587416fb5a8e8b41aab..aa5adbb6eb5d48d3f573f83c227d45632f44a2c8 100644 (file)
@@ -139,14 +139,14 @@ static void usb6fire_midi_in_trigger(
        spin_unlock_irqrestore(&rt->in_lock, flags);
 }
 
-static struct snd_rawmidi_ops out_ops = {
+static const struct snd_rawmidi_ops out_ops = {
        .open = usb6fire_midi_out_open,
        .close = usb6fire_midi_out_close,
        .trigger = usb6fire_midi_out_trigger,
        .drain = usb6fire_midi_out_drain
 };
 
-static struct snd_rawmidi_ops in_ops = {
+static const struct snd_rawmidi_ops in_ops = {
        .open = usb6fire_midi_in_open,
        .close = usb6fire_midi_in_close,
        .trigger = usb6fire_midi_in_trigger
index 2d2d122b069f37974b7353d781023cf99cbe11ef..42cb33b94f6a6f9ffad59dd650955439377e6275 100644 (file)
@@ -10,6 +10,7 @@ snd-usb-audio-objs :=         card.o \
                        mixer.o \
                        mixer_quirks.o \
                        mixer_scarlett.o \
+                       mixer_us16x08.o \
                        pcm.o \
                        proc.o \
                        quirks.o \
index d060dddcc52d5d71be56731b647d2d64442c1fc8..2ff9d578753a7b7d20ece51ff45bdb503586a519 100644 (file)
@@ -252,13 +252,13 @@ static void bcd2000_input_complete(struct urb *urb)
                        __func__, ret);
 }
 
-static struct snd_rawmidi_ops bcd2000_midi_output = {
+static const struct snd_rawmidi_ops bcd2000_midi_output = {
        .open =    bcd2000_midi_output_open,
        .close =   bcd2000_midi_output_close,
        .trigger = bcd2000_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops bcd2000_midi_input = {
+static const struct snd_rawmidi_ops bcd2000_midi_input = {
        .open =    bcd2000_midi_input_open,
        .close =   bcd2000_midi_input_close,
        .trigger = bcd2000_midi_input_trigger,
index 2d7588461b33763039b6e23ec8a4c6d108f1c39d..f8e5b1b57c4fcac93102487362886d669e6fc0fe 100644 (file)
@@ -102,14 +102,14 @@ static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *subs
 }
 
 
-static struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
+static const struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
 {
        .open =         snd_usb_caiaq_midi_output_open,
        .close =        snd_usb_caiaq_midi_output_close,
        .trigger =      snd_usb_caiaq_midi_output_trigger,
 };
 
-static struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
+static const struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
 {
        .open =         snd_usb_caiaq_midi_input_open,
        .close =        snd_usb_caiaq_midi_input_close,
index 90009c0b3a92e42f2598e05b451a0cbc0d79c8bf..0ff5a7d2e19fe1cc584a6420461841be26781b9b 100644 (file)
@@ -492,42 +492,46 @@ static void line6_destruct(struct snd_card *card)
        usb_put_dev(usbdev);
 }
 
-/* get data from endpoint descriptor (see usb_maxpacket): */
-static void line6_get_interval(struct usb_line6 *line6)
+static void line6_get_usb_properties(struct usb_line6 *line6)
 {
        struct usb_device *usbdev = line6->usbdev;
        const struct line6_properties *properties = line6->properties;
        int pipe;
-       struct usb_host_endpoint *ep;
+       struct usb_host_endpoint *ep = NULL;
 
-       if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
-               pipe =
-                       usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r);
-       } else {
-               pipe =
-                       usb_rcvbulkpipe(line6->usbdev, line6->properties->ep_ctrl_r);
+       if (properties->capabilities & LINE6_CAP_CONTROL) {
+               if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+                       pipe = usb_rcvintpipe(line6->usbdev,
+                               line6->properties->ep_ctrl_r);
+               } else {
+                       pipe = usb_rcvbulkpipe(line6->usbdev,
+                               line6->properties->ep_ctrl_r);
+               }
+               ep = usbdev->ep_in[usb_pipeendpoint(pipe)];
        }
-       ep = usbdev->ep_in[usb_pipeendpoint(pipe)];
 
+       /* Control data transfer properties */
        if (ep) {
                line6->interval = ep->desc.bInterval;
-               if (usbdev->speed == USB_SPEED_LOW) {
-                       line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND;
-                       line6->iso_buffers = USB_LOW_ISO_BUFFERS;
-               } else {
-                       line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND;
-                       line6->iso_buffers = USB_HIGH_ISO_BUFFERS;
-               }
-
                line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
        } else {
-               dev_err(line6->ifcdev,
-                       "endpoint not available, using fallback values");
+               if (properties->capabilities & LINE6_CAP_CONTROL) {
+                       dev_err(line6->ifcdev,
+                               "endpoint not available, using fallback values");
+               }
                line6->interval = LINE6_FALLBACK_INTERVAL;
                line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
        }
-}
 
+       /* Isochronous transfer properties */
+       if (usbdev->speed == USB_SPEED_LOW) {
+               line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND;
+               line6->iso_buffers = USB_LOW_ISO_BUFFERS;
+       } else {
+               line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND;
+               line6->iso_buffers = USB_HIGH_ISO_BUFFERS;
+       }
+}
 
 /* Enable buffering of incoming messages, flush the buffer */
 static int line6_hwdep_open(struct snd_hwdep *hw, struct file *file)
@@ -754,8 +758,9 @@ int line6_probe(struct usb_interface *interface,
                goto error;
        }
 
+       line6_get_usb_properties(line6);
+
        if (properties->capabilities & LINE6_CAP_CONTROL) {
-               line6_get_interval(line6);
                ret = line6_init_cap_control(line6);
                if (ret < 0)
                        goto error;
index d0fb2f205bd94a804b6958cef5fa51e2f58eae85..1d3a23b02d68a9cb021bd315fa018b63ac2a4e6b 100644 (file)
@@ -200,14 +200,14 @@ static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
                line6->line6midi->substream_receive = NULL;
 }
 
-static struct snd_rawmidi_ops line6_midi_output_ops = {
+static const struct snd_rawmidi_ops line6_midi_output_ops = {
        .open = line6_midi_output_open,
        .close = line6_midi_output_close,
        .trigger = line6_midi_output_trigger,
        .drain = line6_midi_output_drain,
 };
 
-static struct snd_rawmidi_ops line6_midi_input_ops = {
+static const struct snd_rawmidi_ops line6_midi_input_ops = {
        .open = line6_midi_input_open,
        .close = line6_midi_input_close,
        .trigger = line6_midi_input_trigger,
index 7ba92921bf283b3ffc8c0987917afc7fe830c383..6e763bc8d7dbb5b7d4ba43ef3201050b726b089a 100644 (file)
@@ -1234,14 +1234,14 @@ static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream,
                clear_bit(substream->number, &umidi->input_triggered);
 }
 
-static struct snd_rawmidi_ops snd_usbmidi_output_ops = {
+static const struct snd_rawmidi_ops snd_usbmidi_output_ops = {
        .open = snd_usbmidi_output_open,
        .close = snd_usbmidi_output_close,
        .trigger = snd_usbmidi_output_trigger,
        .drain = snd_usbmidi_output_drain,
 };
 
-static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
+static const struct snd_rawmidi_ops snd_usbmidi_input_ops = {
        .open = snd_usbmidi_input_open,
        .close = snd_usbmidi_input_close,
        .trigger = snd_usbmidi_input_trigger
index 04991b00913222f07f4d6dbcb0dc6b955db4f5a5..4fa0053a40af27673d48cd8bba56eac3be919f8b 100644 (file)
@@ -43,6 +43,7 @@
 #include "mixer.h"
 #include "mixer_quirks.h"
 #include "mixer_scarlett.h"
+#include "mixer_us16x08.h"
 #include "helper.h"
 
 extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
@@ -1729,6 +1730,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
                return err;
 
        switch (mixer->chip->usb_id) {
+       /* Tascam US-16x08 */
+       case USB_ID(0x0644, 0x8047):
+               err = snd_us16x08_controls_create(mixer);
+               break;
        case USB_ID(0x041e, 0x3020):
        case USB_ID(0x041e, 0x3040):
        case USB_ID(0x041e, 0x3042):
diff --git a/sound/usb/mixer_us16x08.c b/sound/usb/mixer_us16x08.c
new file mode 100644 (file)
index 0000000..301939b
--- /dev/null
@@ -0,0 +1,1465 @@
+/*
+ *   Tascam US-16x08 ALSA driver
+ *
+ *   Copyright (c) 2016 by Detlef Urban (onkel@paraair.de)
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+
+#include "mixer_us16x08.h"
+
+/* USB control message templates */
+static const char route_msg[] = {
+       0x61,
+       0x02,
+       0x03, /* input from master (0x02) or input from computer bus (0x03) */
+       0x62,
+       0x02,
+       0x01, /* input index (0x01/0x02 eq. left/right) or bus (0x01-0x08) */
+       0x41,
+       0x01,
+       0x61,
+       0x02,
+       0x01,
+       0x62,
+       0x02,
+       0x01, /* output index (0x01-0x08) */
+       0x42,
+       0x01,
+       0x43,
+       0x01,
+       0x00,
+       0x00
+};
+
+static const char mix_init_msg1[] = {
+       0x71, 0x01, 0x00, 0x00
+};
+
+static const char mix_init_msg2[] = {
+       0x62, 0x02, 0x00, 0x61, 0x02, 0x04, 0xb1, 0x01, 0x00, 0x00
+};
+
+static const char mix_msg_in[] = {
+       /* default message head, equal to all mixers */
+       0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
+       0x81, /* 0x06: Controller ID */
+       0x02, /* 0x07:  */
+       0x00, /* 0x08: Value of common mixer */
+       0x00,
+       0x00
+};
+
+static const char mix_msg_out[] = {
+       /* default message head, equal to all mixers */
+       0x61, 0x02, 0x02, 0x62, 0x02, 0x01,
+       0x81, /* 0x06: Controller ID */
+       0x02, /*                    0x07:  */
+       0x00, /*                    0x08: Value of common mixer */
+       0x00,
+       0x00
+};
+
+static const char bypass_msg_out[] = {
+       0x45,
+       0x02,
+       0x01, /* on/off flag */
+       0x00,
+       0x00
+};
+
+static const char bus_msg_out[] = {
+       0x44,
+       0x02,
+       0x01, /* on/off flag */
+       0x00,
+       0x00
+};
+
+static const char comp_msg[] = {
+       /* default message head, equal to all mixers */
+       0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
+       0x91,
+       0x02,
+       0xf0, /* 0x08: Threshold db (8) (e0 ... 00) (+-0dB -- -32dB) x-32 */
+       0x92,
+       0x02,
+       0x0a, /* 0x0b: Ratio (0a,0b,0d,0f,11,14,19,1e,23,28,32,3c,50,a0,ff)  */
+       0x93,
+       0x02,
+       0x02, /* 0x0e: Attack (0x02 ... 0xc0) (2ms ... 200ms) */
+       0x94,
+       0x02,
+       0x01, /* 0x11: Release (0x01 ... 0x64) (10ms ... 1000ms) x*10  */
+       0x95,
+       0x02,
+       0x03, /* 0x14: gain (0 ... 20) (0dB .. 20dB) */
+       0x96,
+       0x02,
+       0x01,
+       0x97,
+       0x02,
+       0x01, /* 0x1a: main Comp switch (0 ... 1) (off ... on)) */
+       0x00,
+       0x00
+};
+
+static const char eqs_msq[] = {
+       /* default message head, equal to all mixers */
+       0x61, 0x02, 0x04, 0x62, 0x02, 0x01,
+       0x51, /*                0x06: Controller ID  */
+       0x02,
+       0x04, /* 0x08: EQ set num (0x01..0x04) (LOW, LOWMID, HIGHMID, HIGH)) */
+       0x52,
+       0x02,
+       0x0c, /* 0x0b: value dB (0 ... 12) (-12db .. +12db)  x-6 */
+       0x53,
+       0x02,
+       0x0f, /* 0x0e: value freq (32-47) (1.7kHz..18kHz) */
+       0x54,
+       0x02,
+       0x02, /* 0x11: band width (0-6) (Q16-Q0.25)  2^x/4 (EQ xxMID only) */
+       0x55,
+       0x02,
+       0x01, /* 0x14: main EQ switch (0 ... 1) (off ... on)) */
+       0x00,
+       0x00
+};
+
+/* compressor ratio map */
+static const char ratio_map[] = {
+       0x0a, 0x0b, 0x0d, 0x0f, 0x11, 0x14, 0x19, 0x1e,
+       0x23, 0x28, 0x32, 0x3c, 0x50, 0xa0, 0xff
+};
+
+/* route enumeration names */
+const const char *route_names[] = {
+       "Master Left", "Master Right", "Output 1", "Output 2", "Output 3",
+       "Output 4", "Output 5", "Output 6", "Output 7", "Output 8",
+};
+
+static int snd_us16x08_recv_urb(struct snd_usb_audio *chip,
+       unsigned char *buf, int size)
+{
+
+       mutex_lock(&chip->mutex);
+       snd_usb_ctl_msg(chip->dev,
+               usb_rcvctrlpipe(chip->dev, 0),
+               SND_US16X08_URB_METER_REQUEST,
+               SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+/* wrapper function to send prepared URB buffer to usb device. Return an error
+ * code if something went wrong
+ */
+static int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size)
+{
+       int err = 0;
+
+       if (chip) {
+               err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+                       SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE,
+                       0, 0, buf, size);
+       }
+
+       return err;
+}
+
+static int snd_us16x08_route_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       return snd_ctl_enum_info(uinfo, 1, 10, route_names);
+}
+
+static int snd_us16x08_route_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       int index = ucontrol->id.index;
+
+       /* route has no bias */
+       ucontrol->value.enumerated.item[0] = elem->cache_val[index];
+
+       return 0;
+}
+
+static int snd_us16x08_route_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       int index = ucontrol->id.index;
+       char buf[sizeof(route_msg)];
+       int val, val_org, err = 0;
+
+       /* prepare the message buffer from template */
+       memcpy(buf, route_msg, sizeof(route_msg));
+
+       /*  get the new value (no bias for routes) */
+       val = ucontrol->value.enumerated.item[0];
+
+       /* sanity check */
+       if (val < 0 || val > 9)
+               return -EINVAL;
+
+       if (val < 2) {
+               /* input comes from a master channel */
+               val_org = val;
+               buf[2] = 0x02;
+       } else {
+               /* input comes from a computer channel */
+               buf[2] = 0x03;
+               val_org = val - 2;
+       }
+
+       /* place new route selection in URB message */
+       buf[5] = (unsigned char) (val_org & 0x0f) + 1;
+       /* place route selector in URB message */
+       buf[13] = index + 1;
+
+       err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg));
+
+       if (err > 0) {
+               elem->cached |= 1 << index;
+               elem->cache_val[index] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set routing, err:%d\n", err);
+       }
+
+       return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_master_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->count = 1;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+       uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+       uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+       return 0;
+}
+
+static int snd_us16x08_master_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       int index = ucontrol->id.index;
+
+       ucontrol->value.integer.value[0] = elem->cache_val[index];
+
+       return 0;
+}
+
+static int snd_us16x08_master_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       char buf[sizeof(mix_msg_out)];
+       int val, err = 0;
+       int index = ucontrol->id.index;
+
+       /* prepare the message buffer from template */
+       memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
+
+       /* new control value incl. bias*/
+       val = ucontrol->value.integer.value[0];
+
+       /* sanity check */
+       if (val < SND_US16X08_KCMIN(kcontrol)
+               || val > SND_US16X08_KCMAX(kcontrol))
+               return -EINVAL;
+
+       buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
+       buf[6] = elem->head.id;
+
+       /* place channel selector in URB message */
+       buf[5] = index + 1;
+       err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
+
+       if (err > 0) {
+               elem->cached |= 1 << index;
+               elem->cache_val[index] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set master, err:%d\n", err);
+       }
+
+       return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       char buf[sizeof(mix_msg_out)];
+       int val, err = 0;
+
+       val = ucontrol->value.integer.value[0];
+
+       /* prepare the message buffer from template */
+       switch (elem->head.id) {
+       case SND_US16X08_ID_BYPASS:
+               memcpy(buf, bypass_msg_out, sizeof(bypass_msg_out));
+               buf[2] = val;
+               err = snd_us16x08_send_urb(chip, buf, sizeof(bypass_msg_out));
+               break;
+       case SND_US16X08_ID_BUSS_OUT:
+               memcpy(buf, bus_msg_out, sizeof(bus_msg_out));
+               buf[2] = val;
+               err = snd_us16x08_send_urb(chip, buf, sizeof(bus_msg_out));
+               break;
+       case SND_US16X08_ID_MUTE:
+               memcpy(buf, mix_msg_out, sizeof(mix_msg_out));
+               buf[8] = val;
+               buf[6] = elem->head.id;
+               buf[5] = 1;
+               err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out));
+               break;
+       }
+
+       if (err > 0) {
+               elem->cached |= 1;
+               elem->cache_val[0] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set buss param, err:%d\n", err);
+       }
+
+       return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+
+       switch (elem->head.id) {
+       case SND_US16X08_ID_BUSS_OUT:
+               ucontrol->value.integer.value[0] = elem->cache_val[0];
+               break;
+       case SND_US16X08_ID_BYPASS:
+               ucontrol->value.integer.value[0] = elem->cache_val[0];
+               break;
+       case SND_US16X08_ID_MUTE:
+               ucontrol->value.integer.value[0] = elem->cache_val[0];
+               break;
+       }
+
+       return 0;
+}
+
+/* gets a current mixer value from common store */
+static int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       int index = ucontrol->id.index;
+
+       ucontrol->value.integer.value[0] = elem->cache_val[index];
+
+       return 0;
+}
+
+static int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       char buf[sizeof(mix_msg_in)];
+       int val, err;
+       int index = ucontrol->id.index;
+
+       /* prepare URB message from template */
+       memcpy(buf, mix_msg_in, sizeof(mix_msg_in));
+
+       val = ucontrol->value.integer.value[0];
+
+       /* sanity check */
+       if (val < SND_US16X08_KCMIN(kcontrol)
+               || val > SND_US16X08_KCMAX(kcontrol))
+               return -EINVAL;
+
+       /* add the bias to the new value */
+       buf[8] = val - SND_US16X08_KCBIAS(kcontrol);
+       buf[6] = elem->head.id;
+       buf[5] = index + 1;
+
+       err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in));
+
+       if (err > 0) {
+               elem->cached |= 1 << index;
+               elem->cache_val[index] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set channel, err:%d\n", err);
+       }
+
+       return err > 0 ? 1 : 0;
+}
+
+static int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->count = 1;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol);
+       uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol);
+       uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol);
+       return 0;
+}
+
+static int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_us16x08_comp_store *store =
+               ((struct snd_us16x08_comp_store *) elem->private_data);
+       int index = ucontrol->id.index;
+       int val_idx = COMP_STORE_IDX(elem->head.id);
+
+       ucontrol->value.integer.value[0] = store->val[val_idx][index];
+
+       return 0;
+}
+
+static int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       struct snd_us16x08_comp_store *store =
+               ((struct snd_us16x08_comp_store *) elem->private_data);
+       int index = ucontrol->id.index;
+       char buf[sizeof(comp_msg)];
+       int val_idx, val;
+       int err = 0;
+
+       /* prepare compressor URB message from template  */
+       memcpy(buf, comp_msg, sizeof(comp_msg));
+
+       /* new control value incl. bias*/
+       val_idx = elem->head.id - SND_US16X08_ID_COMP_BASE;
+
+       val = ucontrol->value.integer.value[0];
+
+       /* sanity check */
+       if (val < SND_US16X08_KCMIN(kcontrol)
+               || val > SND_US16X08_KCMAX(kcontrol))
+               return -EINVAL;
+
+       store->val[val_idx][index] = ucontrol->value.integer.value[0];
+
+       /* place comp values in message buffer watch bias! */
+       buf[8] = store->val[
+               COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][index]
+               - SND_US16X08_COMP_THRESHOLD_BIAS;
+       buf[11] = ratio_map[store->val[
+               COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index]];
+       buf[14] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index]
+               + SND_US16X08_COMP_ATTACK_BIAS;
+       buf[17] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][index]
+               + SND_US16X08_COMP_RELEASE_BIAS;
+       buf[20] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index];
+       buf[26] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][index];
+
+       /* place channel selector in message buffer */
+       buf[5] = index + 1;
+
+       err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg));
+
+       if (err > 0) {
+               elem->cached |= 1 << index;
+               elem->cache_val[index] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set compressor, err:%d\n", err);
+       }
+
+       return 1;
+}
+
+static int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int val = 0;
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_us16x08_eq_store *store =
+               ((struct snd_us16x08_eq_store *) elem->private_data);
+       int index = ucontrol->id.index;
+
+       /* get low switch from cache is enough, cause all bands are together */
+       val = store->val[EQ_STORE_BAND_IDX(elem->head.id)]
+               [EQ_STORE_PARAM_IDX(elem->head.id)][index];
+       ucontrol->value.integer.value[0] = val;
+
+       return 0;
+}
+
+static int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       struct snd_us16x08_eq_store *store =
+               ((struct snd_us16x08_eq_store *) elem->private_data);
+       int index = ucontrol->id.index;
+
+       char buf[sizeof(eqs_msq)];
+       int val, err = 0;
+       int b_idx;
+
+       /* new control value incl. bias*/
+       val = ucontrol->value.integer.value[0] + SND_US16X08_KCBIAS(kcontrol);
+
+       /* prepare URB message from EQ template */
+       memcpy(buf, eqs_msq, sizeof(eqs_msq));
+
+       /* place channel index in URB message */
+       buf[5] = index + 1;
+       for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
+               /* all four EQ bands have to be enabled/disabled in once */
+               buf[20] = val;
+               buf[17] = store->val[b_idx][2][index];
+               buf[14] = store->val[b_idx][1][index];
+               buf[11] = store->val[b_idx][0][index];
+               buf[8] = b_idx + 1;
+               err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+               if (err < 0)
+                       break;
+               store->val[b_idx][3][index] = val;
+               msleep(15);
+       }
+
+       if (err > 0) {
+               elem->cached |= 1 << index;
+               elem->cache_val[index] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set eq switch, err:%d\n", err);
+       }
+
+       return 1;
+}
+
+static int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int val = 0;
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_us16x08_eq_store *store =
+               ((struct snd_us16x08_eq_store *) elem->private_data);
+       int index = ucontrol->id.index;
+       int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
+       int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
+
+       val = store->val[b_idx][p_idx][index];
+
+       ucontrol->value.integer.value[0] = val;
+
+       return 0;
+}
+
+static int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       struct snd_us16x08_eq_store *store =
+               ((struct snd_us16x08_eq_store *) elem->private_data);
+       int index = ucontrol->id.index;
+       char buf[sizeof(eqs_msq)];
+       int val, err = 0;
+       int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1;
+       int p_idx = EQ_STORE_PARAM_IDX(elem->head.id);
+
+       /* copy URB buffer from EQ template */
+       memcpy(buf, eqs_msq, sizeof(eqs_msq));
+
+       val = ucontrol->value.integer.value[0];
+
+       /* sanity check */
+       if (val < SND_US16X08_KCMIN(kcontrol)
+               || val > SND_US16X08_KCMAX(kcontrol))
+               return -EINVAL;
+
+       store->val[b_idx][p_idx][index] = val;
+       buf[20] = store->val[b_idx][3][index];
+       buf[17] = store->val[b_idx][2][index];
+       buf[14] = store->val[b_idx][1][index];
+       buf[11] = store->val[b_idx][0][index];
+
+       /* place channel index in URB buffer */
+       buf[5] = index + 1;
+
+       /* place EQ band in URB buffer */
+       buf[8] = b_idx + 1;
+
+       err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq));
+
+       if (err > 0) {
+               /* store new value in EQ band cache */
+               elem->cached |= 1 << index;
+               elem->cache_val[index] = val;
+       } else {
+               usb_audio_dbg(chip, "Failed to set eq param, err:%d\n", err);
+       }
+
+       return 1;
+}
+
+static int snd_us16x08_meter_info(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->count = 1;
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.max = 0x7FFF;
+       uinfo->value.integer.min = 0;
+
+       return 0;
+}
+
+/* calculate compressor index for reduction level request */
+static int snd_get_meter_comp_index(struct snd_us16x08_meter_store *store)
+{
+       int ret;
+
+       /* any channel active */
+       if (store->comp_active_index) {
+               /* check for stereo link */
+               if (store->comp_active_index & 0x20) {
+                       /* reset comp_index to left channel*/
+                       if (store->comp_index -
+                               store->comp_active_index > 1)
+                               store->comp_index =
+                               store->comp_active_index;
+
+                       ret = store->comp_index++ & 0x1F;
+               } else {
+                       /* no stereo link */
+                       ret = store->comp_active_index;
+               }
+       } else {
+               /* skip channels with no compressor active */
+               while (!store->comp_store->val[
+                       COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)]
+                       [store->comp_index - 1]
+                       && store->comp_index <= SND_US16X08_MAX_CHANNELS) {
+                       store->comp_index++;
+               }
+               ret = store->comp_index++;
+               if (store->comp_index > SND_US16X08_MAX_CHANNELS)
+                       store->comp_index = 1;
+       }
+       return ret;
+}
+
+/* retrieve the meter level values from URB message */
+static void get_meter_levels_from_urb(int s,
+       struct snd_us16x08_meter_store *store,
+       u8 *meter_urb)
+{
+       int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8);
+
+       if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
+               MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) {
+               if (MUC0(meter_urb, s) == 0x72)
+                       store->meter_level[MUB2(meter_urb, s) - 1] = val;
+               if (MUC0(meter_urb, s) == 0xb2)
+                       store->comp_level[MUB2(meter_urb, s) - 1] = val;
+       }
+       if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 &&
+               MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62)
+               store->master_level[MUB2(meter_urb, s) - 1] = val;
+}
+
+/* Function to retrieve current meter values from the device.
+ *
+ * The device needs to be polled for meter values with an initial
+ * requests. It will return with a sequence of different meter value
+ * packages. The first request (case 0:) initiate this meter response sequence.
+ * After the third response, an additional request can be placed,
+ * to retrieve compressor reduction level value for given channel. This round
+ * trip channel selector will skip all inactive compressors.
+ * A mixer can interrupt this round-trip by selecting one ore two (stereo-link)
+ * specific channels.
+ */
+static int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       int i, set;
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_usb_audio *chip = elem->head.mixer->chip;
+       struct snd_us16x08_meter_store *store = elem->private_data;
+       u8 meter_urb[64];
+       char tmp[max(sizeof(mix_init_msg1), sizeof(mix_init_msg2))];
+
+       if (elem) {
+               store = (struct snd_us16x08_meter_store *) elem->private_data;
+               chip = elem->head.mixer->chip;
+       } else
+               return 0;
+
+       switch (kcontrol->private_value) {
+       case 0:
+               memcpy(tmp, mix_init_msg1, sizeof(mix_init_msg1));
+               snd_us16x08_send_urb(chip, tmp, 4);
+               snd_us16x08_recv_urb(chip, meter_urb,
+                       sizeof(meter_urb));
+               kcontrol->private_value++;
+               break;
+       case 1:
+               snd_us16x08_recv_urb(chip, meter_urb,
+                       sizeof(meter_urb));
+               kcontrol->private_value++;
+               break;
+       case 2:
+               snd_us16x08_recv_urb(chip, meter_urb,
+                       sizeof(meter_urb));
+               kcontrol->private_value++;
+               break;
+       case 3:
+               memcpy(tmp, mix_init_msg2, sizeof(mix_init_msg2));
+               tmp[2] = snd_get_meter_comp_index(store);
+               snd_us16x08_send_urb(chip, tmp, 10);
+               snd_us16x08_recv_urb(chip, meter_urb,
+                       sizeof(meter_urb));
+               kcontrol->private_value = 0;
+               break;
+       }
+
+       for (set = 0; set < 6; set++)
+               get_meter_levels_from_urb(set, store, meter_urb);
+
+       for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+               ucontrol->value.integer.value[i] =
+                       store ? store->meter_level[i] : 0;
+       }
+
+       ucontrol->value.integer.value[i++] = store ? store->master_level[0] : 0;
+       ucontrol->value.integer.value[i++] = store ? store->master_level[1] : 0;
+
+       for (i = 2; i < SND_US16X08_MAX_CHANNELS + 2; i++)
+               ucontrol->value.integer.value[i + SND_US16X08_MAX_CHANNELS] =
+               store ? store->comp_level[i - 2] : 0;
+
+       return 1;
+}
+
+static int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *elem = kcontrol->private_data;
+       struct snd_us16x08_meter_store *store = elem->private_data;
+       int val;
+
+       val = ucontrol->value.integer.value[0];
+
+       /* sanity check */
+       if (val < 0 || val >= SND_US16X08_MAX_CHANNELS)
+               return -EINVAL;
+
+       store->comp_active_index = val;
+       store->comp_index = val;
+
+       return 1;
+}
+
+static struct snd_kcontrol_new snd_us16x08_ch_boolean_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_switch_info,
+       .get = snd_us16x08_channel_get,
+       .put = snd_us16x08_channel_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_ch_int_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_channel_get,
+       .put = snd_us16x08_channel_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
+};
+
+static struct snd_kcontrol_new snd_us16x08_pan_int_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_channel_get,
+       .put = snd_us16x08_channel_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 255)
+};
+
+static struct snd_kcontrol_new snd_us16x08_master_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 1,
+       .info = snd_us16x08_master_info,
+       .get = snd_us16x08_master_get,
+       .put = snd_us16x08_master_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133)
+};
+
+static struct snd_kcontrol_new snd_us16x08_route_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 8,
+       .info = snd_us16x08_route_info,
+       .get = snd_us16x08_route_get,
+       .put = snd_us16x08_route_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 9)
+};
+
+static struct snd_kcontrol_new snd_us16x08_bus_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 1,
+       .info = snd_us16x08_switch_info,
+       .get = snd_us16x08_bus_get,
+       .put = snd_us16x08_bus_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_compswitch_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_switch_info,
+       .get = snd_us16x08_comp_get,
+       .put = snd_us16x08_comp_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_threshold_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_comp_get,
+       .put = snd_us16x08_comp_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_COMP_THRESHOLD_BIAS, 1,
+       0, 0x20)
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_ratio_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_comp_get,
+       .put = snd_us16x08_comp_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0,
+       sizeof(ratio_map) - 1), /*max*/
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_gain_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_comp_get,
+       .put = snd_us16x08_comp_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x14)
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_attack_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_comp_get,
+       .put = snd_us16x08_comp_put,
+       .private_value =
+       SND_US16X08_KCSET(SND_US16X08_COMP_ATTACK_BIAS, 1, 0, 0xc6),
+};
+
+static struct snd_kcontrol_new snd_us16x08_comp_release_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_comp_get,
+       .put = snd_us16x08_comp_put,
+       .private_value =
+       SND_US16X08_KCSET(SND_US16X08_COMP_RELEASE_BIAS, 1, 0, 0x63),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_gain_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_eq_get,
+       .put = snd_us16x08_eq_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 24),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_low_freq_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_eq_get,
+       .put = snd_us16x08_eq_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x1F),
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_mid_freq_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_eq_get,
+       .put = snd_us16x08_eq_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x3F)
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_mid_width_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_eq_get,
+       .put = snd_us16x08_eq_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x06)
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_high_freq_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_mix_info,
+       .get = snd_us16x08_eq_get,
+       .put = snd_us16x08_eq_put,
+       .private_value =
+       SND_US16X08_KCSET(SND_US16X08_EQ_HIGHFREQ_BIAS, 1, 0, 0x1F)
+};
+
+static struct snd_kcontrol_new snd_us16x08_eq_switch_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 16,
+       .info = snd_us16x08_switch_info,
+       .get = snd_us16x08_eqswitch_get,
+       .put = snd_us16x08_eqswitch_put,
+       .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1)
+};
+
+static struct snd_kcontrol_new snd_us16x08_meter_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .count = 1,
+       .info = snd_us16x08_meter_info,
+       .get = snd_us16x08_meter_get,
+       .put = snd_us16x08_meter_put
+};
+
+/* control store preparation */
+
+/* setup compressor store and assign default value */
+static struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void)
+{
+       int i = 0;
+       struct snd_us16x08_comp_store *tmp =
+               kmalloc(sizeof(struct snd_us16x08_comp_store), GFP_KERNEL);
+
+       if (tmp == NULL)
+               return NULL;
+
+       for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+               tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][i]
+                       = 0x20;
+               tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][i] = 0x00;
+               tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][i] = 0x00;
+               tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][i] = 0x00;
+               tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][i] = 0x00;
+               tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][i] = 0x00;
+       }
+       return tmp;
+}
+
+/* setup EQ store and assign default values */
+static struct snd_us16x08_eq_store *snd_us16x08_create_eq_store(void)
+{
+       int i, b_idx;
+       struct snd_us16x08_eq_store *tmp =
+               kmalloc(sizeof(struct snd_us16x08_eq_store), GFP_KERNEL);
+
+       if (tmp == NULL)
+               return NULL;
+
+       for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) {
+               for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) {
+                       tmp->val[b_idx][0][i] = 0x0c;
+                       tmp->val[b_idx][3][i] = 0x00;
+                       switch (b_idx) {
+                       case 0: /* EQ Low */
+                               tmp->val[b_idx][1][i] = 0x05;
+                               tmp->val[b_idx][2][i] = 0xff;
+                               break;
+                       case 1: /* EQ Mid low */
+                               tmp->val[b_idx][1][i] = 0x0e;
+                               tmp->val[b_idx][2][i] = 0x02;
+                               break;
+                       case 2: /* EQ Mid High */
+                               tmp->val[b_idx][1][i] = 0x1b;
+                               tmp->val[b_idx][2][i] = 0x02;
+                               break;
+                       case 3: /* EQ High */
+                               tmp->val[b_idx][1][i] = 0x2f
+                                       - SND_US16X08_EQ_HIGHFREQ_BIAS;
+                               tmp->val[b_idx][2][i] = 0xff;
+                               break;
+                       }
+               }
+       }
+       return tmp;
+}
+
+struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void)
+{
+       struct snd_us16x08_meter_store *tmp =
+               kzalloc(sizeof(struct snd_us16x08_meter_store), GFP_KERNEL);
+
+       if (!tmp)
+               return NULL;
+       tmp->comp_index = 1;
+       tmp->comp_active_index = 0;
+       return tmp;
+
+}
+
+static int add_new_ctl(struct usb_mixer_interface *mixer,
+       const struct snd_kcontrol_new *ncontrol,
+       int index, int val_type, int channels,
+       const char *name, const void *opt,
+       void (*freeer)(struct snd_kcontrol *kctl),
+       struct usb_mixer_elem_info **elem_ret)
+{
+       struct snd_kcontrol *kctl;
+       struct usb_mixer_elem_info *elem;
+       int err;
+
+       usb_audio_dbg(mixer->chip, "us16x08 add mixer %s\n", name);
+
+       elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+       if (!elem)
+               return -ENOMEM;
+
+       elem->head.mixer = mixer;
+       elem->head.resume = NULL;
+       elem->control = 0;
+       elem->idx_off = 0;
+       elem->head.id = index;
+       elem->val_type = val_type;
+       elem->channels = channels;
+       elem->private_data = (void *) opt;
+
+       kctl = snd_ctl_new1(ncontrol, elem);
+       if (!kctl) {
+               kfree(elem);
+               return -ENOMEM;
+       }
+
+       kctl->private_free = freeer;
+
+       strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+
+       err = snd_usb_mixer_add_control(&elem->head, kctl);
+       if (err < 0)
+               return err;
+
+       if (elem_ret)
+               *elem_ret = elem;
+
+       return 0;
+}
+
+static struct snd_us16x08_control_params control_params;
+
+/* table of EQ controls */
+static struct snd_us16x08_control_params eq_controls[] = {
+       { /* EQ switch */
+               .kcontrol_new = &snd_us16x08_eq_switch_ctl,
+               .control_id = SND_US16X08_ID_EQENABLE,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "EQ Switch",
+               .freeer = snd_usb_mixer_elem_free
+       },
+       { /* EQ low gain */
+               .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+               .control_id = SND_US16X08_ID_EQLOWLEVEL,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ Low Volume",
+               .freeer = snd_usb_mixer_elem_free
+       },
+       { /* EQ low freq */
+               .kcontrol_new = &snd_us16x08_eq_low_freq_ctl,
+               .control_id = SND_US16X08_ID_EQLOWFREQ,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ Low Frequence",
+               .freeer = NULL
+       },
+       { /* EQ mid low gain */
+               .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+               .control_id = SND_US16X08_ID_EQLOWMIDLEVEL,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ MidLow Volume",
+               .freeer = snd_usb_mixer_elem_free
+       },
+       { /* EQ mid low freq */
+               .kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
+               .control_id = SND_US16X08_ID_EQLOWMIDFREQ,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ MidLow Frequence",
+               .freeer = NULL
+       },
+       { /* EQ mid low Q */
+               .kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
+               .control_id = SND_US16X08_ID_EQLOWMIDWIDTH,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ MidQLow Q",
+               .freeer = NULL
+       },
+       { /* EQ mid high gain */
+               .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+               .control_id = SND_US16X08_ID_EQHIGHMIDLEVEL,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ MidHigh Volume",
+               .freeer = snd_usb_mixer_elem_free
+       },
+       { /* EQ mid high freq */
+               .kcontrol_new = &snd_us16x08_eq_mid_freq_ctl,
+               .control_id = SND_US16X08_ID_EQHIGHMIDFREQ,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ MidHigh Frequence",
+               .freeer = NULL
+       },
+       { /* EQ mid high Q */
+               .kcontrol_new = &snd_us16x08_eq_mid_width_ctl,
+               .control_id = SND_US16X08_ID_EQHIGHMIDWIDTH,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ MidHigh Q",
+               .freeer = NULL
+       },
+       { /* EQ high gain */
+               .kcontrol_new = &snd_us16x08_eq_gain_ctl,
+               .control_id = SND_US16X08_ID_EQHIGHLEVEL,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ High Volume",
+               .freeer = snd_usb_mixer_elem_free
+       },
+       { /* EQ low freq */
+               .kcontrol_new = &snd_us16x08_eq_high_freq_ctl,
+               .control_id = SND_US16X08_ID_EQHIGHFREQ,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "EQ High Frequence",
+               .freeer = NULL
+       },
+};
+
+/* table of compressor controls */
+static struct snd_us16x08_control_params comp_controls[] = {
+       { /* Comp enable */
+               .kcontrol_new = &snd_us16x08_compswitch_ctl,
+               .control_id = SND_US16X08_ID_COMP_SWITCH,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "Compressor Switch",
+               .freeer = snd_usb_mixer_elem_free
+       },
+       { /* Comp threshold */
+               .kcontrol_new = &snd_us16x08_comp_threshold_ctl,
+               .control_id = SND_US16X08_ID_COMP_THRESHOLD,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Compressor Threshold Volume",
+               .freeer = NULL
+       },
+       { /* Comp ratio */
+               .kcontrol_new = &snd_us16x08_comp_ratio_ctl,
+               .control_id = SND_US16X08_ID_COMP_RATIO,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Compressor Ratio",
+               .freeer = NULL
+       },
+       { /* Comp attack */
+               .kcontrol_new = &snd_us16x08_comp_attack_ctl,
+               .control_id = SND_US16X08_ID_COMP_ATTACK,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Compressor Attack",
+               .freeer = NULL
+       },
+       { /* Comp release */
+               .kcontrol_new = &snd_us16x08_comp_release_ctl,
+               .control_id = SND_US16X08_ID_COMP_RELEASE,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Compressor Release",
+               .freeer = NULL
+       },
+       { /* Comp gain */
+               .kcontrol_new = &snd_us16x08_comp_gain_ctl,
+               .control_id = SND_US16X08_ID_COMP_GAIN,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Compressor Volume",
+               .freeer = NULL
+       },
+};
+
+/* table of channel controls */
+static struct snd_us16x08_control_params channel_controls[] = {
+       { /* Phase */
+               .kcontrol_new = &snd_us16x08_ch_boolean_ctl,
+               .control_id = SND_US16X08_ID_PHASE,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "Phase Switch",
+               .freeer = snd_usb_mixer_elem_free,
+               .default_val = 0
+       },
+       { /* Fader */
+               .kcontrol_new = &snd_us16x08_ch_int_ctl,
+               .control_id = SND_US16X08_ID_FADER,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Line Volume",
+               .freeer = NULL,
+               .default_val = 127
+       },
+       { /* Mute */
+               .kcontrol_new = &snd_us16x08_ch_boolean_ctl,
+               .control_id = SND_US16X08_ID_MUTE,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "Mute Switch",
+               .freeer = NULL,
+               .default_val = 0
+       },
+       { /* Pan */
+               .kcontrol_new = &snd_us16x08_pan_int_ctl,
+               .control_id = SND_US16X08_ID_PAN,
+               .type = USB_MIXER_U16,
+               .num_channels = 16,
+               .name = "Pan Left-Right Volume",
+               .freeer = NULL,
+               .default_val = 127
+       },
+};
+
+/* table of master controls */
+static struct snd_us16x08_control_params master_controls[] = {
+       { /* Master */
+               .kcontrol_new = &snd_us16x08_master_ctl,
+               .control_id = SND_US16X08_ID_FADER,
+               .type = USB_MIXER_U8,
+               .num_channels = 16,
+               .name = "Master Volume",
+               .freeer = NULL,
+               .default_val = 127
+       },
+       { /* Bypass */
+               .kcontrol_new = &snd_us16x08_bus_ctl,
+               .control_id = SND_US16X08_ID_BYPASS,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "DSP Bypass Switch",
+               .freeer = NULL,
+               .default_val = 0
+       },
+       { /* Buss out */
+               .kcontrol_new = &snd_us16x08_bus_ctl,
+               .control_id = SND_US16X08_ID_BUSS_OUT,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "Buss Out Switch",
+               .freeer = NULL,
+               .default_val = 0
+       },
+       { /* Master mute */
+               .kcontrol_new = &snd_us16x08_bus_ctl,
+               .control_id = SND_US16X08_ID_MUTE,
+               .type = USB_MIXER_BOOLEAN,
+               .num_channels = 16,
+               .name = "Master Mute Switch",
+               .freeer = NULL,
+               .default_val = 0
+       },
+
+};
+
+int snd_us16x08_controls_create(struct usb_mixer_interface *mixer)
+{
+       int i, j;
+       int err;
+       struct usb_mixer_elem_info *elem;
+       struct snd_us16x08_comp_store *comp_store;
+       struct snd_us16x08_meter_store *meter_store;
+       struct snd_us16x08_eq_store *eq_store;
+
+       /* just check for non-MIDI interface */
+       if (mixer->hostif->desc.bInterfaceNumber == 3) {
+
+               /* create compressor mixer elements */
+               comp_store = snd_us16x08_create_comp_store();
+               if (comp_store == NULL)
+                       return -ENOMEM;
+
+               /* create eq store */
+               eq_store = snd_us16x08_create_eq_store();
+               if (eq_store == NULL) {
+                       kfree(comp_store);
+                       return -ENOMEM;
+               }
+
+               /* create meters store */
+               meter_store = snd_us16x08_create_meter_store();
+               if (meter_store == NULL) {
+                       kfree(comp_store);
+                       kfree(eq_store);
+                       return -ENOMEM;
+               }
+
+               /* add routing control */
+               err = add_new_ctl(mixer, &snd_us16x08_route_ctl,
+                       SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route",
+                       NULL, NULL, &elem);
+               if (err < 0) {
+                       usb_audio_dbg(mixer->chip,
+                               "Failed to create route control, err:%d\n",
+                               err);
+                       return err;
+               }
+               for (i = 0; i < 8; i++)
+                       elem->cache_val[i] = i < 2 ? i : i + 2;
+               elem->cached = 0xff;
+
+               /* add master controls */
+               for (i = 0;
+                       i < sizeof(master_controls)
+                       / sizeof(control_params);
+                       i++) {
+
+                       err = add_new_ctl(mixer,
+                               master_controls[i].kcontrol_new,
+                               master_controls[i].control_id,
+                               master_controls[i].type,
+                               master_controls[i].num_channels,
+                               master_controls[i].name,
+                               comp_store,
+                               master_controls[i].freeer, &elem);
+                       if (err < 0)
+                               return err;
+                       elem->cache_val[0] = master_controls[i].default_val;
+                       elem->cached = 1;
+               }
+
+               /* add channel controls */
+               for (i = 0;
+                       i < sizeof(channel_controls)
+                       / sizeof(control_params);
+                       i++) {
+
+                       err = add_new_ctl(mixer,
+                               channel_controls[i].kcontrol_new,
+                               channel_controls[i].control_id,
+                               channel_controls[i].type,
+                               channel_controls[i].num_channels,
+                               channel_controls[i].name,
+                               comp_store,
+                               channel_controls[i].freeer, &elem);
+                       if (err < 0)
+                               return err;
+                       for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) {
+                               elem->cache_val[j] =
+                                       channel_controls[i].default_val;
+                       }
+                       elem->cached = 0xffff;
+               }
+
+               /* add EQ controls */
+               for (i = 0; i < sizeof(eq_controls) /
+                       sizeof(control_params); i++) {
+
+                       err = add_new_ctl(mixer,
+                               eq_controls[i].kcontrol_new,
+                               eq_controls[i].control_id,
+                               eq_controls[i].type,
+                               eq_controls[i].num_channels,
+                               eq_controls[i].name,
+                               eq_store,
+                               eq_controls[i].freeer, NULL);
+                       if (err < 0)
+                               return err;
+               }
+
+               /* add compressor controls */
+               for (i = 0;
+                       i < sizeof(comp_controls)
+                       / sizeof(control_params);
+                       i++) {
+
+                       err = add_new_ctl(mixer,
+                               comp_controls[i].kcontrol_new,
+                               comp_controls[i].control_id,
+                               comp_controls[i].type,
+                               comp_controls[i].num_channels,
+                               comp_controls[i].name,
+                               comp_store,
+                               comp_controls[i].freeer, NULL);
+                       if (err < 0)
+                               return err;
+               }
+
+               /* meter function 'get' must access to compressor store
+                * so place a reference here
+                */
+               meter_store->comp_store = comp_store;
+               err = add_new_ctl(mixer, &snd_us16x08_meter_ctl,
+                       SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter",
+                       (void *) meter_store, snd_usb_mixer_elem_free, NULL);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
diff --git a/sound/usb/mixer_us16x08.h b/sound/usb/mixer_us16x08.h
new file mode 100644 (file)
index 0000000..64f89b5
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef __USB_MIXER_US16X08_H
+#define __USB_MIXER_US16X08_H
+
+#define SND_US16X08_MAX_CHANNELS 16
+
+/* define some bias, cause some alsa-mixers wont work with
+ * negative ranges or if mixer-min != 0
+ */
+#define SND_US16X08_NO_BIAS 0
+#define SND_US16X08_FADER_BIAS 127
+#define SND_US16X08_EQ_HIGHFREQ_BIAS 0x20
+#define SND_US16X08_COMP_THRESHOLD_BIAS 0x20
+#define SND_US16X08_COMP_ATTACK_BIAS 2
+#define SND_US16X08_COMP_RELEASE_BIAS 1
+
+/* get macro for components of kcontrol private_value */
+#define SND_US16X08_KCBIAS(x) (((x)->private_value >> 24) & 0xff)
+#define SND_US16X08_KCSTEP(x) (((x)->private_value >> 16) & 0xff)
+#define SND_US16X08_KCMIN(x) (((x)->private_value >> 8) & 0xff)
+#define SND_US16X08_KCMAX(x) (((x)->private_value >> 0) & 0xff)
+/* set macro for kcontrol private_value */
+#define SND_US16X08_KCSET(bias, step, min, max)  \
+       (((bias) << 24) | ((step) << 16) | ((min) << 8) | (max))
+
+/* the URB request/type to control Tascam mixers */
+#define SND_US16X08_URB_REQUEST 0x1D
+#define SND_US16X08_URB_REQUESTTYPE 0x40
+
+/* the URB params to retrieve meter ranges */
+#define SND_US16X08_URB_METER_REQUEST       0x1e
+#define SND_US16X08_URB_METER_REQUESTTYPE   0xc0
+
+#define MUA0(x, y) ((x)[(y) * 10 + 4])
+#define MUA1(x, y) ((x)[(y) * 10 + 5])
+#define MUA2(x, y) ((x)[(y) * 10 + 6])
+#define MUB0(x, y) ((x)[(y) * 10 + 7])
+#define MUB1(x, y) ((x)[(y) * 10 + 8])
+#define MUB2(x, y) ((x)[(y) * 10 + 9])
+#define MUC0(x, y) ((x)[(y) * 10 + 10])
+#define MUC1(x, y) ((x)[(y) * 10 + 11])
+#define MUC2(x, y) ((x)[(y) * 10 + 12])
+#define MUC3(x, y) ((x)[(y) * 10 + 13])
+
+/* Common Channel control IDs */
+#define SND_US16X08_ID_BYPASS 0x45
+#define SND_US16X08_ID_BUSS_OUT 0x44
+#define SND_US16X08_ID_PHASE 0x85
+#define SND_US16X08_ID_MUTE 0x83
+#define SND_US16X08_ID_FADER 0x81
+#define SND_US16X08_ID_PAN 0x82
+#define SND_US16X08_ID_METER 0xB1
+
+#define SND_US16X08_ID_EQ_BAND_COUNT 4
+#define SND_US16X08_ID_EQ_PARAM_COUNT 4
+
+/* EQ level IDs */
+#define SND_US16X08_ID_EQLOWLEVEL 0x01
+#define SND_US16X08_ID_EQLOWMIDLEVEL 0x02
+#define SND_US16X08_ID_EQHIGHMIDLEVEL 0x03
+#define SND_US16X08_ID_EQHIGHLEVEL 0x04
+
+/* EQ frequence IDs */
+#define SND_US16X08_ID_EQLOWFREQ 0x11
+#define SND_US16X08_ID_EQLOWMIDFREQ 0x12
+#define SND_US16X08_ID_EQHIGHMIDFREQ 0x13
+#define SND_US16X08_ID_EQHIGHFREQ 0x14
+
+/* EQ width IDs */
+#define SND_US16X08_ID_EQLOWMIDWIDTH 0x22
+#define SND_US16X08_ID_EQHIGHMIDWIDTH 0x23
+
+#define SND_US16X08_ID_EQENABLE 0x30
+
+#define EQ_STORE_BAND_IDX(x) ((x) & 0xf)
+#define EQ_STORE_PARAM_IDX(x) (((x) & 0xf0) >> 4)
+
+#define SND_US16X08_ID_ROUTE 0x00
+
+/* Compressor Ids */
+#define SND_US16X08_ID_COMP_BASE       0x32
+#define SND_US16X08_ID_COMP_THRESHOLD  SND_US16X08_ID_COMP_BASE
+#define SND_US16X08_ID_COMP_RATIO      (SND_US16X08_ID_COMP_BASE + 1)
+#define SND_US16X08_ID_COMP_ATTACK     (SND_US16X08_ID_COMP_BASE + 2)
+#define SND_US16X08_ID_COMP_RELEASE    (SND_US16X08_ID_COMP_BASE + 3)
+#define SND_US16X08_ID_COMP_GAIN       (SND_US16X08_ID_COMP_BASE + 4)
+#define SND_US16X08_ID_COMP_SWITCH     (SND_US16X08_ID_COMP_BASE + 5)
+#define SND_US16X08_ID_COMP_COUNT      6
+
+#define COMP_STORE_IDX(x) ((x) - SND_US16X08_ID_COMP_BASE)
+
+struct snd_us16x08_eq_store {
+       u8 val[SND_US16X08_ID_EQ_BAND_COUNT][SND_US16X08_ID_EQ_PARAM_COUNT]
+               [SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_comp_store {
+       u8 val[SND_US16X08_ID_COMP_COUNT][SND_US16X08_MAX_CHANNELS];
+};
+
+struct snd_us16x08_meter_store {
+       int meter_level[SND_US16X08_MAX_CHANNELS];
+       int master_level[2]; /* level of meter for master output */
+       int comp_index; /* round trip channel selector */
+       int comp_active_index; /* channel select from user space mixer */
+       int comp_level[16]; /* compressor reduction level */
+       struct snd_us16x08_comp_store *comp_store;
+};
+
+struct snd_us16x08_control_params {
+       struct snd_kcontrol_new *kcontrol_new;
+       int control_id;
+       int type;
+       int num_channels;
+       const char *name;
+       void (*freeer)(struct snd_kcontrol *kctl);
+       int default_val;
+};
+
+#define snd_us16x08_switch_info snd_ctl_boolean_mono_info
+
+int snd_us16x08_controls_create(struct usb_mixer_interface *mixer);
+#endif /* __USB_MIXER_US16X08_H */
index eb4b9f7a571e0f154fd7e00b81ef2c5ff7a17130..01eff6ce6401a3f8c6c8b51da93524f635bba86a 100644 (file)
@@ -1360,6 +1360,21 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
                if (fp->altsetting == 3)
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
+
+       /* Amanero Combo384 USB interface with native DSD support */
+       case USB_ID(0x16d0, 0x071a):
+               if (fp->altsetting == 2) {
+                       switch (chip->dev->descriptor.bcdDevice) {
+                       case 0x199:
+                               return SNDRV_PCM_FMTBIT_DSD_U32_LE;
+                       case 0x19b:
+                               return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+                       default:
+                               break;
+                       }
+               }
+               break;
+
        default:
                break;
        }
diff --git a/sound/x86/Kconfig b/sound/x86/Kconfig
new file mode 100644 (file)
index 0000000..30d066e
--- /dev/null
@@ -0,0 +1,15 @@
+menuconfig SND_X86
+       tristate "X86 sound devices"
+       depends on X86
+       ---help---
+         X86 sound devices that don't fall under SoC or PCI categories
+
+if SND_X86
+
+config HDMI_LPE_AUDIO
+       tristate "HDMI audio without HDaudio on Intel Atom platforms"
+       depends on DRM_I915
+       help
+        Choose this option to support HDMI LPE Audio mode
+
+endif  # SND_X86
diff --git a/sound/x86/Makefile b/sound/x86/Makefile
new file mode 100644 (file)
index 0000000..7ff9198
--- /dev/null
@@ -0,0 +1,4 @@
+snd-hdmi-lpe-audio-objs += \
+       intel_hdmi_audio.o
+
+obj-$(CONFIG_HDMI_LPE_AUDIO) += snd-hdmi-lpe-audio.o
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
new file mode 100644 (file)
index 0000000..360cff3
--- /dev/null
@@ -0,0 +1,1851 @@
+/*
+ *   intel_hdmi_audio.c - Intel HDMI audio driver
+ *
+ *  Copyright (C) 2016 Intel Corp
+ *  Authors:   Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ *             Ramesh Babu K V <ramesh.babu@intel.com>
+ *             Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ *             Jerome Anand <jerome.anand@intel.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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * ALSA driver for Intel HDMI audio
+ */
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <asm/cacheflush.h>
+#include <sound/core.h>
+#include <sound/asoundef.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/jack.h>
+#include <drm/drm_edid.h>
+#include <drm/intel_lpe_audio.h>
+#include "intel_hdmi_audio.h"
+
+/*standard module options for ALSA. This module supports only one card*/
+static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
+static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
+
+module_param_named(index, hdmi_card_index, int, 0444);
+MODULE_PARM_DESC(index,
+               "Index value for INTEL Intel HDMI Audio controller.");
+module_param_named(id, hdmi_card_id, charp, 0444);
+MODULE_PARM_DESC(id,
+               "ID string for INTEL Intel HDMI Audio controller.");
+
+/*
+ * ELD SA bits in the CEA Speaker Allocation data block
+ */
+static const int eld_speaker_allocation_bits[] = {
+       [0] = FL | FR,
+       [1] = LFE,
+       [2] = FC,
+       [3] = RL | RR,
+       [4] = RC,
+       [5] = FLC | FRC,
+       [6] = RLC | RRC,
+       /* the following are not defined in ELD yet */
+       [7] = 0,
+};
+
+/*
+ * This is an ordered list!
+ *
+ * The preceding ones have better chances to be selected by
+ * hdmi_channel_allocation().
+ */
+static struct cea_channel_speaker_allocation channel_allocations[] = {
+/*                        channel:   7     6    5    4    3     2    1    0  */
+{ .ca_index = 0x00,  .speakers = {   0,    0,   0,   0,   0,    0,  FR,  FL } },
+                               /* 2.1 */
+{ .ca_index = 0x01,  .speakers = {   0,    0,   0,   0,   0,  LFE,  FR,  FL } },
+                               /* Dolby Surround */
+{ .ca_index = 0x02,  .speakers = {   0,    0,   0,   0,  FC,    0,  FR,  FL } },
+                               /* surround40 */
+{ .ca_index = 0x08,  .speakers = {   0,    0,  RR,  RL,   0,    0,  FR,  FL } },
+                               /* surround41 */
+{ .ca_index = 0x09,  .speakers = {   0,    0,  RR,  RL,   0,  LFE,  FR,  FL } },
+                               /* surround50 */
+{ .ca_index = 0x0a,  .speakers = {   0,    0,  RR,  RL,  FC,    0,  FR,  FL } },
+                               /* surround51 */
+{ .ca_index = 0x0b,  .speakers = {   0,    0,  RR,  RL,  FC,  LFE,  FR,  FL } },
+                               /* 6.1 */
+{ .ca_index = 0x0f,  .speakers = {   0,   RC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+                               /* surround71 */
+{ .ca_index = 0x13,  .speakers = { RRC,  RLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+
+{ .ca_index = 0x03,  .speakers = {   0,    0,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x04,  .speakers = {   0,    0,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x05,  .speakers = {   0,    0,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x06,  .speakers = {   0,    0,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x07,  .speakers = {   0,    0,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x0c,  .speakers = {   0,   RC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x0d,  .speakers = {   0,   RC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x0e,  .speakers = {   0,   RC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x10,  .speakers = { RRC,  RLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x11,  .speakers = { RRC,  RLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x12,  .speakers = { RRC,  RLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x14,  .speakers = { FRC,  FLC,   0,   0,   0,    0,  FR,  FL } },
+{ .ca_index = 0x15,  .speakers = { FRC,  FLC,   0,   0,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x16,  .speakers = { FRC,  FLC,   0,   0,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x17,  .speakers = { FRC,  FLC,   0,   0,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x18,  .speakers = { FRC,  FLC,   0,  RC,   0,    0,  FR,  FL } },
+{ .ca_index = 0x19,  .speakers = { FRC,  FLC,   0,  RC,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1a,  .speakers = { FRC,  FLC,   0,  RC,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1b,  .speakers = { FRC,  FLC,   0,  RC,  FC,  LFE,  FR,  FL } },
+{ .ca_index = 0x1c,  .speakers = { FRC,  FLC,  RR,  RL,   0,    0,  FR,  FL } },
+{ .ca_index = 0x1d,  .speakers = { FRC,  FLC,  RR,  RL,   0,  LFE,  FR,  FL } },
+{ .ca_index = 0x1e,  .speakers = { FRC,  FLC,  RR,  RL,  FC,    0,  FR,  FL } },
+{ .ca_index = 0x1f,  .speakers = { FRC,  FLC,  RR,  RL,  FC,  LFE,  FR,  FL } },
+};
+
+static const struct channel_map_table map_tables[] = {
+       { SNDRV_CHMAP_FL,       0x00,   FL },
+       { SNDRV_CHMAP_FR,       0x01,   FR },
+       { SNDRV_CHMAP_RL,       0x04,   RL },
+       { SNDRV_CHMAP_RR,       0x05,   RR },
+       { SNDRV_CHMAP_LFE,      0x02,   LFE },
+       { SNDRV_CHMAP_FC,       0x03,   FC },
+       { SNDRV_CHMAP_RLC,      0x06,   RLC },
+       { SNDRV_CHMAP_RRC,      0x07,   RRC },
+       {} /* terminator */
+};
+
+/* hardware capability structure */
+static const struct snd_pcm_hardware had_pcm_hardware = {
+       .info = (SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID |
+               SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+       .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+                   SNDRV_PCM_FMTBIT_S24_LE |
+                   SNDRV_PCM_FMTBIT_S32_LE),
+       .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,
+       .rate_min = HAD_MIN_RATE,
+       .rate_max = HAD_MAX_RATE,
+       .channels_min = HAD_MIN_CHANNEL,
+       .channels_max = HAD_MAX_CHANNEL,
+       .buffer_bytes_max = HAD_MAX_BUFFER,
+       .period_bytes_min = HAD_MIN_PERIOD_BYTES,
+       .period_bytes_max = HAD_MAX_PERIOD_BYTES,
+       .periods_min = HAD_MIN_PERIODS,
+       .periods_max = HAD_MAX_PERIODS,
+       .fifo_size = HAD_FIFO_SIZE,
+};
+
+/* Get the active PCM substream;
+ * Call had_substream_put() for unreferecing.
+ * Don't call this inside had_spinlock, as it takes by itself
+ */
+static struct snd_pcm_substream *
+had_substream_get(struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_substream *substream;
+       unsigned long flags;
+
+       spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
+       substream = intelhaddata->stream_info.substream;
+       if (substream)
+               intelhaddata->stream_info.substream_refcount++;
+       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+       return substream;
+}
+
+/* Unref the active PCM substream;
+ * Don't call this inside had_spinlock, as it takes by itself
+ */
+static void had_substream_put(struct snd_intelhad *intelhaddata)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
+       intelhaddata->stream_info.substream_refcount--;
+       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+}
+
+/* Register access functions */
+static u32 had_read_register_raw(struct snd_intelhad *ctx, u32 reg)
+{
+       return ioread32(ctx->mmio_start + ctx->had_config_offset + reg);
+}
+
+static void had_write_register_raw(struct snd_intelhad *ctx, u32 reg, u32 val)
+{
+       iowrite32(val, ctx->mmio_start + ctx->had_config_offset + reg);
+}
+
+static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val)
+{
+       if (!ctx->connected)
+               *val = 0;
+       else
+               *val = had_read_register_raw(ctx, reg);
+}
+
+static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
+{
+       if (ctx->connected)
+               had_write_register_raw(ctx, reg, val);
+}
+
+/*
+ * enable / disable audio configuration
+ *
+ * The normal read/modify should not directly be used on VLV2 for
+ * updating AUD_CONFIG register.
+ * This is because:
+ * Bit6 of AUD_CONFIG register is writeonly due to a silicon bug on VLV2
+ * HDMI IP. As a result a read-modify of AUD_CONFIG regiter will always
+ * clear bit6. AUD_CONFIG[6:4] represents the "channels" field of the
+ * register. This field should be 1xy binary for configuration with 6 or
+ * more channels. Read-modify of AUD_CONFIG (Eg. for enabling audio)
+ * causes the "channels" field to be updated as 0xy binary resulting in
+ * bad audio. The fix is to always write the AUD_CONFIG[6:4] with
+ * appropriate value when doing read-modify of AUD_CONFIG register.
+ */
+static void had_enable_audio(struct snd_intelhad *intelhaddata,
+                            bool enable)
+{
+       /* update the cached value */
+       intelhaddata->aud_config.regx.aud_en = enable;
+       had_write_register(intelhaddata, AUD_CONFIG,
+                          intelhaddata->aud_config.regval);
+}
+
+/* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */
+static void had_ack_irqs(struct snd_intelhad *ctx)
+{
+       u32 status_reg;
+
+       if (!ctx->connected)
+               return;
+       had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
+       status_reg |= HDMI_AUDIO_BUFFER_DONE | HDMI_AUDIO_UNDERRUN;
+       had_write_register(ctx, AUD_HDMI_STATUS, status_reg);
+       had_read_register(ctx, AUD_HDMI_STATUS, &status_reg);
+}
+
+/* Reset buffer pointers */
+static void had_reset_audio(struct snd_intelhad *intelhaddata)
+{
+       had_write_register(intelhaddata, AUD_HDMI_STATUS,
+                          AUD_HDMI_STATUSG_MASK_FUNCRST);
+       had_write_register(intelhaddata, AUD_HDMI_STATUS, 0);
+}
+
+/*
+ * initialize audio channel status registers
+ * This function is called in the prepare callback
+ */
+static int had_prog_status_reg(struct snd_pcm_substream *substream,
+                       struct snd_intelhad *intelhaddata)
+{
+       union aud_cfg cfg_val = {.regval = 0};
+       union aud_ch_status_0 ch_stat0 = {.regval = 0};
+       union aud_ch_status_1 ch_stat1 = {.regval = 0};
+
+       ch_stat0.regx.lpcm_id = (intelhaddata->aes_bits &
+                                         IEC958_AES0_NONAUDIO) >> 1;
+       ch_stat0.regx.clk_acc = (intelhaddata->aes_bits &
+                                         IEC958_AES3_CON_CLOCK) >> 4;
+       cfg_val.regx.val_bit = ch_stat0.regx.lpcm_id;
+
+       switch (substream->runtime->rate) {
+       case AUD_SAMPLE_RATE_32:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_32KHZ;
+               break;
+
+       case AUD_SAMPLE_RATE_44_1:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_44KHZ;
+               break;
+       case AUD_SAMPLE_RATE_48:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_48KHZ;
+               break;
+       case AUD_SAMPLE_RATE_88_2:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_88KHZ;
+               break;
+       case AUD_SAMPLE_RATE_96:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_96KHZ;
+               break;
+       case AUD_SAMPLE_RATE_176_4:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_176KHZ;
+               break;
+       case AUD_SAMPLE_RATE_192:
+               ch_stat0.regx.samp_freq = CH_STATUS_MAP_192KHZ;
+               break;
+
+       default:
+               /* control should never come here */
+               return -EINVAL;
+       }
+
+       had_write_register(intelhaddata,
+                          AUD_CH_STATUS_0, ch_stat0.regval);
+
+       switch (substream->runtime->format) {
+       case SNDRV_PCM_FORMAT_S16_LE:
+               ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_20;
+               ch_stat1.regx.wrd_len = SMPL_WIDTH_16BITS;
+               break;
+       case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S32_LE:
+               ch_stat1.regx.max_wrd_len = MAX_SMPL_WIDTH_24;
+               ch_stat1.regx.wrd_len = SMPL_WIDTH_24BITS;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       had_write_register(intelhaddata,
+                          AUD_CH_STATUS_1, ch_stat1.regval);
+       return 0;
+}
+
+/*
+ * function to initialize audio
+ * registers and buffer confgiuration registers
+ * This function is called in the prepare callback
+ */
+static int had_init_audio_ctrl(struct snd_pcm_substream *substream,
+                              struct snd_intelhad *intelhaddata)
+{
+       union aud_cfg cfg_val = {.regval = 0};
+       union aud_buf_config buf_cfg = {.regval = 0};
+       u8 channels;
+
+       had_prog_status_reg(substream, intelhaddata);
+
+       buf_cfg.regx.audio_fifo_watermark = FIFO_THRESHOLD;
+       buf_cfg.regx.dma_fifo_watermark = DMA_FIFO_THRESHOLD;
+       buf_cfg.regx.aud_delay = 0;
+       had_write_register(intelhaddata, AUD_BUF_CONFIG, buf_cfg.regval);
+
+       channels = substream->runtime->channels;
+       cfg_val.regx.num_ch = channels - 2;
+       if (channels <= 2)
+               cfg_val.regx.layout = LAYOUT0;
+       else
+               cfg_val.regx.layout = LAYOUT1;
+
+       if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE)
+               cfg_val.regx.packet_mode = 1;
+
+       if (substream->runtime->format == SNDRV_PCM_FORMAT_S32_LE)
+               cfg_val.regx.left_align = 1;
+
+       cfg_val.regx.val_bit = 1;
+
+       /* fix up the DP bits */
+       if (intelhaddata->dp_output) {
+               cfg_val.regx.dp_modei = 1;
+               cfg_val.regx.set = 1;
+       }
+
+       had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval);
+       intelhaddata->aud_config = cfg_val;
+       return 0;
+}
+
+/*
+ * Compute derived values in channel_allocations[].
+ */
+static void init_channel_allocations(void)
+{
+       int i, j;
+       struct cea_channel_speaker_allocation *p;
+
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               p = channel_allocations + i;
+               p->channels = 0;
+               p->spk_mask = 0;
+               for (j = 0; j < ARRAY_SIZE(p->speakers); j++)
+                       if (p->speakers[j]) {
+                               p->channels++;
+                               p->spk_mask |= p->speakers[j];
+                       }
+       }
+}
+
+/*
+ * The transformation takes two steps:
+ *
+ *      eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask
+ *            spk_mask => (channel_allocations[])         => ai->CA
+ *
+ * TODO: it could select the wrong CA from multiple candidates.
+ */
+static int had_channel_allocation(struct snd_intelhad *intelhaddata,
+                                 int channels)
+{
+       int i;
+       int ca = 0;
+       int spk_mask = 0;
+
+       /*
+        * CA defaults to 0 for basic stereo audio
+        */
+       if (channels <= 2)
+               return 0;
+
+       /*
+        * expand ELD's speaker allocation mask
+        *
+        * ELD tells the speaker mask in a compact(paired) form,
+        * expand ELD's notions to match the ones used by Audio InfoFrame.
+        */
+
+       for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+               if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
+                       spk_mask |= eld_speaker_allocation_bits[i];
+       }
+
+       /* search for the first working match in the CA table */
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               if (channels == channel_allocations[i].channels &&
+               (spk_mask & channel_allocations[i].spk_mask) ==
+                               channel_allocations[i].spk_mask) {
+                       ca = channel_allocations[i].ca_index;
+                       break;
+               }
+       }
+
+       dev_dbg(intelhaddata->dev, "select CA 0x%x for %d\n", ca, channels);
+
+       return ca;
+}
+
+/* from speaker bit mask to ALSA API channel position */
+static int spk_to_chmap(int spk)
+{
+       const struct channel_map_table *t = map_tables;
+
+       for (; t->map; t++) {
+               if (t->spk_mask == spk)
+                       return t->map;
+       }
+       return 0;
+}
+
+static void had_build_channel_allocation_map(struct snd_intelhad *intelhaddata)
+{
+       int i, c;
+       int spk_mask = 0;
+       struct snd_pcm_chmap_elem *chmap;
+       u8 eld_high, eld_high_mask = 0xF0;
+       u8 high_msb;
+
+       kfree(intelhaddata->chmap->chmap);
+       intelhaddata->chmap->chmap = NULL;
+
+       chmap = kzalloc(sizeof(*chmap), GFP_KERNEL);
+       if (!chmap)
+               return;
+
+       dev_dbg(intelhaddata->dev, "eld speaker = %x\n",
+               intelhaddata->eld[DRM_ELD_SPEAKER]);
+
+       /* WA: Fix the max channel supported to 8 */
+
+       /*
+        * Sink may support more than 8 channels, if eld_high has more than
+        * one bit set. SOC supports max 8 channels.
+        * Refer eld_speaker_allocation_bits, for sink speaker allocation
+        */
+
+       /* if 0x2F < eld < 0x4F fall back to 0x2f, else fall back to 0x4F */
+       eld_high = intelhaddata->eld[DRM_ELD_SPEAKER] & eld_high_mask;
+       if ((eld_high & (eld_high-1)) && (eld_high > 0x1F)) {
+               /* eld_high & (eld_high-1): if more than 1 bit set */
+               /* 0x1F: 7 channels */
+               for (i = 1; i < 4; i++) {
+                       high_msb = eld_high & (0x80 >> i);
+                       if (high_msb) {
+                               intelhaddata->eld[DRM_ELD_SPEAKER] &=
+                                       high_msb | 0xF;
+                               break;
+                       }
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) {
+               if (intelhaddata->eld[DRM_ELD_SPEAKER] & (1 << i))
+                       spk_mask |= eld_speaker_allocation_bits[i];
+       }
+
+       for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) {
+               if (spk_mask == channel_allocations[i].spk_mask) {
+                       for (c = 0; c < channel_allocations[i].channels; c++) {
+                               chmap->map[c] = spk_to_chmap(
+                                       channel_allocations[i].speakers[
+                                               (MAX_SPEAKERS - 1) - c]);
+                       }
+                       chmap->channels = channel_allocations[i].channels;
+                       intelhaddata->chmap->chmap = chmap;
+                       break;
+               }
+       }
+       if (i >= ARRAY_SIZE(channel_allocations))
+               kfree(chmap);
+}
+
+/*
+ * ALSA API channel-map control callbacks
+ */
+static int had_chmap_ctl_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = HAD_MAX_CHANNEL;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = SNDRV_CHMAP_LAST;
+       return 0;
+}
+
+static int had_chmap_ctl_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
+       struct snd_intelhad *intelhaddata = info->private_data;
+       int i;
+       const struct snd_pcm_chmap_elem *chmap;
+
+       memset(ucontrol->value.integer.value, 0,
+              sizeof(long) * HAD_MAX_CHANNEL);
+       mutex_lock(&intelhaddata->mutex);
+       if (!intelhaddata->chmap->chmap) {
+               mutex_unlock(&intelhaddata->mutex);
+               return 0;
+       }
+
+       chmap = intelhaddata->chmap->chmap;
+       for (i = 0; i < chmap->channels; i++)
+               ucontrol->value.integer.value[i] = chmap->map[i];
+       mutex_unlock(&intelhaddata->mutex);
+
+       return 0;
+}
+
+static int had_register_chmap_ctls(struct snd_intelhad *intelhaddata,
+                                               struct snd_pcm *pcm)
+{
+       int err;
+
+       err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       NULL, 0, (unsigned long)intelhaddata,
+                       &intelhaddata->chmap);
+       if (err < 0)
+               return err;
+
+       intelhaddata->chmap->private_data = intelhaddata;
+       intelhaddata->chmap->kctl->info = had_chmap_ctl_info;
+       intelhaddata->chmap->kctl->get = had_chmap_ctl_get;
+       intelhaddata->chmap->chmap = NULL;
+       return 0;
+}
+
+/*
+ * Initialize Data Island Packets registers
+ * This function is called in the prepare callback
+ */
+static void had_prog_dip(struct snd_pcm_substream *substream,
+                        struct snd_intelhad *intelhaddata)
+{
+       int i;
+       union aud_ctrl_st ctrl_state = {.regval = 0};
+       union aud_info_frame2 frame2 = {.regval = 0};
+       union aud_info_frame3 frame3 = {.regval = 0};
+       u8 checksum = 0;
+       u32 info_frame;
+       int channels;
+       int ca;
+
+       channels = substream->runtime->channels;
+
+       had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
+
+       ca = had_channel_allocation(intelhaddata, channels);
+       if (intelhaddata->dp_output) {
+               info_frame = DP_INFO_FRAME_WORD1;
+               frame2.regval = (substream->runtime->channels - 1) | (ca << 24);
+       } else {
+               info_frame = HDMI_INFO_FRAME_WORD1;
+               frame2.regx.chnl_cnt = substream->runtime->channels - 1;
+               frame3.regx.chnl_alloc = ca;
+
+               /* Calculte the byte wide checksum for all valid DIP words */
+               for (i = 0; i < BYTES_PER_WORD; i++)
+                       checksum += (info_frame >> (i * 8)) & 0xff;
+               for (i = 0; i < BYTES_PER_WORD; i++)
+                       checksum += (frame2.regval >> (i * 8)) & 0xff;
+               for (i = 0; i < BYTES_PER_WORD; i++)
+                       checksum += (frame3.regval >> (i * 8)) & 0xff;
+
+               frame2.regx.chksum = -(checksum);
+       }
+
+       had_write_register(intelhaddata, AUD_HDMIW_INFOFR, info_frame);
+       had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame2.regval);
+       had_write_register(intelhaddata, AUD_HDMIW_INFOFR, frame3.regval);
+
+       /* program remaining DIP words with zero */
+       for (i = 0; i < HAD_MAX_DIP_WORDS-VALID_DIP_WORDS; i++)
+               had_write_register(intelhaddata, AUD_HDMIW_INFOFR, 0x0);
+
+       ctrl_state.regx.dip_freq = 1;
+       ctrl_state.regx.dip_en_sta = 1;
+       had_write_register(intelhaddata, AUD_CNTL_ST, ctrl_state.regval);
+}
+
+static int had_calculate_maud_value(u32 aud_samp_freq, u32 link_rate)
+{
+       u32 maud_val;
+
+       /* Select maud according to DP 1.2 spec */
+       if (link_rate == DP_2_7_GHZ) {
+               switch (aud_samp_freq) {
+               case AUD_SAMPLE_RATE_32:
+                       maud_val = AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_44_1:
+                       maud_val = AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_48:
+                       maud_val = AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_88_2:
+                       maud_val = AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_96:
+                       maud_val = AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_176_4:
+                       maud_val = AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL;
+                       break;
+
+               case HAD_MAX_RATE:
+                       maud_val = HAD_MAX_RATE_DP_2_7_MAUD_VAL;
+                       break;
+
+               default:
+                       maud_val = -EINVAL;
+                       break;
+               }
+       } else if (link_rate == DP_1_62_GHZ) {
+               switch (aud_samp_freq) {
+               case AUD_SAMPLE_RATE_32:
+                       maud_val = AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_44_1:
+                       maud_val = AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_48:
+                       maud_val = AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_88_2:
+                       maud_val = AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_96:
+                       maud_val = AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL;
+                       break;
+
+               case AUD_SAMPLE_RATE_176_4:
+                       maud_val = AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL;
+                       break;
+
+               case HAD_MAX_RATE:
+                       maud_val = HAD_MAX_RATE_DP_1_62_MAUD_VAL;
+                       break;
+
+               default:
+                       maud_val = -EINVAL;
+                       break;
+               }
+       } else
+               maud_val = -EINVAL;
+
+       return maud_val;
+}
+
+/*
+ * Program HDMI audio CTS value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @tmds: sampling frequency of the display data
+ * @link_rate: DP link rate
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata: substream private data
+ *
+ * Program CTS register based on the audio and display sampling frequency
+ */
+static void had_prog_cts(u32 aud_samp_freq, u32 tmds, u32 link_rate,
+                        u32 n_param, struct snd_intelhad *intelhaddata)
+{
+       u32 cts_val;
+       u64 dividend, divisor;
+
+       if (intelhaddata->dp_output) {
+               /* Substitute cts_val with Maud according to DP 1.2 spec*/
+               cts_val = had_calculate_maud_value(aud_samp_freq, link_rate);
+       } else {
+               /* Calculate CTS according to HDMI 1.3a spec*/
+               dividend = (u64)tmds * n_param*1000;
+               divisor = 128 * aud_samp_freq;
+               cts_val = div64_u64(dividend, divisor);
+       }
+       dev_dbg(intelhaddata->dev, "TMDS value=%d, N value=%d, CTS Value=%d\n",
+                tmds, n_param, cts_val);
+       had_write_register(intelhaddata, AUD_HDMI_CTS, (BIT(24) | cts_val));
+}
+
+static int had_calculate_n_value(u32 aud_samp_freq)
+{
+       int n_val;
+
+       /* Select N according to HDMI 1.3a spec*/
+       switch (aud_samp_freq) {
+       case AUD_SAMPLE_RATE_32:
+               n_val = 4096;
+               break;
+
+       case AUD_SAMPLE_RATE_44_1:
+               n_val = 6272;
+               break;
+
+       case AUD_SAMPLE_RATE_48:
+               n_val = 6144;
+               break;
+
+       case AUD_SAMPLE_RATE_88_2:
+               n_val = 12544;
+               break;
+
+       case AUD_SAMPLE_RATE_96:
+               n_val = 12288;
+               break;
+
+       case AUD_SAMPLE_RATE_176_4:
+               n_val = 25088;
+               break;
+
+       case HAD_MAX_RATE:
+               n_val = 24576;
+               break;
+
+       default:
+               n_val = -EINVAL;
+               break;
+       }
+       return n_val;
+}
+
+/*
+ * Program HDMI audio N value
+ *
+ * @aud_samp_freq: sampling frequency of audio data
+ * @n_param: N value, depends on aud_samp_freq
+ * @intelhaddata: substream private data
+ *
+ * This function is called in the prepare callback.
+ * It programs based on the audio and display sampling frequency
+ */
+static int had_prog_n(u32 aud_samp_freq, u32 *n_param,
+                     struct snd_intelhad *intelhaddata)
+{
+       int n_val;
+
+       if (intelhaddata->dp_output) {
+               /*
+                * According to DP specs, Maud and Naud values hold
+                * a relationship, which is stated as:
+                * Maud/Naud = 512 * fs / f_LS_Clk
+                * where, fs is the sampling frequency of the audio stream
+                * and Naud is 32768 for Async clock.
+                */
+
+               n_val = DP_NAUD_VAL;
+       } else
+               n_val = had_calculate_n_value(aud_samp_freq);
+
+       if (n_val < 0)
+               return n_val;
+
+       had_write_register(intelhaddata, AUD_N_ENABLE, (BIT(24) | n_val));
+       *n_param = n_val;
+       return 0;
+}
+
+/*
+ * PCM ring buffer handling
+ *
+ * The hardware provides a ring buffer with the fixed 4 buffer descriptors
+ * (BDs).  The driver maps these 4 BDs onto the PCM ring buffer.  The mapping
+ * moves at each period elapsed.  The below illustrates how it works:
+ *
+ * At time=0
+ *  PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ *  BD  | 0 | 1 | 2 | 3 |
+ *
+ * At time=1 (period elapsed)
+ *  PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ *  BD      | 1 | 2 | 3 | 0 |
+ *
+ * At time=2 (second period elapsed)
+ *  PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ *  BD          | 2 | 3 | 0 | 1 |
+ *
+ * The bd_head field points to the index of the BD to be read.  It's also the
+ * position to be filled at next.  The pcm_head and the pcm_filled fields
+ * point to the indices of the current position and of the next position to
+ * be filled, respectively.  For PCM buffer there are both _head and _filled
+ * because they may be difference when nperiods > 4.  For example, in the
+ * example above at t=1, bd_head=1 and pcm_head=1 while pcm_filled=5:
+ *
+ * pcm_head (=1) --v               v-- pcm_filled (=5)
+ *       PCM | 0 | 1 | 2 | 3 | 4 | 5 | .... |n-1|
+ *       BD      | 1 | 2 | 3 | 0 |
+ *  bd_head (=1) --^               ^-- next to fill (= bd_head)
+ *
+ * For nperiods < 4, the remaining BDs out of 4 are marked as invalid, so that
+ * the hardware skips those BDs in the loop.
+ *
+ * An exceptional setup is the case with nperiods=1.  Since we have to update
+ * BDs after finishing one BD processing, we'd need at least two BDs, where
+ * both BDs point to the same content, the same address, the same size of the
+ * whole PCM buffer.
+ */
+
+#define AUD_BUF_ADDR(x)                (AUD_BUF_A_ADDR + (x) * HAD_REG_WIDTH)
+#define AUD_BUF_LEN(x)         (AUD_BUF_A_LENGTH + (x) * HAD_REG_WIDTH)
+
+/* Set up a buffer descriptor at the "filled" position */
+static void had_prog_bd(struct snd_pcm_substream *substream,
+                       struct snd_intelhad *intelhaddata)
+{
+       int idx = intelhaddata->bd_head;
+       int ofs = intelhaddata->pcmbuf_filled * intelhaddata->period_bytes;
+       u32 addr = substream->runtime->dma_addr + ofs;
+
+       addr |= AUD_BUF_VALID;
+       if (!substream->runtime->no_period_wakeup)
+               addr |= AUD_BUF_INTR_EN;
+       had_write_register(intelhaddata, AUD_BUF_ADDR(idx), addr);
+       had_write_register(intelhaddata, AUD_BUF_LEN(idx),
+                          intelhaddata->period_bytes);
+
+       /* advance the indices to the next */
+       intelhaddata->bd_head++;
+       intelhaddata->bd_head %= intelhaddata->num_bds;
+       intelhaddata->pcmbuf_filled++;
+       intelhaddata->pcmbuf_filled %= substream->runtime->periods;
+}
+
+/* invalidate a buffer descriptor with the given index */
+static void had_invalidate_bd(struct snd_intelhad *intelhaddata,
+                             int idx)
+{
+       had_write_register(intelhaddata, AUD_BUF_ADDR(idx), 0);
+       had_write_register(intelhaddata, AUD_BUF_LEN(idx), 0);
+}
+
+/* Initial programming of ring buffer */
+static void had_init_ringbuf(struct snd_pcm_substream *substream,
+                            struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int i, num_periods;
+
+       num_periods = runtime->periods;
+       intelhaddata->num_bds = min(num_periods, HAD_NUM_OF_RING_BUFS);
+       /* set the minimum 2 BDs for num_periods=1 */
+       intelhaddata->num_bds = max(intelhaddata->num_bds, 2U);
+       intelhaddata->period_bytes =
+               frames_to_bytes(runtime, runtime->period_size);
+       WARN_ON(intelhaddata->period_bytes & 0x3f);
+
+       intelhaddata->bd_head = 0;
+       intelhaddata->pcmbuf_head = 0;
+       intelhaddata->pcmbuf_filled = 0;
+
+       for (i = 0; i < HAD_NUM_OF_RING_BUFS; i++) {
+               if (i < intelhaddata->num_bds)
+                       had_prog_bd(substream, intelhaddata);
+               else /* invalidate the rest */
+                       had_invalidate_bd(intelhaddata, i);
+       }
+
+       intelhaddata->bd_head = 0; /* reset at head again before starting */
+}
+
+/* process a bd, advance to the next */
+static void had_advance_ringbuf(struct snd_pcm_substream *substream,
+                               struct snd_intelhad *intelhaddata)
+{
+       int num_periods = substream->runtime->periods;
+
+       /* reprogram the next buffer */
+       had_prog_bd(substream, intelhaddata);
+
+       /* proceed to next */
+       intelhaddata->pcmbuf_head++;
+       intelhaddata->pcmbuf_head %= num_periods;
+}
+
+/* process the current BD(s);
+ * returns the current PCM buffer byte position, or -EPIPE for underrun.
+ */
+static int had_process_ringbuf(struct snd_pcm_substream *substream,
+                              struct snd_intelhad *intelhaddata)
+{
+       int len, processed;
+       unsigned long flags;
+
+       processed = 0;
+       spin_lock_irqsave(&intelhaddata->had_spinlock, flags);
+       for (;;) {
+               /* get the remaining bytes on the buffer */
+               had_read_register(intelhaddata,
+                                 AUD_BUF_LEN(intelhaddata->bd_head),
+                                 &len);
+               if (len < 0 || len > intelhaddata->period_bytes) {
+                       dev_dbg(intelhaddata->dev, "Invalid buf length %d\n",
+                               len);
+                       len = -EPIPE;
+                       goto out;
+               }
+
+               if (len > 0) /* OK, this is the current buffer */
+                       break;
+
+               /* len=0 => already empty, check the next buffer */
+               if (++processed >= intelhaddata->num_bds) {
+                       len = -EPIPE; /* all empty? - report underrun */
+                       goto out;
+               }
+               had_advance_ringbuf(substream, intelhaddata);
+       }
+
+       len = intelhaddata->period_bytes - len;
+       len += intelhaddata->period_bytes * intelhaddata->pcmbuf_head;
+ out:
+       spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+       return len;
+}
+
+/* called from irq handler */
+static void had_process_buffer_done(struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_substream *substream;
+
+       substream = had_substream_get(intelhaddata);
+       if (!substream)
+               return; /* no stream? - bail out */
+
+       if (!intelhaddata->connected) {
+               snd_pcm_stop_xrun(substream);
+               goto out; /* disconnected? - bail out */
+       }
+
+       /* process or stop the stream */
+       if (had_process_ringbuf(substream, intelhaddata) < 0)
+               snd_pcm_stop_xrun(substream);
+       else
+               snd_pcm_period_elapsed(substream);
+
+ out:
+       had_substream_put(intelhaddata);
+}
+
+/*
+ * The interrupt status 'sticky' bits might not be cleared by
+ * setting '1' to that bit once...
+ */
+static void wait_clear_underrun_bit(struct snd_intelhad *intelhaddata)
+{
+       int i;
+       u32 val;
+
+       for (i = 0; i < 100; i++) {
+               /* clear bit30, 31 AUD_HDMI_STATUS */
+               had_read_register(intelhaddata, AUD_HDMI_STATUS, &val);
+               if (!(val & AUD_HDMI_STATUS_MASK_UNDERRUN))
+                       return;
+               udelay(100);
+               cond_resched();
+               had_write_register(intelhaddata, AUD_HDMI_STATUS, val);
+       }
+       dev_err(intelhaddata->dev, "Unable to clear UNDERRUN bits\n");
+}
+
+/* Perform some reset procedure but only when need_reset is set;
+ * this is called from prepare or hw_free callbacks once after trigger STOP
+ * or underrun has been processed in order to settle down the h/w state.
+ */
+static void had_do_reset(struct snd_intelhad *intelhaddata)
+{
+       if (!intelhaddata->need_reset || !intelhaddata->connected)
+               return;
+
+       /* Reset buffer pointers */
+       had_reset_audio(intelhaddata);
+       wait_clear_underrun_bit(intelhaddata);
+       intelhaddata->need_reset = false;
+}
+
+/* called from irq handler */
+static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_substream *substream;
+
+       /* Report UNDERRUN error to above layers */
+       substream = had_substream_get(intelhaddata);
+       if (substream) {
+               snd_pcm_stop_xrun(substream);
+               had_substream_put(intelhaddata);
+       }
+       intelhaddata->need_reset = true;
+}
+
+/*
+ * ALSA PCM open callback
+ */
+static int had_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_intelhad *intelhaddata;
+       struct snd_pcm_runtime *runtime;
+       int retval;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       pm_runtime_get_sync(intelhaddata->dev);
+
+       /* set the runtime hw parameter with local snd_pcm_hardware struct */
+       runtime->hw = had_pcm_hardware;
+
+       retval = snd_pcm_hw_constraint_integer(runtime,
+                        SNDRV_PCM_HW_PARAM_PERIODS);
+       if (retval < 0)
+               goto error;
+
+       /* Make sure, that the period size is always aligned
+        * 64byte boundary
+        */
+       retval = snd_pcm_hw_constraint_step(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64);
+       if (retval < 0)
+               goto error;
+
+       retval = snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24);
+       if (retval < 0)
+               goto error;
+
+       /* expose PCM substream */
+       spin_lock_irq(&intelhaddata->had_spinlock);
+       intelhaddata->stream_info.substream = substream;
+       intelhaddata->stream_info.substream_refcount++;
+       spin_unlock_irq(&intelhaddata->had_spinlock);
+
+       return retval;
+ error:
+       pm_runtime_put(intelhaddata->dev);
+       return retval;
+}
+
+/*
+ * ALSA PCM close callback
+ */
+static int had_pcm_close(struct snd_pcm_substream *substream)
+{
+       struct snd_intelhad *intelhaddata;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+
+       /* unreference and sync with the pending PCM accesses */
+       spin_lock_irq(&intelhaddata->had_spinlock);
+       intelhaddata->stream_info.substream = NULL;
+       intelhaddata->stream_info.substream_refcount--;
+       while (intelhaddata->stream_info.substream_refcount > 0) {
+               spin_unlock_irq(&intelhaddata->had_spinlock);
+               cpu_relax();
+               spin_lock_irq(&intelhaddata->had_spinlock);
+       }
+       spin_unlock_irq(&intelhaddata->had_spinlock);
+
+       pm_runtime_put(intelhaddata->dev);
+       return 0;
+}
+
+/*
+ * ALSA PCM hw_params callback
+ */
+static int had_pcm_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *hw_params)
+{
+       struct snd_intelhad *intelhaddata;
+       unsigned long addr;
+       int pages, buf_size, retval;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+       buf_size = params_buffer_bytes(hw_params);
+       retval = snd_pcm_lib_malloc_pages(substream, buf_size);
+       if (retval < 0)
+               return retval;
+       dev_dbg(intelhaddata->dev, "%s:allocated memory = %d\n",
+               __func__, buf_size);
+       /* mark the pages as uncached region */
+       addr = (unsigned long) substream->runtime->dma_area;
+       pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+       retval = set_memory_uc(addr, pages);
+       if (retval) {
+               dev_err(intelhaddata->dev, "set_memory_uc failed.Error:%d\n",
+                       retval);
+               return retval;
+       }
+       memset(substream->runtime->dma_area, 0, buf_size);
+
+       return retval;
+}
+
+/*
+ * ALSA PCM hw_free callback
+ */
+static int had_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_intelhad *intelhaddata;
+       unsigned long addr;
+       u32 pages;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+       had_do_reset(intelhaddata);
+
+       /* mark back the pages as cached/writeback region before the free */
+       if (substream->runtime->dma_area != NULL) {
+               addr = (unsigned long) substream->runtime->dma_area;
+               pages = (substream->runtime->dma_bytes + PAGE_SIZE - 1) /
+                                                               PAGE_SIZE;
+               set_memory_wb(addr, pages);
+               return snd_pcm_lib_free_pages(substream);
+       }
+       return 0;
+}
+
+/*
+ * ALSA PCM trigger callback
+ */
+static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       int retval = 0;
+       struct snd_intelhad *intelhaddata;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+
+       spin_lock(&intelhaddata->had_spinlock);
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+       case SNDRV_PCM_TRIGGER_RESUME:
+               /* Enable Audio */
+               had_ack_irqs(intelhaddata); /* FIXME: do we need this? */
+               had_enable_audio(intelhaddata, true);
+               break;
+
+       case SNDRV_PCM_TRIGGER_STOP:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               /* Disable Audio */
+               had_enable_audio(intelhaddata, false);
+               intelhaddata->need_reset = true;
+               break;
+
+       default:
+               retval = -EINVAL;
+       }
+       spin_unlock(&intelhaddata->had_spinlock);
+       return retval;
+}
+
+/*
+ * ALSA PCM prepare callback
+ */
+static int had_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       int retval;
+       u32 disp_samp_freq, n_param;
+       u32 link_rate = 0;
+       struct snd_intelhad *intelhaddata;
+       struct snd_pcm_runtime *runtime;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+       runtime = substream->runtime;
+
+       dev_dbg(intelhaddata->dev, "period_size=%d\n",
+               (int)frames_to_bytes(runtime, runtime->period_size));
+       dev_dbg(intelhaddata->dev, "periods=%d\n", runtime->periods);
+       dev_dbg(intelhaddata->dev, "buffer_size=%d\n",
+               (int)snd_pcm_lib_buffer_bytes(substream));
+       dev_dbg(intelhaddata->dev, "rate=%d\n", runtime->rate);
+       dev_dbg(intelhaddata->dev, "channels=%d\n", runtime->channels);
+
+       had_do_reset(intelhaddata);
+
+       /* Get N value in KHz */
+       disp_samp_freq = intelhaddata->tmds_clock_speed;
+
+       retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
+       if (retval) {
+               dev_err(intelhaddata->dev,
+                       "programming N value failed %#x\n", retval);
+               goto prep_end;
+       }
+
+       if (intelhaddata->dp_output)
+               link_rate = intelhaddata->link_rate;
+
+       had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
+                    n_param, intelhaddata);
+
+       had_prog_dip(substream, intelhaddata);
+
+       retval = had_init_audio_ctrl(substream, intelhaddata);
+
+       /* Prog buffer address */
+       had_init_ringbuf(substream, intelhaddata);
+
+       /*
+        * Program channel mapping in following order:
+        * FL, FR, C, LFE, RL, RR
+        */
+
+       had_write_register(intelhaddata, AUD_BUF_CH_SWAP, SWAP_LFE_CENTER);
+
+prep_end:
+       return retval;
+}
+
+/*
+ * ALSA PCM pointer callback
+ */
+static snd_pcm_uframes_t had_pcm_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_intelhad *intelhaddata;
+       int len;
+
+       intelhaddata = snd_pcm_substream_chip(substream);
+
+       if (!intelhaddata->connected)
+               return SNDRV_PCM_POS_XRUN;
+
+       len = had_process_ringbuf(substream, intelhaddata);
+       if (len < 0)
+               return SNDRV_PCM_POS_XRUN;
+       len = bytes_to_frames(substream->runtime, len);
+       /* wrapping may happen when periods=1 */
+       len %= substream->runtime->buffer_size;
+       return len;
+}
+
+/*
+ * ALSA PCM mmap callback
+ */
+static int had_pcm_mmap(struct snd_pcm_substream *substream,
+                       struct vm_area_struct *vma)
+{
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       return remap_pfn_range(vma, vma->vm_start,
+                       substream->dma_buffer.addr >> PAGE_SHIFT,
+                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+/*
+ * ALSA PCM ops
+ */
+static const struct snd_pcm_ops had_pcm_ops = {
+       .open =         had_pcm_open,
+       .close =        had_pcm_close,
+       .ioctl =        snd_pcm_lib_ioctl,
+       .hw_params =    had_pcm_hw_params,
+       .hw_free =      had_pcm_hw_free,
+       .prepare =      had_pcm_prepare,
+       .trigger =      had_pcm_trigger,
+       .pointer =      had_pcm_pointer,
+       .mmap =         had_pcm_mmap,
+};
+
+/* process mode change of the running stream; called in mutex */
+static int had_process_mode_change(struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_substream *substream;
+       int retval = 0;
+       u32 disp_samp_freq, n_param;
+       u32 link_rate = 0;
+
+       substream = had_substream_get(intelhaddata);
+       if (!substream)
+               return 0;
+
+       /* Disable Audio */
+       had_enable_audio(intelhaddata, false);
+
+       /* Update CTS value */
+       disp_samp_freq = intelhaddata->tmds_clock_speed;
+
+       retval = had_prog_n(substream->runtime->rate, &n_param, intelhaddata);
+       if (retval) {
+               dev_err(intelhaddata->dev,
+                       "programming N value failed %#x\n", retval);
+               goto out;
+       }
+
+       if (intelhaddata->dp_output)
+               link_rate = intelhaddata->link_rate;
+
+       had_prog_cts(substream->runtime->rate, disp_samp_freq, link_rate,
+                    n_param, intelhaddata);
+
+       /* Enable Audio */
+       had_enable_audio(intelhaddata, true);
+
+out:
+       had_substream_put(intelhaddata);
+       return retval;
+}
+
+/* process hot plug, called from wq with mutex locked */
+static void had_process_hot_plug(struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_substream *substream;
+
+       spin_lock_irq(&intelhaddata->had_spinlock);
+       if (intelhaddata->connected) {
+               dev_dbg(intelhaddata->dev, "Device already connected\n");
+               spin_unlock_irq(&intelhaddata->had_spinlock);
+               return;
+       }
+
+       intelhaddata->connected = true;
+       dev_dbg(intelhaddata->dev,
+               "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
+                       __func__, __LINE__);
+       spin_unlock_irq(&intelhaddata->had_spinlock);
+
+       had_build_channel_allocation_map(intelhaddata);
+
+       /* Report to above ALSA layer */
+       substream = had_substream_get(intelhaddata);
+       if (substream) {
+               snd_pcm_stop_xrun(substream);
+               had_substream_put(intelhaddata);
+       }
+
+       snd_jack_report(intelhaddata->jack, SND_JACK_AVOUT);
+}
+
+/* process hot unplug, called from wq with mutex locked */
+static void had_process_hot_unplug(struct snd_intelhad *intelhaddata)
+{
+       struct snd_pcm_substream *substream;
+
+       spin_lock_irq(&intelhaddata->had_spinlock);
+       if (!intelhaddata->connected) {
+               dev_dbg(intelhaddata->dev, "Device already disconnected\n");
+               spin_unlock_irq(&intelhaddata->had_spinlock);
+               return;
+
+       }
+
+       /* Disable Audio */
+       had_enable_audio(intelhaddata, false);
+
+       intelhaddata->connected = false;
+       dev_dbg(intelhaddata->dev,
+               "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_DISCONNECTED\n",
+                       __func__, __LINE__);
+       spin_unlock_irq(&intelhaddata->had_spinlock);
+
+       kfree(intelhaddata->chmap->chmap);
+       intelhaddata->chmap->chmap = NULL;
+
+       /* Report to above ALSA layer */
+       substream = had_substream_get(intelhaddata);
+       if (substream) {
+               snd_pcm_stop_xrun(substream);
+               had_substream_put(intelhaddata);
+       }
+
+       snd_jack_report(intelhaddata->jack, 0);
+}
+
+/*
+ * ALSA iec958 and ELD controls
+ */
+
+static int had_iec958_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+       uinfo->count = 1;
+       return 0;
+}
+
+static int had_iec958_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&intelhaddata->mutex);
+       ucontrol->value.iec958.status[0] = (intelhaddata->aes_bits >> 0) & 0xff;
+       ucontrol->value.iec958.status[1] = (intelhaddata->aes_bits >> 8) & 0xff;
+       ucontrol->value.iec958.status[2] =
+                                       (intelhaddata->aes_bits >> 16) & 0xff;
+       ucontrol->value.iec958.status[3] =
+                                       (intelhaddata->aes_bits >> 24) & 0xff;
+       mutex_unlock(&intelhaddata->mutex);
+       return 0;
+}
+
+static int had_iec958_mask_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.iec958.status[0] = 0xff;
+       ucontrol->value.iec958.status[1] = 0xff;
+       ucontrol->value.iec958.status[2] = 0xff;
+       ucontrol->value.iec958.status[3] = 0xff;
+       return 0;
+}
+
+static int had_iec958_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       unsigned int val;
+       struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+       int changed = 0;
+
+       val = (ucontrol->value.iec958.status[0] << 0) |
+               (ucontrol->value.iec958.status[1] << 8) |
+               (ucontrol->value.iec958.status[2] << 16) |
+               (ucontrol->value.iec958.status[3] << 24);
+       mutex_lock(&intelhaddata->mutex);
+       if (intelhaddata->aes_bits != val) {
+               intelhaddata->aes_bits = val;
+               changed = 1;
+       }
+       mutex_unlock(&intelhaddata->mutex);
+       return changed;
+}
+
+static int had_ctl_eld_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+       uinfo->count = HDMI_MAX_ELD_BYTES;
+       return 0;
+}
+
+static int had_ctl_eld_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_intelhad *intelhaddata = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&intelhaddata->mutex);
+       memcpy(ucontrol->value.bytes.data, intelhaddata->eld,
+              HDMI_MAX_ELD_BYTES);
+       mutex_unlock(&intelhaddata->mutex);
+       return 0;
+}
+
+static const struct snd_kcontrol_new had_controls[] = {
+       {
+               .access = SNDRV_CTL_ELEM_ACCESS_READ,
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK),
+               .info = had_iec958_info, /* shared */
+               .get = had_iec958_mask_get,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+               .info = had_iec958_info,
+               .get = had_iec958_get,
+               .put = had_iec958_put,
+       },
+       {
+               .access = (SNDRV_CTL_ELEM_ACCESS_READ |
+                          SNDRV_CTL_ELEM_ACCESS_VOLATILE),
+               .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+               .name = "ELD",
+               .info = had_ctl_eld_info,
+               .get = had_ctl_eld_get,
+       },
+};
+
+/*
+ * audio interrupt handler
+ */
+static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
+{
+       struct snd_intelhad *ctx = dev_id;
+       u32 audio_stat;
+
+       /* use raw register access to ack IRQs even while disconnected */
+       audio_stat = had_read_register_raw(ctx, AUD_HDMI_STATUS);
+
+       if (audio_stat & HDMI_AUDIO_UNDERRUN) {
+               had_write_register_raw(ctx, AUD_HDMI_STATUS,
+                                      HDMI_AUDIO_UNDERRUN);
+               had_process_buffer_underrun(ctx);
+       }
+
+       if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
+               had_write_register_raw(ctx, AUD_HDMI_STATUS,
+                                      HDMI_AUDIO_BUFFER_DONE);
+               had_process_buffer_done(ctx);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * monitor plug/unplug notification from i915; just kick off the work
+ */
+static void notify_audio_lpe(struct platform_device *pdev)
+{
+       struct snd_intelhad *ctx = platform_get_drvdata(pdev);
+
+       schedule_work(&ctx->hdmi_audio_wq);
+}
+
+/* the work to handle monitor hot plug/unplug */
+static void had_audio_wq(struct work_struct *work)
+{
+       struct snd_intelhad *ctx =
+               container_of(work, struct snd_intelhad, hdmi_audio_wq);
+       struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data;
+
+       pm_runtime_get_sync(ctx->dev);
+       mutex_lock(&ctx->mutex);
+       if (!pdata->hdmi_connected) {
+               dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
+                       __func__);
+               memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */
+               had_process_hot_unplug(ctx);
+       } else {
+               struct intel_hdmi_lpe_audio_eld *eld = &pdata->eld;
+
+               dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
+                       __func__, eld->port_id, pdata->tmds_clock_speed);
+
+               switch (eld->pipe_id) {
+               case 0:
+                       ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+                       break;
+               case 1:
+                       ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
+                       break;
+               case 2:
+                       ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
+                       break;
+               default:
+                       dev_dbg(ctx->dev, "Invalid pipe %d\n",
+                               eld->pipe_id);
+                       break;
+               }
+
+               memcpy(ctx->eld, eld->eld_data, sizeof(ctx->eld));
+
+               ctx->dp_output = pdata->dp_output;
+               ctx->tmds_clock_speed = pdata->tmds_clock_speed;
+               ctx->link_rate = pdata->link_rate;
+
+               had_process_hot_plug(ctx);
+
+               /* Process mode change if stream is active */
+               had_process_mode_change(ctx);
+       }
+       mutex_unlock(&ctx->mutex);
+       pm_runtime_put(ctx->dev);
+}
+
+/*
+ * Jack interface
+ */
+static int had_create_jack(struct snd_intelhad *ctx)
+{
+       int err;
+
+       err = snd_jack_new(ctx->card, "HDMI/DP", SND_JACK_AVOUT, &ctx->jack,
+                          true, false);
+       if (err < 0)
+               return err;
+       ctx->jack->private_data = ctx;
+       return 0;
+}
+
+/*
+ * PM callbacks
+ */
+
+static int hdmi_lpe_audio_runtime_suspend(struct device *dev)
+{
+       struct snd_intelhad *ctx = dev_get_drvdata(dev);
+       struct snd_pcm_substream *substream;
+
+       substream = had_substream_get(ctx);
+       if (substream) {
+               snd_pcm_suspend(substream);
+               had_substream_put(ctx);
+       }
+
+       return 0;
+}
+
+static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev)
+{
+       struct snd_intelhad *ctx = dev_get_drvdata(dev);
+       int err;
+
+       err = hdmi_lpe_audio_runtime_suspend(dev);
+       if (!err)
+               snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D3hot);
+       return err;
+}
+
+static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev)
+{
+       struct snd_intelhad *ctx = dev_get_drvdata(dev);
+
+       snd_power_change_state(ctx->card, SNDRV_CTL_POWER_D0);
+       return 0;
+}
+
+/* release resources */
+static void hdmi_lpe_audio_free(struct snd_card *card)
+{
+       struct snd_intelhad *ctx = card->private_data;
+
+       cancel_work_sync(&ctx->hdmi_audio_wq);
+
+       if (ctx->mmio_start)
+               iounmap(ctx->mmio_start);
+       if (ctx->irq >= 0)
+               free_irq(ctx->irq, ctx);
+}
+
+/*
+ * hdmi_lpe_audio_probe - start bridge with i915
+ *
+ * This function is called when the i915 driver creates the
+ * hdmi-lpe-audio platform device.
+ */
+static int hdmi_lpe_audio_probe(struct platform_device *pdev)
+{
+       struct snd_card *card;
+       struct snd_intelhad *ctx;
+       struct snd_pcm *pcm;
+       struct intel_hdmi_lpe_audio_pdata *pdata;
+       int irq;
+       struct resource *res_mmio;
+       int i, ret;
+
+       pdata = pdev->dev.platform_data;
+       if (!pdata) {
+               dev_err(&pdev->dev, "%s: quit: pdata not allocated by i915!!\n", __func__);
+               return -EINVAL;
+       }
+
+       /* get resources */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "Could not get irq resource\n");
+               return -ENODEV;
+       }
+
+       res_mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res_mmio) {
+               dev_err(&pdev->dev, "Could not get IO_MEM resources\n");
+               return -ENXIO;
+       }
+
+       /* create a card instance with ALSA framework */
+       ret = snd_card_new(&pdev->dev, hdmi_card_index, hdmi_card_id,
+                          THIS_MODULE, sizeof(*ctx), &card);
+       if (ret)
+               return ret;
+
+       ctx = card->private_data;
+       spin_lock_init(&ctx->had_spinlock);
+       mutex_init(&ctx->mutex);
+       ctx->connected = false;
+       ctx->dev = &pdev->dev;
+       ctx->card = card;
+       ctx->aes_bits = SNDRV_PCM_DEFAULT_CON_SPDIF;
+       strcpy(card->driver, INTEL_HAD);
+       strcpy(card->shortname, "Intel HDMI/DP LPE Audio");
+       strcpy(card->longname, "Intel HDMI/DP LPE Audio");
+
+       ctx->irq = -1;
+       ctx->tmds_clock_speed = DIS_SAMPLE_RATE_148_5;
+       INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
+
+       card->private_free = hdmi_lpe_audio_free;
+
+       /* assume pipe A as default */
+       ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+
+       platform_set_drvdata(pdev, ctx);
+
+       dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
+               __func__, (unsigned int)res_mmio->start,
+               (unsigned int)res_mmio->end);
+
+       ctx->mmio_start = ioremap_nocache(res_mmio->start,
+                                         (size_t)(resource_size(res_mmio)));
+       if (!ctx->mmio_start) {
+               dev_err(&pdev->dev, "Could not get ioremap\n");
+               ret = -EACCES;
+               goto err;
+       }
+
+       /* setup interrupt handler */
+       ret = request_irq(irq, display_pipe_interrupt_handler, 0,
+                         pdev->name, ctx);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "request_irq failed\n");
+               goto err;
+       }
+
+       ctx->irq = irq;
+
+       ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
+                         MAX_CAP_STREAMS, &pcm);
+       if (ret)
+               goto err;
+
+       /* setup private data which can be retrieved when required */
+       pcm->private_data = ctx;
+       pcm->info_flags = 0;
+       strncpy(pcm->name, card->shortname, strlen(card->shortname));
+       /* setup the ops for playabck */
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &had_pcm_ops);
+
+       /* only 32bit addressable */
+       dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+       dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+       /* allocate dma pages;
+        * try to allocate 600k buffer as default which is large enough
+        */
+       snd_pcm_lib_preallocate_pages_for_all(pcm,
+                       SNDRV_DMA_TYPE_DEV, NULL,
+                       HAD_DEFAULT_BUFFER, HAD_MAX_BUFFER);
+
+       /* create controls */
+       for (i = 0; i < ARRAY_SIZE(had_controls); i++) {
+               ret = snd_ctl_add(card, snd_ctl_new1(&had_controls[i], ctx));
+               if (ret < 0)
+                       goto err;
+       }
+
+       init_channel_allocations();
+
+       /* Register channel map controls */
+       ret = had_register_chmap_ctls(ctx, pcm);
+       if (ret < 0)
+               goto err;
+
+       ret = had_create_jack(ctx);
+       if (ret < 0)
+               goto err;
+
+       ret = snd_card_register(card);
+       if (ret)
+               goto err;
+
+       spin_lock_irq(&pdata->lpe_audio_slock);
+       pdata->notify_audio_lpe = notify_audio_lpe;
+       pdata->notify_pending = false;
+       spin_unlock_irq(&pdata->lpe_audio_slock);
+
+       pm_runtime_set_active(&pdev->dev);
+       pm_runtime_enable(&pdev->dev);
+
+       dev_dbg(&pdev->dev, "%s: handle pending notification\n", __func__);
+       schedule_work(&ctx->hdmi_audio_wq);
+
+       return 0;
+
+err:
+       snd_card_free(card);
+       return ret;
+}
+
+/*
+ * hdmi_lpe_audio_remove - stop bridge with i915
+ *
+ * This function is called when the platform device is destroyed.
+ */
+static int hdmi_lpe_audio_remove(struct platform_device *pdev)
+{
+       struct snd_intelhad *ctx = platform_get_drvdata(pdev);
+
+       snd_card_free(ctx->card);
+       return 0;
+}
+
+static const struct dev_pm_ops hdmi_lpe_audio_pm = {
+       SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume)
+       SET_RUNTIME_PM_OPS(hdmi_lpe_audio_runtime_suspend, NULL, NULL)
+};
+
+static struct platform_driver hdmi_lpe_audio_driver = {
+       .driver         = {
+               .name  = "hdmi-lpe-audio",
+               .pm = &hdmi_lpe_audio_pm,
+       },
+       .probe          = hdmi_lpe_audio_probe,
+       .remove         = hdmi_lpe_audio_remove,
+};
+
+module_platform_driver(hdmi_lpe_audio_driver);
+MODULE_ALIAS("platform:hdmi_lpe_audio");
+
+MODULE_AUTHOR("Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>");
+MODULE_AUTHOR("Ramesh Babu K V <ramesh.babu@intel.com>");
+MODULE_AUTHOR("Vaibhav Agarwal <vaibhav.agarwal@intel.com>");
+MODULE_AUTHOR("Jerome Anand <jerome.anand@intel.com>");
+MODULE_DESCRIPTION("Intel HDMI Audio driver");
+MODULE_LICENSE("GPL v2");
+MODULE_SUPPORTED_DEVICE("{Intel,Intel_HAD}");
diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h
new file mode 100644 (file)
index 0000000..2d3e389
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 Intel Corporation
+ *  Authors:   Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ *             Ramesh Babu K V <ramesh.babu@intel.com>
+ *             Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ *             Jerome Anand <jerome.anand@intel.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _INTEL_HDMI_AUDIO_H_
+#define _INTEL_HDMI_AUDIO_H_
+
+#include "intel_hdmi_lpe_audio.h"
+
+#define PCM_INDEX              0
+#define MAX_PB_STREAMS         1
+#define MAX_CAP_STREAMS                0
+#define BYTES_PER_WORD         0x4
+#define INTEL_HAD              "HdmiLpeAudio"
+
+/*
+ *     CEA speaker placement:
+ *
+ *     FL  FLC   FC   FRC   FR
+ *
+ *                                             LFE
+ *
+ *     RL  RLC   RC   RRC   RR
+ *
+ *     The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M
+ *     corresponds to CEA RL/RR; The SMPTE channel _assignment_ C/LFE is
+ *     swapped to CEA LFE/FC.
+ */
+enum cea_speaker_placement {
+       FL  = (1 <<  0),        /* Front Left           */
+       FC  = (1 <<  1),        /* Front Center         */
+       FR  = (1 <<  2),        /* Front Right          */
+       FLC = (1 <<  3),        /* Front Left Center    */
+       FRC = (1 <<  4),        /* Front Right Center   */
+       RL  = (1 <<  5),        /* Rear Left            */
+       RC  = (1 <<  6),        /* Rear Center          */
+       RR  = (1 <<  7),        /* Rear Right           */
+       RLC = (1 <<  8),        /* Rear Left Center     */
+       RRC = (1 <<  9),        /* Rear Right Center    */
+       LFE = (1 << 10),        /* Low Frequency Effect */
+};
+
+struct cea_channel_speaker_allocation {
+       int ca_index;
+       int speakers[8];
+
+       /* derived values, just for convenience */
+       int channels;
+       int spk_mask;
+};
+
+struct channel_map_table {
+       unsigned char map;              /* ALSA API channel map position */
+       unsigned char cea_slot;         /* CEA slot value */
+       int spk_mask;                   /* speaker position bit mask */
+};
+
+struct pcm_stream_info {
+       struct snd_pcm_substream *substream;
+       int substream_refcount;
+};
+
+/*
+ * struct snd_intelhad - intelhad driver structure
+ *
+ * @card: ptr to hold card details
+ * @connected: the monitor connection status
+ * @stream_info: stream information
+ * @eld: holds ELD info
+ * @curr_buf: pointer to hold current active ring buf
+ * @valid_buf_cnt: ring buffer count for stream
+ * @had_spinlock: driver lock
+ * @aes_bits: IEC958 status bits
+ * @buff_done: id of current buffer done intr
+ * @dev: platoform device handle
+ * @chmap: holds channel map info
+ */
+struct snd_intelhad {
+       struct snd_card *card;
+       bool            connected;
+       struct          pcm_stream_info stream_info;
+       unsigned char   eld[HDMI_MAX_ELD_BYTES];
+       bool dp_output;
+       unsigned int    aes_bits;
+       spinlock_t had_spinlock;
+       struct device *dev;
+       struct snd_pcm_chmap *chmap;
+       int tmds_clock_speed;
+       int link_rate;
+
+       /* ring buffer (BD) position index */
+       unsigned int bd_head;
+       /* PCM buffer position indices */
+       unsigned int pcmbuf_head;       /* being processed */
+       unsigned int pcmbuf_filled;     /* to be filled */
+
+       unsigned int num_bds;           /* number of BDs */
+       unsigned int period_bytes;      /* PCM period size in bytes */
+
+       /* internal stuff */
+       int irq;
+       void __iomem *mmio_start;
+       unsigned int had_config_offset;
+       union aud_cfg aud_config;       /* AUD_CONFIG reg value cache */
+       struct work_struct hdmi_audio_wq;
+       struct mutex mutex; /* for protecting chmap and eld */
+       bool need_reset;
+       struct snd_jack *jack;
+};
+
+#endif /* _INTEL_HDMI_AUDIO_ */
diff --git a/sound/x86/intel_hdmi_lpe_audio.h b/sound/x86/intel_hdmi_lpe_audio.h
new file mode 100644 (file)
index 0000000..477e515
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ *   intel_hdmi_lpe_audio.h - Intel HDMI LPE audio driver
+ *
+ *  Copyright (C) 2016 Intel Corp
+ *  Authors:   Sailaja Bandarupalli <sailaja.bandarupalli@intel.com>
+ *             Ramesh Babu K V <ramesh.babu@intel.com>
+ *             Vaibhav Agarwal <vaibhav.agarwal@intel.com>
+ *             Jerome Anand <jerome.anand@intel.com>
+ *             Aravind Siddappaji <aravindx.siddappaji@intel.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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef __INTEL_HDMI_LPE_AUDIO_H
+#define __INTEL_HDMI_LPE_AUDIO_H
+
+#define HAD_MIN_CHANNEL                2
+#define HAD_MAX_CHANNEL                8
+#define HAD_NUM_OF_RING_BUFS   4
+
+/* max 20bit address, aligned to 64 */
+#define HAD_MAX_BUFFER         ((1024 * 1024 - 1) & ~0x3f)
+#define HAD_DEFAULT_BUFFER     (600 * 1024) /* default prealloc size */
+#define HAD_MAX_PERIODS                256     /* arbitrary, but should suffice */
+#define HAD_MIN_PERIODS                1
+#define HAD_MAX_PERIOD_BYTES   ((HAD_MAX_BUFFER / HAD_MIN_PERIODS) & ~0x3f)
+#define HAD_MIN_PERIOD_BYTES   1024    /* might be smaller */
+#define HAD_FIFO_SIZE          0 /* fifo not being used */
+#define MAX_SPEAKERS           8
+
+#define AUD_SAMPLE_RATE_32     32000
+#define AUD_SAMPLE_RATE_44_1   44100
+#define AUD_SAMPLE_RATE_48     48000
+#define AUD_SAMPLE_RATE_88_2   88200
+#define AUD_SAMPLE_RATE_96     96000
+#define AUD_SAMPLE_RATE_176_4  176400
+#define AUD_SAMPLE_RATE_192    192000
+
+#define HAD_MIN_RATE           AUD_SAMPLE_RATE_32
+#define HAD_MAX_RATE           AUD_SAMPLE_RATE_192
+
+#define DIS_SAMPLE_RATE_25_2   25200
+#define DIS_SAMPLE_RATE_27     27000
+#define DIS_SAMPLE_RATE_54     54000
+#define DIS_SAMPLE_RATE_74_25  74250
+#define DIS_SAMPLE_RATE_148_5  148500
+#define HAD_REG_WIDTH          0x08
+#define HAD_MAX_DIP_WORDS              16
+
+/* DP Link Rates */
+#define DP_2_7_GHZ                     270000
+#define DP_1_62_GHZ                    162000
+
+/* Maud Values */
+#define AUD_SAMPLE_RATE_32_DP_2_7_MAUD_VAL             1988
+#define AUD_SAMPLE_RATE_44_1_DP_2_7_MAUD_VAL           2740
+#define AUD_SAMPLE_RATE_48_DP_2_7_MAUD_VAL             2982
+#define AUD_SAMPLE_RATE_88_2_DP_2_7_MAUD_VAL           5480
+#define AUD_SAMPLE_RATE_96_DP_2_7_MAUD_VAL             5965
+#define AUD_SAMPLE_RATE_176_4_DP_2_7_MAUD_VAL          10961
+#define HAD_MAX_RATE_DP_2_7_MAUD_VAL                   11930
+#define AUD_SAMPLE_RATE_32_DP_1_62_MAUD_VAL            3314
+#define AUD_SAMPLE_RATE_44_1_DP_1_62_MAUD_VAL          4567
+#define AUD_SAMPLE_RATE_48_DP_1_62_MAUD_VAL            4971
+#define AUD_SAMPLE_RATE_88_2_DP_1_62_MAUD_VAL          9134
+#define AUD_SAMPLE_RATE_96_DP_1_62_MAUD_VAL            9942
+#define AUD_SAMPLE_RATE_176_4_DP_1_62_MAUD_VAL         18268
+#define HAD_MAX_RATE_DP_1_62_MAUD_VAL                  19884
+
+/* Naud Value */
+#define DP_NAUD_VAL                                    32768
+
+/* HDMI Controller register offsets - audio domain common */
+/* Base address for below regs = 0x65000 */
+enum hdmi_ctrl_reg_offset_common {
+       AUDIO_HDMI_CONFIG_A = 0x000,
+       AUDIO_HDMI_CONFIG_B = 0x800,
+       AUDIO_HDMI_CONFIG_C = 0x900,
+};
+/* HDMI controller register offsets */
+enum hdmi_ctrl_reg_offset {
+       AUD_CONFIG              = 0x0,
+       AUD_CH_STATUS_0         = 0x08,
+       AUD_CH_STATUS_1         = 0x0C,
+       AUD_HDMI_CTS            = 0x10,
+       AUD_N_ENABLE            = 0x14,
+       AUD_SAMPLE_RATE         = 0x18,
+       AUD_BUF_CONFIG          = 0x20,
+       AUD_BUF_CH_SWAP         = 0x24,
+       AUD_BUF_A_ADDR          = 0x40,
+       AUD_BUF_A_LENGTH        = 0x44,
+       AUD_BUF_B_ADDR          = 0x48,
+       AUD_BUF_B_LENGTH        = 0x4c,
+       AUD_BUF_C_ADDR          = 0x50,
+       AUD_BUF_C_LENGTH        = 0x54,
+       AUD_BUF_D_ADDR          = 0x58,
+       AUD_BUF_D_LENGTH        = 0x5c,
+       AUD_CNTL_ST             = 0x60,
+       AUD_HDMI_STATUS         = 0x64, /* v2 */
+       AUD_HDMIW_INFOFR        = 0x68, /* v2 */
+};
+
+/* Audio configuration */
+union aud_cfg {
+       struct {
+               u32 aud_en:1;
+               u32 layout:1;           /* LAYOUT[01], see below */
+               u32 fmt:2;
+               u32 num_ch:3;
+               u32 set:1;
+               u32 flat:1;
+               u32 val_bit:1;
+               u32 user_bit:1;
+               u32 underrun:1;         /* 0: send null packets,
+                                        * 1: send silence stream
+                                        */
+               u32 packet_mode:1;      /* 0: 32bit container, 1: 16bit */
+               u32 left_align:1;       /* 0: MSB bits 0-23, 1: bits 8-31 */
+               u32 bogus_sample:1;     /* bogus sample for odd channels */
+               u32 dp_modei:1;         /* 0: HDMI, 1: DP */
+               u32 rsvd:16;
+       } regx;
+       u32 regval;
+};
+
+#define AUD_CONFIG_VALID_BIT                   (1 << 9)
+#define AUD_CONFIG_DP_MODE                     (1 << 15)
+#define AUD_CONFIG_CH_MASK     0x70
+#define LAYOUT0                        0               /* interleaved stereo */
+#define LAYOUT1                        1               /* for channels > 2 */
+
+/* Audio Channel Status 0 Attributes */
+union aud_ch_status_0 {
+       struct {
+               u32 ch_status:1;
+               u32 lpcm_id:1;
+               u32 cp_info:1;
+               u32 format:3;
+               u32 mode:2;
+               u32 ctg_code:8;
+               u32 src_num:4;
+               u32 ch_num:4;
+               u32 samp_freq:4;        /* CH_STATUS_MAP_XXX */
+               u32 clk_acc:2;
+               u32 rsvd:2;
+       } regx;
+       u32 regval;
+};
+
+/* samp_freq values - Sampling rate as per IEC60958 Ver 3 */
+#define CH_STATUS_MAP_32KHZ    0x3
+#define CH_STATUS_MAP_44KHZ    0x0
+#define CH_STATUS_MAP_48KHZ    0x2
+#define CH_STATUS_MAP_88KHZ    0x8
+#define CH_STATUS_MAP_96KHZ    0xA
+#define CH_STATUS_MAP_176KHZ   0xC
+#define CH_STATUS_MAP_192KHZ   0xE
+
+/* Audio Channel Status 1 Attributes */
+union aud_ch_status_1 {
+       struct {
+               u32 max_wrd_len:1;
+               u32 wrd_len:3;
+               u32 rsvd:28;
+       } regx;
+       u32 regval;
+};
+
+#define MAX_SMPL_WIDTH_20      0x0
+#define MAX_SMPL_WIDTH_24      0x1
+#define SMPL_WIDTH_16BITS      0x1
+#define SMPL_WIDTH_24BITS      0x5
+
+/* CTS register */
+union aud_hdmi_cts {
+       struct {
+               u32 cts_val:24;
+               u32 en_cts_prog:1;
+               u32 rsvd:7;
+       } regx;
+       u32 regval;
+};
+
+/* N register */
+union aud_hdmi_n_enable {
+       struct {
+               u32 n_val:24;
+               u32 en_n_prog:1;
+               u32 rsvd:7;
+       } regx;
+       u32 regval;
+};
+
+/* Audio Buffer configurations */
+union aud_buf_config {
+       struct {
+               u32 audio_fifo_watermark:8;
+               u32 dma_fifo_watermark:3;
+               u32 rsvd0:5;
+               u32 aud_delay:8;
+               u32 rsvd1:8;
+       } regx;
+       u32 regval;
+};
+
+#define FIFO_THRESHOLD         0xFE
+#define DMA_FIFO_THRESHOLD     0x7
+
+/* Audio Sample Swapping offset */
+union aud_buf_ch_swap {
+       struct {
+               u32 first_0:3;
+               u32 second_0:3;
+               u32 first_1:3;
+               u32 second_1:3;
+               u32 first_2:3;
+               u32 second_2:3;
+               u32 first_3:3;
+               u32 second_3:3;
+               u32 rsvd:8;
+       } regx;
+       u32 regval;
+};
+
+#define SWAP_LFE_CENTER                0x00fac4c8      /* octal 76543210 */
+
+/* Address for Audio Buffer */
+union aud_buf_addr {
+       struct {
+               u32 valid:1;
+               u32 intr_en:1;
+               u32 rsvd:4;
+               u32 addr:26;
+       } regx;
+       u32 regval;
+};
+
+#define AUD_BUF_VALID          (1U << 0)
+#define AUD_BUF_INTR_EN                (1U << 1)
+
+/* Length of Audio Buffer */
+union aud_buf_len {
+       struct {
+               u32 buf_len:20;
+               u32 rsvd:12;
+       } regx;
+       u32 regval;
+};
+
+/* Audio Control State Register offset */
+union aud_ctrl_st {
+       struct {
+               u32 ram_addr:4;
+               u32 eld_ack:1;
+               u32 eld_addr:4;
+               u32 eld_buf_size:5;
+               u32 eld_valid:1;
+               u32 cp_ready:1;
+               u32 dip_freq:2;
+               u32 dip_idx:3;
+               u32 dip_en_sta:4;
+               u32 rsvd:7;
+       } regx;
+       u32 regval;
+};
+
+/* Audio HDMI Widget Data Island Packet offset */
+union aud_info_frame1 {
+       struct {
+               u32 pkt_type:8;
+               u32 ver_num:8;
+               u32 len:5;
+               u32 rsvd:11;
+       } regx;
+       u32 regval;
+};
+
+#define HDMI_INFO_FRAME_WORD1  0x000a0184
+#define DP_INFO_FRAME_WORD1    0x00441b84
+
+/* DIP frame 2 */
+union aud_info_frame2 {
+       struct {
+               u32 chksum:8;
+               u32 chnl_cnt:3;
+               u32 rsvd0:1;
+               u32 coding_type:4;
+               u32 smpl_size:2;
+               u32 smpl_freq:3;
+               u32 rsvd1:3;
+               u32 format:8;
+       } regx;
+       u32 regval;
+};
+
+/* DIP frame 3 */
+union aud_info_frame3 {
+       struct {
+               u32 chnl_alloc:8;
+               u32 rsvd0:3;
+               u32 lsv:4;
+               u32 dm_inh:1;
+               u32 rsvd1:16;
+       } regx;
+       u32 regval;
+};
+
+#define VALID_DIP_WORDS                3
+
+/* AUD_HDMI_STATUS bits */
+#define HDMI_AUDIO_UNDERRUN            (1U << 31)
+#define HDMI_AUDIO_BUFFER_DONE         (1U << 29)
+
+/* AUD_HDMI_STATUS register mask */
+#define AUD_HDMI_STATUS_MASK_UNDERRUN  0xC0000000
+#define AUD_HDMI_STATUS_MASK_SRDBG     0x00000002
+#define AUD_HDMI_STATUSG_MASK_FUNCRST  0x00000001
+
+#endif
index 5e0dea2cdc01f65849f49f10392293a21b3a468d..039636ffb6c8a3edb6c14fd9a2b3a854ab84f982 100644 (file)
@@ -150,9 +150,9 @@ int arch_decode_instruction(struct elf *elf, struct section *sec,
                *type = INSN_RETURN;
                break;
 
-       case 0xc5: /* iret */
        case 0xca: /* retf */
        case 0xcb: /* retf */
+       case 0xcf: /* iret */
                *type = INSN_CONTEXT_SWITCH;
                break;