Merge remote-tracking branches 'asoc/topic/txx9', 'asoc/topic/wm8750', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Wed, 4 Feb 2015 20:57:24 +0000 (20:57 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 4 Feb 2015 20:57:24 +0000 (20:57 +0000)
1245 files changed:
.mailmap
Documentation/ABI/testing/sysfs-class-mei
Documentation/ABI/testing/sysfs-platform-dell-laptop [deleted file]
Documentation/devicetree/bindings/arm/arm-boards
Documentation/devicetree/bindings/arm/fw-cfg.txt [new file with mode: 0644]
Documentation/devicetree/bindings/graph.txt
Documentation/devicetree/bindings/i2c/i2c-st.txt
Documentation/devicetree/bindings/i2c/trivial-devices.txt
Documentation/devicetree/bindings/input/gpio-keys.txt
Documentation/devicetree/bindings/input/stmpe-keypad.txt
Documentation/devicetree/bindings/net/davinci_emac.txt
Documentation/devicetree/bindings/sound/designware-i2s.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/pcm512x.txt
Documentation/devicetree/bindings/sound/samsung-i2s.txt
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/sound/st,sta32x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/tlv320aic3x.txt
Documentation/devicetree/bindings/sound/ts3a227e.txt
Documentation/devicetree/bindings/vendor-prefixes.txt
Documentation/kernel-parameters.txt
Documentation/networking/ip-sysctl.txt
Documentation/target/tcm_mod_builder.py
Documentation/thermal/cpu-cooling-api.txt
MAINTAINERS
Makefile
arch/alpha/kernel/pci.c
arch/alpha/mm/fault.c
arch/arc/mm/fault.c
arch/arm/boot/dts/armada-370-db.dts
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/berlin2q-marvell-dmp.dts
arch/arm/boot/dts/berlin2q.dtsi
arch/arm/boot/dts/dra7-evm.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5420-arndale-octa.dts
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/imx25.dtsi
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx6qdl.dtsi
arch/arm/boot/dts/imx6sx-sdb.dts
arch/arm/boot/dts/ls1021a.dtsi
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/rk3288-evb.dtsi
arch/arm/boot/dts/sama5d3xmb.dtsi
arch/arm/boot/dts/sama5d4.dtsi
arch/arm/boot/dts/ste-nomadik-nhk15.dts
arch/arm/boot/dts/sun4i-a10.dtsi
arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
arch/arm/boot/dts/sun5i-a10s.dtsi
arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
arch/arm/boot/dts/sun5i-a13-olinuxino.dts
arch/arm/boot/dts/sun5i-a13.dtsi
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun7i-a20-bananapi.dts
arch/arm/boot/dts/sun7i-a20-hummingbird.dts
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
arch/arm/boot/dts/sun8i-a23.dtsi
arch/arm/boot/dts/sun9i-a80-optimus.dts
arch/arm/boot/dts/sun9i-a80.dtsi
arch/arm/boot/dts/tegra20-seaboard.dts
arch/arm/boot/dts/vf610-twr.dts
arch/arm/configs/exynos_defconfig
arch/arm/configs/multi_v7_defconfig
arch/arm/configs/omap2plus_defconfig
arch/arm/include/asm/kvm_emulate.h
arch/arm/include/asm/kvm_host.h
arch/arm/include/asm/kvm_mmu.h
arch/arm/include/uapi/asm/unistd.h
arch/arm/kernel/calls.S
arch/arm/kernel/entry-header.S
arch/arm/kernel/perf_event.c
arch/arm/kernel/perf_regs.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kvm/arm.c
arch/arm/kvm/coproc.c
arch/arm/kvm/coproc.h
arch/arm/kvm/coproc_a15.c
arch/arm/kvm/coproc_a7.c
arch/arm/kvm/mmu.c
arch/arm/kvm/trace.h
arch/arm/mach-at91/board-dt-sama5.c
arch/arm/mach-imx/clk-imx6q.c
arch/arm/mach-imx/clk-imx6sx.c
arch/arm/mach-mvebu/coherency.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/control.h
arch/arm/mach-omap2/omap-headsmp.S
arch/arm/mach-omap2/omap-smp.c
arch/arm/mach-omap2/omap4-common.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_44xx_data.c
arch/arm/mach-omap2/omap_hwmod_54xx_data.c
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm_common.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-rockchip/rockchip.c
arch/arm/mach-shmobile/board-ape6evm.c
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-r8a7778.c
arch/arm/mach-shmobile/setup-r8a7779.c
arch/arm/mach-shmobile/setup-rcar-gen2.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-shmobile/timer.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/dump.c
arch/arm/mm/init.c
arch/arm/mm/mmu.c
arch/arm64/Makefile
arch/arm64/boot/dts/Makefile
arch/arm64/boot/dts/arm/juno.dts
arch/arm64/configs/defconfig
arch/arm64/include/asm/arch_timer.h
arch/arm64/include/asm/cpu.h
arch/arm64/include/asm/dma-mapping.h
arch/arm64/include/asm/kvm_emulate.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/processor.h
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/arm64/kernel/cpuinfo.c
arch/arm64/kernel/efi.c
arch/arm64/kernel/module.c
arch/arm64/kernel/perf_regs.c
arch/arm64/kernel/setup.c
arch/arm64/kernel/smp_spin_table.c
arch/arm64/kernel/suspend.c
arch/arm64/kvm/hyp.S
arch/arm64/kvm/reset.c
arch/arm64/kvm/sys_regs.c
arch/arm64/mm/dump.c
arch/arm64/mm/init.c
arch/avr32/kernel/module.c
arch/avr32/mm/fault.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/cris/arch-v32/drivers/sync_serial.c
arch/cris/kernel/module.c
arch/cris/mm/fault.c
arch/frv/mb93090-mb00/pci-frv.c
arch/frv/mm/fault.c
arch/ia64/include/asm/unistd.h
arch/ia64/include/uapi/asm/unistd.h
arch/ia64/kernel/acpi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/module.c
arch/ia64/mm/fault.c
arch/ia64/pci/pci.c
arch/m32r/mm/fault.c
arch/m68k/include/asm/unistd.h
arch/m68k/include/uapi/asm/unistd.h
arch/m68k/kernel/syscalltable.S
arch/m68k/mm/fault.c
arch/metag/mm/fault.c
arch/microblaze/mm/fault.c
arch/microblaze/pci/pci-common.c
arch/mips/mm/fault.c
arch/mips/net/bpf_jit.c
arch/mn10300/mm/fault.c
arch/mn10300/unit-asb2305/pci-asb2305.c
arch/mn10300/unit-asb2305/pci.c
arch/nios2/kernel/cpuinfo.c
arch/nios2/kernel/entry.S
arch/nios2/kernel/module.c
arch/nios2/kernel/signal.c
arch/nios2/mm/fault.c
arch/openrisc/mm/fault.c
arch/parisc/include/asm/ldcw.h
arch/parisc/kernel/module.c
arch/parisc/mm/fault.c
arch/powerpc/crypto/sha1.c
arch/powerpc/include/asm/kexec.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/include/uapi/asm/unistd.h
arch/powerpc/kernel/machine_kexec_64.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/smp.c
arch/powerpc/mm/copro_fault.c
arch/powerpc/mm/fault.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/xmon/xmon.c
arch/s390/hypfs/hypfs_vm.c
arch/s390/include/asm/irqflags.h
arch/s390/include/asm/timex.h
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/module.c
arch/s390/kernel/syscalls.S
arch/s390/kernel/uprobes.c
arch/s390/kernel/vtime.c
arch/s390/mm/fault.c
arch/s390/mm/pgtable.c
arch/s390/net/bpf_jit.S
arch/s390/net/bpf_jit_comp.c
arch/score/mm/fault.c
arch/sh/mm/fault.c
arch/sparc/kernel/pci.c
arch/sparc/mm/fault_32.c
arch/sparc/mm/fault_64.c
arch/sparc/net/bpf_jit_comp.c
arch/tile/kernel/module.c
arch/tile/mm/fault.c
arch/um/Kconfig.common
arch/um/kernel/trap.c
arch/x86/Kconfig
arch/x86/boot/Makefile
arch/x86/boot/compressed/Makefile
arch/x86/boot/compressed/misc.c
arch/x86/crypto/Makefile
arch/x86/crypto/aes_ctrby8_avx-x86_64.S
arch/x86/crypto/sha-mb/sha1_mb.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/desc.h
arch/x86/include/asm/mmu_context.h
arch/x86/include/asm/vgtod.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/cpu/Makefile
arch/x86/kernel/cpu/mkcapflags.sh
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_rapl.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/irq.c
arch/x86/kernel/kprobes/core.c
arch/x86/kernel/perf_regs.c
arch/x86/kernel/tls.c
arch/x86/kernel/tsc.c
arch/x86/kvm/emulate.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/vmx.c
arch/x86/lib/insn.c
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/mpx.c
arch/x86/mm/pat.c
arch/x86/pci/i386.c
arch/x86/pci/xen.c
arch/x86/tools/calc_run_size.pl [deleted file]
arch/x86/tools/calc_run_size.sh [new file with mode: 0644]
arch/x86/um/sys_call_table_32.c
arch/x86/um/sys_call_table_64.c
arch/x86/vdso/vma.c
arch/x86/xen/enlighten.c
arch/x86/xen/p2m.c
arch/x86/xen/setup.c
arch/x86/xen/time.c
arch/xtensa/mm/fault.c
block/blk-core.c
block/blk-mq-sysfs.c
block/blk-mq-tag.c
block/blk-mq-tag.h
block/blk-mq.c
block/blk-mq.h
block/blk-timeout.c
crypto/aes_generic.c
crypto/af_alg.c
crypto/ansi_cprng.c
crypto/blowfish_generic.c
crypto/camellia_generic.c
crypto/cast5_generic.c
crypto/cast6_generic.c
crypto/crc32c_generic.c
crypto/crct10dif_generic.c
crypto/des_generic.c
crypto/ghash-generic.c
crypto/krng.c
crypto/salsa20_generic.c
crypto/serpent_generic.c
crypto/sha1_generic.c
crypto/sha256_generic.c
crypto/sha512_generic.c
crypto/tea.c
crypto/tgr192.c
crypto/twofish_generic.c
crypto/wp512.c
drivers/Kconfig
drivers/Makefile
drivers/acpi/acpi_processor.c
drivers/acpi/device_pm.c
drivers/acpi/int340x_thermal.c
drivers/acpi/pci_irq.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/scan.c
drivers/acpi/video.c
drivers/ata/Kconfig
drivers/ata/ahci.c
drivers/ata/ahci_xgene.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/sata_dwc_460ex.c
drivers/ata/sata_sil24.c
drivers/base/power/domain.c
drivers/base/power/opp.c
drivers/block/null_blk.c
drivers/block/nvme-core.c
drivers/block/rbd.c
drivers/block/virtio_blk.c
drivers/bus/arm-cci.c
drivers/bus/mvebu-mbus.c
drivers/char/agp/ali-agp.c
drivers/char/agp/amd64-agp.c
drivers/char/agp/ati-agp.c
drivers/char/agp/backend.c
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-gtt.c
drivers/char/agp/nvidia-agp.c
drivers/char/agp/via-agp.c
drivers/char/ipmi/ipmi_msghandler.c
drivers/char/ipmi/ipmi_ssif.c
drivers/clk/at91/clk-slow.c
drivers/clk/berlin/bg2q.c
drivers/clk/clk-ppc-corenet.c
drivers/clk/clk.c
drivers/clk/rockchip/clk-cpu.c
drivers/clk/rockchip/clk-rk3188.c
drivers/clk/rockchip/clk-rk3288.c
drivers/clocksource/arm_arch_timer.c
drivers/clocksource/bcm_kona_timer.c
drivers/clocksource/exynos_mct.c
drivers/clocksource/sh_tmu.c
drivers/cpufreq/cpufreq-dt.c
drivers/cpufreq/cpufreq.c
drivers/cpuidle/governors/ladder.c
drivers/cpuidle/governors/menu.c
drivers/dma/dw/core.c
drivers/dma/dw/platform.c
drivers/gpio/gpio-crystalcove.c
drivers/gpio/gpio-dln2.c
drivers/gpio/gpio-grgpio.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib-sysfs.c
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.h
drivers/gpu/drm/Makefile
drivers/gpu/drm/amd/amdkfd/Makefile
drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c [deleted file]
drivers/gpu/drm/amd/amdkfd/kfd_module.c
drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_pasid.c
drivers/gpu/drm/amd/amdkfd/kfd_priv.h
drivers/gpu/drm/amd/amdkfd/kfd_process.c
drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/include/kgd_kfd_interface.h
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_runtime_pm.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/msm/mdp/mdp_kms.c
drivers/gpu/drm/msm/mdp/mdp_kms.h
drivers/gpu/drm/msm/msm_atomic.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fbdev.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/nouveau/core/core/event.c
drivers/gpu/drm/nouveau/core/core/notify.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c
drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/dce3_1_afmt.c
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dma.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kfd.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/radeon/radeon_vm.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dma.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-kye.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-logitech-hidpp.c
drivers/hid/hid-roccat-pyra.c
drivers/hid/i2c-hid/i2c-hid.c
drivers/hid/usbhid/hid-quirks.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/i5500_temp.c [new file with mode: 0644]
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sh_mobile.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-slave-eeprom.c
drivers/iio/adc/ad799x.c
drivers/iio/inkern.c
drivers/infiniband/hw/mlx4/main.c
drivers/input/evdev.c
drivers/input/input.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/gpio_keys.c
drivers/input/keyboard/hil_kbd.c
drivers/input/keyboard/stmpe-keypad.c
drivers/input/mouse/alps.c
drivers/input/mouse/elantech.c
drivers/input/mouse/synaptics.c
drivers/input/mouse/trackpoint.c
drivers/input/mouse/trackpoint.h
drivers/input/serio/i8042-x86ia64io.h
drivers/input/serio/i8042.c
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/edt-ft5x06.c
drivers/iommu/intel-iommu.c
drivers/iommu/ipmmu-vmsa.c
drivers/iommu/rockchip-iommu.c
drivers/iommu/tegra-gart.c
drivers/irqchip/irq-atmel-aic-common.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-hip04.c
drivers/irqchip/irq-mtk-sysirq.c
drivers/irqchip/irq-omap-intc.c
drivers/isdn/hardware/eicon/message.c
drivers/leds/leds-netxbig.c
drivers/mcb/mcb-internal.h
drivers/mcb/mcb-pci.c
drivers/md/dm-cache-metadata.c
drivers/md/dm-cache-target.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/media/pci/cx23885/cx23885-cards.c
drivers/media/pci/cx23885/cx23885-core.c
drivers/media/pci/cx23885/cx23885-dvb.c
drivers/media/pci/cx23885/cx23885.h
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/mx3_camera.c
drivers/media/platform/soc_camera/omap1_camera.c
drivers/media/platform/soc_camera/pxa_camera.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/mfd/da9052-core.c
drivers/mfd/rtsx_usb.c
drivers/mfd/stmpe.c
drivers/mfd/stmpe.h
drivers/mfd/tps65218.c
drivers/misc/cxl/context.c
drivers/misc/cxl/file.c
drivers/misc/mei/hw-me.c
drivers/mmc/core/mmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pci.h
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci.c
drivers/net/bonding/bond_main.c
drivers/net/caif/caif_virtio.c
drivers/net/can/c_can/c_can.c
drivers/net/can/c_can/c_can_platform.c
drivers/net/can/dev.c
drivers/net/can/m_can/m_can.c
drivers/net/can/usb/kvaser_usb.c
drivers/net/ethernet/8390/ne2k-pci.c
drivers/net/ethernet/Kconfig
drivers/net/ethernet/Makefile
drivers/net/ethernet/allwinner/sun4i-emac.c
drivers/net/ethernet/altera/altera_tse_main.c
drivers/net/ethernet/amd/xgbe/xgbe-common.h
drivers/net/ethernet/amd/xgbe/xgbe-dev.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/brocade/bna/bnad_debugfs.c
drivers/net/ethernet/cadence/at91_ether.c
drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_common.h
drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
drivers/net/ethernet/cisco/enic/enic_main.c
drivers/net/ethernet/dnet.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec.h
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/e100.c
drivers/net/ethernet/intel/i40e/Makefile
drivers/net/ethernet/intel/i40e/i40e_debugfs.c
drivers/net/ethernet/intel/i40e/i40e_osdep.h
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/marvell/mv643xx_eth.c
drivers/net/ethernet/mellanox/mlx4/en_netdev.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/main.c
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/micrel/ksz884x.c
drivers/net/ethernet/myricom/myri10ge/myri10ge.c
drivers/net/ethernet/neterion/s2io.c
drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
drivers/net/ethernet/qlogic/qla3xxx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/realtek/8139too.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/s6gmac.c [deleted file]
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/cpsw_ale.c
drivers/net/ethernet/ti/cpsw_ale.h
drivers/net/ethernet/ti/davinci_emac.c
drivers/net/ethernet/xilinx/ll_temac_main.c
drivers/net/ethernet/xilinx/xilinx_axienet.h
drivers/net/ethernet/xilinx/xilinx_axienet_main.c
drivers/net/ethernet/xilinx/xilinx_emaclite.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/ipvlan/ipvlan_core.c
drivers/net/phy/micrel.c
drivers/net/team/team.c
drivers/net/usb/kaweth.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/virtio_net.c
drivers/net/vxlan.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/ipw2x00/Kconfig
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-8000.c
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/xen-netback/xenbus.c
drivers/net/xen-netfront.c
drivers/of/overlay.c
drivers/of/platform.c
drivers/of/unittest-data/tests-overlay.dtsi
drivers/of/unittest.c
drivers/parisc/lba_pci.c
drivers/pci/bus.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/quirks.c
drivers/pci/setup-bus.c
drivers/phy/phy-miphy28lp.c
drivers/phy/phy-omap-control.c
drivers/phy/phy-sun4i-usb.c
drivers/phy/phy-ti-pipe3.c
drivers/pinctrl/core.c
drivers/pinctrl/pinctrl-at91.c
drivers/pinctrl/pinctrl-rockchip.c
drivers/pinctrl/pinctrl-st.c
drivers/pinctrl/pinctrl-xway.c
drivers/pinctrl/qcom/pinctrl-msm.c
drivers/platform/x86/dell-laptop.c
drivers/powercap/intel_rapl.c
drivers/regulator/core.c
drivers/regulator/s2mps11.c
drivers/reset/reset-sunxi.c
drivers/rtc/rtc-s5m.c
drivers/s390/crypto/ap_bus.c
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/scsi.c
drivers/scsi/scsi_debug.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c
drivers/spi/spi-dw-mid.c
drivers/spi/spi-dw.c
drivers/spi/spi-img-spfi.c
drivers/spi/spi-pxa2xx.c
drivers/spi/spi-sh-msiof.c
drivers/staging/lustre/lustre/llite/namei.c
drivers/staging/lustre/lustre/llite/vvp_io.c
drivers/staging/media/tlg2300/Kconfig
drivers/staging/nvec/nvec.c
drivers/staging/vt6655/baseband.c
drivers/staging/vt6655/channel.c
drivers/staging/vt6655/device_main.c
drivers/staging/vt6655/rxtx.c
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/target_core_device.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_pr.c
drivers/target/target_core_rd.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_user.c
drivers/thermal/cpu_cooling.c
drivers/thermal/db8500_cpufreq_cooling.c
drivers/thermal/imx_thermal.c
drivers/thermal/int340x_thermal/Makefile
drivers/thermal/int340x_thermal/acpi_thermal_rel.c
drivers/thermal/int340x_thermal/int3400_thermal.c
drivers/thermal/int340x_thermal/int3402_thermal.c
drivers/thermal/int340x_thermal/int3403_thermal.c
drivers/thermal/int340x_thermal/processor_thermal_device.c [new file with mode: 0644]
drivers/thermal/intel_powerclamp.c
drivers/thermal/of-thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/rockchip_thermal.c
drivers/thermal/samsung/Kconfig
drivers/thermal/samsung/exynos_thermal_common.c
drivers/thermal/samsung/exynos_tmu.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_core.h
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/tty/n_tty.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/samsung.c
drivers/tty/serial/serial_core.c
drivers/tty/tty_io.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/host.c
drivers/usb/core/otg_whitelist.h
drivers/usb/core/quirks.c
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_hid.c
drivers/usb/gadget/function/f_midi.c
drivers/usb/gadget/function/f_uac1.c
drivers/usb/gadget/legacy/inode.c
drivers/usb/gadget/udc/atmel_usba_udc.c
drivers/usb/gadget/udc/bdc/bdc_ep.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci.c
drivers/usb/musb/Kconfig
drivers/usb/musb/blackfin.c
drivers/usb/musb/musb_cppi41.c
drivers/usb/musb/musb_debugfs.c
drivers/usb/musb/musb_host.c
drivers/usb/phy/phy-mv-usb.c
drivers/usb/phy/phy.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/generic.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/option.c
drivers/usb/serial/qcserial.c
drivers/usb/storage/uas-detect.h
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_uas.h
drivers/vfio/pci/vfio_pci.c
drivers/vhost/net.c
drivers/vhost/scsi.c
drivers/vhost/vhost.c
drivers/video/fbdev/broadsheetfb.c
drivers/video/fbdev/core/fb_defio.c
drivers/video/fbdev/omap2/dss/hdmi_pll.c
drivers/video/fbdev/omap2/dss/pll.c
drivers/video/fbdev/omap2/dss/sdi.c
drivers/video/fbdev/simplefb.c
drivers/video/logo/logo.c
drivers/virtio/virtio_pci_common.c
drivers/virtio/virtio_pci_common.h
drivers/virtio/virtio_pci_legacy.c
drivers/watchdog/cadence_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/meson_wdt.c
fs/btrfs/backref.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/ceph/addr.c
fs/cifs/cifsglob.h
fs/cifs/ioctl.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.h
fs/cifs/smb2transport.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/resize.c
fs/ext4/super.c
fs/fcntl.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/quota.c
fs/isofs/rock.c
fs/kernfs/dir.c
fs/lockd/svc.c
fs/locks.c
fs/nfs/direct.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfsd/nfs4state.c
fs/notify/fanotify/fanotify_user.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/namei.c
fs/quota/dquot.c
fs/quota/quota.c
fs/udf/dir.c
fs/udf/file.c
fs/udf/inode.c
fs/udf/namei.c
fs/udf/symlink.c
fs/udf/udfdecl.h
fs/udf/unicode.c
fs/xfs/xfs_qm.h
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quotaops.c
include/acpi/processor.h
include/asm-generic/tlb.h
include/drm/drmP.h
include/drm/drm_gem.h
include/dt-bindings/interrupt-controller/arm-gic.h
include/dt-bindings/sound/samsung-i2s.h [new file with mode: 0644]
include/dt-bindings/thermal/thermal.h
include/linux/acpi.h
include/linux/audit.h
include/linux/blk-mq.h
include/linux/blk_types.h
include/linux/ceph/osd_client.h
include/linux/compiler.h
include/linux/cpu_cooling.h
include/linux/cpuidle.h
include/linux/fs.h
include/linux/genetlink.h
include/linux/i2c.h
include/linux/kdb.h
include/linux/kernel.h
include/linux/libata.h
include/linux/mfd/samsung/s2mps13.h
include/linux/mfd/stmpe.h
include/linux/mm.h
include/linux/mmc/sdhci.h
include/linux/module.h
include/linux/moduleloader.h
include/linux/netdevice.h
include/linux/netlink.h
include/linux/nfs_fs_sb.h
include/linux/oom.h
include/linux/pagemap.h
include/linux/pci.h
include/linux/perf_event.h
include/linux/perf_regs.h
include/linux/phy/omap_control_phy.h
include/linux/pm_domain.h
include/linux/printk.h
include/linux/quota.h
include/linux/quotaops.h
include/linux/rmap.h
include/linux/thermal.h
include/linux/time.h
include/linux/writeback.h
include/net/genetlink.h
include/net/ip.h
include/net/mac80211.h
include/net/neighbour.h
include/net/vxlan.h
include/sound/pcm.h
include/sound/rcar_snd.h
include/sound/rt5677.h
include/sound/simple_card.h
include/sound/soc-dapm.h
include/sound/soc.h
include/sound/sta32x.h
include/target/target_core_backend.h
include/target/target_core_backend_configfs.h
include/target/target_core_base.h
include/trace/events/kvm.h
include/uapi/asm-generic/fcntl.h
include/uapi/linux/can/netlink.h
include/uapi/linux/in6.h
include/uapi/linux/kfd_ioctl.h
include/uapi/linux/libc-compat.h
include/uapi/linux/openvswitch.h
include/uapi/linux/uinput.h
include/uapi/linux/virtio_ring.h
include/xen/interface/nmi.h [new file with mode: 0644]
kernel/audit.c
kernel/auditfilter.c
kernel/auditsc.c
kernel/bpf/core.c
kernel/bpf/syscall.c
kernel/cgroup.c
kernel/debug/debug_core.c
kernel/debug/kdb/kdb_bp.c
kernel/debug/kdb/kdb_debugger.c
kernel/debug/kdb/kdb_main.c
kernel/debug/kdb/kdb_private.h
kernel/events/core.c
kernel/exit.c
kernel/kprobes.c
kernel/locking/mutex-debug.c
kernel/module.c
kernel/params.c
kernel/range.c
kernel/sched/core.c
kernel/sched/deadline.c
kernel/sched/fair.c
kernel/sys.c
kernel/time/ntp.c
kernel/time/time.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace_events.c
kernel/trace/trace_kdb.c
kernel/workqueue.c
lib/Kconfig.kgdb
lib/assoc_array.c
mm/Kconfig.debug
mm/filemap.c
mm/gup.c
mm/ksm.c
mm/memcontrol.c
mm/memory.c
mm/mmap.c
mm/page-writeback.c
mm/page_alloc.c
mm/rmap.c
mm/vmscan.c
net/batman-adv/fragmentation.c
net/batman-adv/gateway_client.c
net/batman-adv/multicast.c
net/batman-adv/network-coding.c
net/batman-adv/originator.c
net/batman-adv/routing.c
net/bluetooth/6lowpan.c
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_event.c
net/bluetooth/hidp/core.c
net/bridge/br_input.c
net/ceph/auth_x.c
net/ceph/mon_client.c
net/core/dev.c
net/core/neighbour.c
net/core/skbuff.c
net/dsa/slave.c
net/ipv4/geneve.c
net/ipv4/ip_forward.c
net/ipv4/ip_sockglue.c
net/ipv4/netfilter/nft_redir_ipv4.c
net/ipv4/ping.c
net/ipv4/route.c
net/ipv4/tcp_output.c
net/ipv4/udp_diag.c
net/ipv6/datagram.c
net/ipv6/ip6_fib.c
net/ipv6/netfilter/nft_redir_ipv6.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/ipv6/xfrm6_policy.c
net/llc/sysctl_net_llc.c
net/mac80211/key.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rx.c
net/mpls/mpls_gso.c
net/netfilter/ipvs/ip_vs_ftp.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nft_nat.c
net/netlink/af_netlink.c
net/netlink/af_netlink.h
net/netlink/genetlink.c
net/openvswitch/actions.c
net/openvswitch/datapath.c
net/openvswitch/flow.c
net/openvswitch/flow_netlink.c
net/openvswitch/vport-geneve.c
net/openvswitch/vport-gre.c
net/openvswitch/vport-vxlan.c
net/openvswitch/vport.c
net/packet/af_packet.c
net/sched/cls_bpf.c
net/sctp/associola.c
net/sctp/socket.c
net/socket.c
net/sunrpc/xdr.c
net/tipc/bcast.c
net/wireless/Kconfig
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/util.c
samples/bpf/test_maps.c
scripts/Makefile.clean
scripts/recordmcount.pl
security/keys/gc.c
sound/core/pcm_lib.c
sound/core/seq/seq_dummy.c
sound/firewire/amdtp.c
sound/firewire/amdtp.h
sound/firewire/bebob/bebob_stream.c
sound/firewire/fireworks/fireworks_stream.c
sound/firewire/fireworks/fireworks_transaction.c
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_priv.h
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_sigmatel.c
sound/soc/adi/axi-i2s.c
sound/soc/atmel/Kconfig
sound/soc/atmel/atmel-pcm-dma.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/db1200.c
sound/soc/au1x/dbdma2.c
sound/soc/au1x/dma.c
sound/soc/codecs/88pm860x-codec.c
sound/soc/codecs/Kconfig
sound/soc/codecs/ad193x.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/bt-sco.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l56.c
sound/soc/codecs/cs42l73.c
sound/soc/codecs/da732x.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/pcm3008.c
sound/soc/codecs/pcm512x-i2c.c
sound/soc/codecs/pcm512x-spi.c
sound/soc/codecs/pcm512x.c
sound/soc/codecs/pcm512x.h
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5631.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5645.h
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5670.h
sound/soc/codecs/rt5677.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sn95031.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta32x.h
sound/soc/codecs/tlv320aic31xx.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/ts3a227e.c
sound/soc/codecs/twl4030.c
sound/soc/codecs/twl6040.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8350.c
sound/soc/codecs/wm8400.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8750.c
sound/soc/codecs/wm8770.c
sound/soc/codecs/wm8804.c
sound/soc/codecs/wm8900.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8904.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8988.c
sound/soc/codecs/wm8990.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8993.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8995.c
sound/soc/codecs/wm8996.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm9081.c
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9705.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_adsp.c
sound/soc/codecs/wm_hubs.c
sound/soc/davinci/Kconfig
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/dwc/Kconfig
sound/soc/dwc/designware_i2s.c
sound/soc/fsl/eukrea-tlv320.c
sound/soc/fsl/fsl_asrc.c
sound/soc/fsl/fsl_asrc.h
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_esai.h
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_spdif.c
sound/soc/fsl/fsl_ssi.c
sound/soc/fsl/fsl_utils.c
sound/soc/fsl/fsl_utils.h
sound/soc/fsl/imx-mc13783.c
sound/soc/fsl/imx-spdif.c
sound/soc/fsl/imx-ssi.c
sound/soc/fsl/imx-wm8962.c
sound/soc/fsl/mx27vis-aic32x4.c
sound/soc/fsl/wm1133-ev1.c
sound/soc/generic/simple-card.c
sound/soc/intel/Kconfig
sound/soc/intel/broadwell.c
sound/soc/intel/byt-rt5640.c
sound/soc/intel/bytcr_dpcm_rt5640.c
sound/soc/intel/cht_bsw_rt5672.c
sound/soc/intel/sst-baytrail-pcm.c
sound/soc/intel/sst-dsp.c
sound/soc/intel/sst-firmware.c
sound/soc/intel/sst-haswell-dsp.c
sound/soc/intel/sst-haswell-ipc.c
sound/soc/intel/sst-haswell-pcm.c
sound/soc/intel/sst-mfld-platform-pcm.c
sound/soc/intel/sst/sst_acpi.c
sound/soc/intel/sst/sst_loader.c
sound/soc/mxs/mxs-saif.c
sound/soc/mxs/mxs-saif.h
sound/soc/mxs/mxs-sgtl5000.c
sound/soc/nuc900/nuc900-pcm.c
sound/soc/omap/ams-delta.c
sound/soc/omap/omap-hdmi-audio.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-twl4030.c
sound/soc/omap/rx51.c
sound/soc/pxa/Kconfig
sound/soc/pxa/corgi.c
sound/soc/pxa/e740_wm9705.c
sound/soc/pxa/e750_wm9705.c
sound/soc/pxa/hx4700.c
sound/soc/pxa/magician.c
sound/soc/pxa/mioa701_wm9713.c
sound/soc/pxa/palm27x.c
sound/soc/pxa/raumfeld.c
sound/soc/pxa/spitz.c
sound/soc/pxa/ttc-dkb.c
sound/soc/pxa/zylonite.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/rockchip/rockchip_i2s.h
sound/soc/samsung/Kconfig
sound/soc/samsung/arndale_rt5631.c
sound/soc/samsung/goni_wm8994.c
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/jive_wm8750.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/odroidx2_max98090.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c24xx_simtec.c
sound/soc/samsung/s3c24xx_uda134x.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/smdk_wm8580.c
sound/soc/samsung/smdk_wm8580pcm.c
sound/soc/samsung/smdk_wm8994pcm.c
sound/soc/sh/dma-sh7760.c
sound/soc/sh/fsi.c
sound/soc/sh/migor.c
sound/soc/sh/rcar/adg.c
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-ac97.c
sound/soc/soc-compress.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c
sound/soc/soc-devres.c
sound/soc/soc-generic-dmaengine-pcm.c
sound/soc/soc-pcm.c
sound/soc/tegra/Kconfig
sound/soc/tegra/Makefile
sound/soc/tegra/tegra_rt5677.c [new file with mode: 0644]
sound/soc/txx9/txx9aclc.c
sound/soc/ux500/mop500_ab8500.c
sound/usb/caiaq/audio.c
sound/usb/mixer.c
tools/include/asm-generic/bitops.h
tools/include/asm-generic/bitops/arch_hweight.h [new file with mode: 0644]
tools/include/asm-generic/bitops/const_hweight.h [new file with mode: 0644]
tools/include/asm-generic/bitops/hweight.h [new file with mode: 0644]
tools/include/linux/bitops.h
tools/lib/api/fs/debugfs.c
tools/lib/api/fs/fs.c
tools/lib/lockdep/preload.c
tools/perf/MANIFEST
tools/perf/Makefile.perf
tools/perf/arch/powerpc/util/skip-callchain-idx.c
tools/perf/bench/sched-pipe.c
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-list.c
tools/perf/builtin-report.c
tools/perf/builtin-top.c
tools/perf/config/Makefile
tools/perf/config/Makefile.arch
tools/perf/perf-sys.h
tools/perf/scripts/perl/Perf-Trace-Util/Context.c
tools/perf/tests/dwarf-unwind.c
tools/perf/tests/hists_cumulate.c
tools/perf/tests/hists_filter.c
tools/perf/tests/hists_output.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/hist.c
tools/perf/ui/tui/setup.c
tools/perf/util/annotate.c
tools/perf/util/annotate.h
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/evlist.c
tools/perf/util/hist.c
tools/perf/util/hist.h
tools/perf/util/hweight.c [deleted file]
tools/perf/util/include/asm/hweight.h [deleted file]
tools/perf/util/machine.c
tools/perf/util/map.h
tools/perf/util/probe-event.c
tools/perf/util/probe-finder.c
tools/perf/util/python-ext-sources
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/unwind-libunwind.c
tools/power/cpupower/utils/cpupower.c
tools/power/cpupower/utils/helpers/sysfs.c
tools/testing/selftests/exec/execveat.c
tools/testing/selftests/mqueue/mq_perf_tests.c
tools/testing/selftests/vm/Makefile
virt/kvm/kvm_main.c

index ada8ad696b2e902489c6e8a8f713f1285bf5a9c5..d357e1bd2a434665ae545d9ed970edd77f15f7d9 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -51,6 +51,7 @@ Greg Kroah-Hartman <gregkh@suse.de>
 Greg Kroah-Hartman <greg@kroah.com>
 Henk Vergonet <Henk.Vergonet@gmail.com>
 Henrik Kretzschmar <henne@nachtwindheim.de>
+Henrik Rydberg <rydberg@bitmath.org>
 Herbert Xu <herbert@gondor.apana.org.au>
 Jacob Shin <Jacob.Shin@amd.com>
 James Bottomley <jejb@mulgrave.(none)>
index 0ec8b8178c41305a4435b208646715c22b94154a..80d9888a8ece2673686ead1cda4504ce568a1051 100644 (file)
@@ -14,3 +14,18 @@ Description:
                The /sys/class/mei/meiN directory is created for
                each probed mei device
 
+What:          /sys/class/mei/meiN/fw_status
+Date:          Nov 2014
+KernelVersion: 3.19
+Contact:       Tomas Winkler <tomas.winkler@intel.com>
+Description:   Display fw status registers content
+
+               The ME FW writes its status information into fw status
+               registers for BIOS and OS to monitor fw health.
+
+               The register contains running state, power management
+               state, error codes, and others. The way the registers
+               are decoded depends on PCH or SoC generation.
+               Also number of registers varies between 1 and 6
+               depending on generation.
+
diff --git a/Documentation/ABI/testing/sysfs-platform-dell-laptop b/Documentation/ABI/testing/sysfs-platform-dell-laptop
deleted file mode 100644 (file)
index 7969443..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-What:          /sys/class/leds/dell::kbd_backlight/als_setting
-Date:          December 2014
-KernelVersion: 3.19
-Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
-Description:
-               This file allows to control the automatic keyboard
-               illumination mode on some systems that have an ambient
-               light sensor. Write 1 to this file to enable the auto
-               mode, 0 to disable it.
-
-What:          /sys/class/leds/dell::kbd_backlight/start_triggers
-Date:          December 2014
-KernelVersion: 3.19
-Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
-Description:
-               This file allows to control the input triggers that
-               turn on the keyboard backlight illumination that is
-               disabled because of inactivity.
-               Read the file to see the triggers available. The ones
-               enabled are preceded by '+', those disabled by '-'.
-
-               To enable a trigger, write its name preceded by '+' to
-               this file. To disable a trigger, write its name preceded
-               by '-' instead.
-
-               For example, to enable the keyboard as trigger run:
-                   echo +keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers
-               To disable it:
-                   echo -keyboard > /sys/class/leds/dell::kbd_backlight/start_triggers
-
-               Note that not all the available triggers can be configured.
-
-What:          /sys/class/leds/dell::kbd_backlight/stop_timeout
-Date:          December 2014
-KernelVersion: 3.19
-Contact:       Gabriele Mazzotta <gabriele.mzt@gmail.com>,
-               Pali Rohár <pali.rohar@gmail.com>
-Description:
-               This file allows to specify the interval after which the
-               keyboard illumination is disabled because of inactivity.
-               The timeouts are expressed in seconds, minutes, hours and
-               days, for which the symbols are 's', 'm', 'h' and 'd'
-               respectively.
-
-               To configure the timeout, write to this file a value along
-               with any the above units. If no unit is specified, the value
-               is assumed to be expressed in seconds.
-
-               For example, to set the timeout to 10 minutes run:
-                   echo 10m > /sys/class/leds/dell::kbd_backlight/stop_timeout
-
-               Note that when this file is read, the returned value might be
-               expressed in a different unit than the one used when the timeout
-               was set.
-
-               Also note that only some timeouts are supported and that
-               some systems might fall back to a specific timeout in case
-               an invalid timeout is written to this file.
index 556c8665fdbf0aa5b89e4a0818b66e30b702f3e9..b78564b2b2019e06a4fea1863191d2cab6303ee2 100644 (file)
@@ -23,7 +23,7 @@ Required nodes:
     range of 0x200 bytes.
 
 - syscon: the root node of the Integrator platforms must have a
-  system controller node pointong to the control registers,
+  system controller node pointing to the control registers,
   with the compatible string
   "arm,integrator-ap-syscon"
   "arm,integrator-cp-syscon"
diff --git a/Documentation/devicetree/bindings/arm/fw-cfg.txt b/Documentation/devicetree/bindings/arm/fw-cfg.txt
new file mode 100644 (file)
index 0000000..953fb64
--- /dev/null
@@ -0,0 +1,72 @@
+* QEMU Firmware Configuration bindings for ARM
+
+QEMU's arm-softmmu and aarch64-softmmu emulation / virtualization targets
+provide the following Firmware Configuration interface on the "virt" machine
+type:
+
+- A write-only, 16-bit wide selector (or control) register,
+- a read-write, 64-bit wide data register.
+
+QEMU exposes the control and data register to ARM guests as memory mapped
+registers; their location is communicated to the guest's UEFI firmware in the
+DTB that QEMU places at the bottom of the guest's DRAM.
+
+The guest writes a selector value (a key) to the selector register, and then
+can read the corresponding data (produced by QEMU) via the data register. If
+the selected entry is writable, the guest can rewrite it through the data
+register.
+
+The selector register takes keys in big endian byte order.
+
+The data register allows accesses with 8, 16, 32 and 64-bit width (only at
+offset 0 of the register). Accesses larger than a byte are interpreted as
+arrays, bundled together only for better performance. The bytes constituting
+such a word, in increasing address order, correspond to the bytes that would
+have been transferred by byte-wide accesses in chronological order.
+
+The interface allows guest firmware to download various parameters and blobs
+that affect how the firmware works and what tables it installs for the guest
+OS. For example, boot order of devices, ACPI tables, SMBIOS tables, kernel and
+initrd images for direct kernel booting, virtual machine UUID, SMP information,
+virtual NUMA topology, and so on.
+
+The authoritative registry of the valid selector values and their meanings is
+the QEMU source code; the structure of the data blobs corresponding to the
+individual key values is also defined in the QEMU source code.
+
+The presence of the registers can be verified by selecting the "signature" blob
+with key 0x0000, and reading four bytes from the data register. The returned
+signature is "QEMU".
+
+The outermost protocol (involving the write / read sequences of the control and
+data registers) is expected to be versioned, and/or described by feature bits.
+The interface revision / feature bitmap can be retrieved with key 0x0001. The
+blob to be read from the data register has size 4, and it is to be interpreted
+as a uint32_t value in little endian byte order. The current value
+(corresponding to the above outer protocol) is zero.
+
+The guest kernel is not expected to use these registers (although it is
+certainly allowed to); the device tree bindings are documented here because
+this is where device tree bindings reside in general.
+
+Required properties:
+
+- compatible: "qemu,fw-cfg-mmio".
+
+- reg: the MMIO region used by the device.
+  * Bytes 0x0 to 0x7 cover the data register.
+  * Bytes 0x8 to 0x9 cover the selector register.
+  * Further registers may be appended to the region in case of future interface
+    revisions / feature bits.
+
+Example:
+
+/ {
+       #size-cells = <0x2>;
+       #address-cells = <0x2>;
+
+       fw-cfg@9020000 {
+               compatible = "qemu,fw-cfg-mmio";
+               reg = <0x0 0x9020000 0x0 0xa>;
+       };
+};
index 1a69c078adf2bbf94f2714f35b43cfec1fc72fc7..fcb1c6a4787b49ba9b76b04126989c9c37a43a9a 100644 (file)
@@ -19,7 +19,7 @@ type of the connections, they just map their existence. Specific properties
 may be described by specialized bindings depending on the type of connection.
 
 To see how this binding applies to video pipelines, for example, see
-Documentation/device-tree/bindings/media/video-interfaces.txt.
+Documentation/devicetree/bindings/media/video-interfaces.txt.
 Here the ports describe data interfaces, and the links between them are
 the connecting data buses. A single port with multiple connections can
 correspond to multiple devices being connected to the same physical bus.
index 437e0db3823cac05ec71702827159851d0806d03..4c26fda3844a7f06c05cdef710d7e08fef2b76b8 100644 (file)
@@ -31,7 +31,7 @@ i2c0: i2c@fed40000 {
        compatible      = "st,comms-ssc4-i2c";
        reg             = <0xfed40000 0x110>;
        interrupts      =  <GIC_SPI 187 IRQ_TYPE_LEVEL_HIGH>;
-       clocks          = <&CLK_S_ICN_REG_0>;
+       clocks          = <&clk_s_a0_ls CLK_ICN_REG>;
        clock-names     = "ssc";
        clock-frequency = <400000>;
        pinctrl-names   = "default";
index 9f4e3824e71eb22bb825cfcd0e2c6d128242f6af..9f41d05be3be8676e307f37f00accdab12722bff 100644 (file)
@@ -47,6 +47,7 @@ dallas,ds3232         Extremely Accurate I²C RTC with Integrated Crystal and SRAM
 dallas,ds4510          CPU Supervisor with Nonvolatile Memory and Programmable I/O
 dallas,ds75            Digital Thermometer and Thermostat
 dlg,da9053             DA9053: flexible system level PMIC with multicore support
+dlg,da9063             DA9063: system PMIC for quad-core application processors
 epson,rx8025           High-Stability. I2C-Bus INTERFACE REAL TIME CLOCK MODULE
 epson,rx8581           I2C-BUS INTERFACE REAL TIME CLOCK MODULE
 fsl,mag3110            MAG3110: Xtrinsic High Accuracy, 3D Magnetometer
index a4a38fcf2ed61d1fa3db42e053fb8259f2ffcc71..44b705767aca45ea1366c6e624f0515c8cb78b99 100644 (file)
@@ -10,12 +10,13 @@ Optional properties:
 Each button (key) is represented as a sub-node of "gpio-keys":
 Subnode properties:
 
+       - gpios: OF device-tree gpio specification.
+       - interrupts: the interrupt line for that input.
        - label: Descriptive name of the key.
        - linux,code: Keycode to emit.
 
-Required mutual exclusive subnode-properties:
-       - gpios: OF device-tree gpio specification.
-       - interrupts: the interrupt line for that input
+Note that either "interrupts" or "gpios" properties can be omitted, but not
+both at the same time. Specifying both properties is allowed.
 
 Optional subnode-properties:
        - linux,input-type: Specify event type this button/key generates.
@@ -23,6 +24,9 @@ Optional subnode-properties:
        - debounce-interval: Debouncing interval time in milliseconds.
          If not specified defaults to 5.
        - gpio-key,wakeup: Boolean, button can wake-up the system.
+       - linux,can-disable: Boolean, indicates that button is connected
+         to dedicated (not shared) interrupt which can be disabled to
+         suppress events from the button.
 
 Example nodes:
 
index 1b97222e8a0bfe30d88f9d921195b721ecd65194..12bb771d66d446647722ba3e423aabc3734f77bc 100644 (file)
@@ -8,6 +8,8 @@ Optional properties:
  - debounce-interval        : Debouncing interval time in milliseconds
  - st,scan-count            : Scanning cycles elapsed before key data is updated
  - st,no-autorepeat         : If specified device will not autorepeat
+ - keypad,num-rows          : See ./matrix-keymap.txt
+ - keypad,num-columns       : See ./matrix-keymap.txt
 
 Example:
 
index 032808843f90a3b1db0389b0a60dd075c9ea3ac6..24c5cdaba8d279a4b132fbd2f964ae1460b3fd0f 100644 (file)
@@ -4,7 +4,8 @@ This file provides information, what the device node
 for the davinci_emac interface contains.
 
 Required properties:
-- compatible: "ti,davinci-dm6467-emac" or "ti,am3517-emac"
+- compatible: "ti,davinci-dm6467-emac", "ti,am3517-emac" or
+  "ti,dm816-emac"
 - reg: Offset and length of the register set for the device
 - ti,davinci-ctrl-reg-offset: offset to control register
 - ti,davinci-ctrl-mod-reg-offset: offset to control module register
diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt
new file mode 100644 (file)
index 0000000..7bb5424
--- /dev/null
@@ -0,0 +1,31 @@
+DesignWare I2S controller
+
+Required properties:
+ - compatible : Must be "snps,designware-i2s"
+ - reg : Must contain the I2S core's registers location and length
+ - clocks : Pairs of phandle and specifier referencing the controller's
+   clocks. The controller expects one clock: the clock used as the sampling
+   rate reference clock sample.
+ - clock-names : "i2sclk" for the sample rate reference clock.
+ - dmas: Pairs of phandle and specifier for the DMA channels that are used by
+   the core. The core expects one or two dma channels: one for transmit and
+   one for receive.
+ - dma-names : "tx" for the transmit channel, "rx" for the receive channel.
+
+For more details on the 'dma', 'dma-names', 'clock' and 'clock-names'
+properties please check:
+       * resource-names.txt
+       * clock/clock-bindings.txt
+       * dma/dma.txt
+
+Example:
+
+       soc_i2s: i2s@7ff90000 {
+               compatible = "snps,designware-i2s";
+               reg = <0x0 0x7ff90000 0x0 0x1000>;
+               clocks = <&scpi_i2sclk 0>;
+               clock-names = "i2sclk";
+               #sound-dai-cells = <0>;
+               dmas = <&dma0 5>;
+               dma-names = "tx";
+       };
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5677.txt
new file mode 100644 (file)
index 0000000..a4589cd
--- /dev/null
@@ -0,0 +1,67 @@
+NVIDIA Tegra audio complex, with RT5677 CODEC
+
+Required properties:
+- compatible : "nvidia,tegra-audio-rt5677"
+- clocks : Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names : Must include the following entries:
+  - pll_a
+  - pll_a_out0
+  - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk)
+- nvidia,model : The user-visible name of this sound complex.
+- nvidia,audio-routing : A list of the connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source. Valid names for sources and
+  sinks are the RT5677's pins (as documented in its binding), and the jacks
+  on the board:
+
+  * Headphone
+  * Speaker
+  * Headset Mic
+  * Internal Mic 1
+  * Internal Mic 2
+
+- nvidia,i2s-controller : The phandle of the Tegra I2S controller that's
+  connected to the CODEC.
+- nvidia,audio-codec : The phandle of the RT5677 audio codec. This binding
+  assumes that AIF1 on the CODEC is connected to Tegra.
+
+Optional properties:
+- nvidia,hp-det-gpios : The GPIO that detects headphones are plugged in
+- nvidia,hp-en-gpios : The GPIO that enables headphone amplifier
+- nvidia,mic-present-gpios: The GPIO that mic jack is plugged in
+- nvidia,dmic-clk-en-gpios : The GPIO that gates DMIC clock signal
+
+Example:
+
+sound {
+       compatible = "nvidia,tegra-audio-rt5677-ryu",
+               "nvidia,tegra-audio-rt5677";
+       nvidia,model = "NVIDIA Tegra Ryu";
+
+       nvidia,audio-routing =
+               "Headphone", "LOUT2",
+               "Headphone", "LOUT1",
+               "Headset Mic", "MICBIAS1",
+               "IN1P", "Headset Mic",
+               "IN1N", "Headset Mic",
+               "DMIC L1", "Internal Mic 1",
+               "DMIC R1", "Internal Mic 1",
+               "DMIC L2", "Internal Mic 2",
+               "DMIC R2", "Internal Mic 2",
+               "Speaker", "PDM1L",
+               "Speaker", "PDM1R";
+
+       nvidia,i2s-controller = <&tegra_i2s1>;
+       nvidia,audio-codec = <&rt5677>;
+
+       nvidia,hp-det-gpios = <&gpio TEGRA_GPIO(R, 7) GPIO_ACTIVE_HIGH>;
+       nvidia,mic-present-gpios = <&gpio TEGRA_GPIO(O, 5) GPIO_ACTIVE_LOW>;
+       nvidia,hp-en-gpios = <&rt5677 1 GPIO_ACTIVE_HIGH>;
+       nvidia,dmic-clk-en-gpios = <&rt5677 2 GPIO_ACTIVE_HIGH>;
+
+       clocks = <&tegra_car TEGRA124_CLK_PLL_A>,
+                <&tegra_car TEGRA124_CLK_PLL_A_OUT0>,
+                <&tegra_car TEGRA124_CLK_EXTERN1>;
+       clock-names = "pll_a", "pll_a_out0", "mclk";
+};
index faff75e64573cb559144fdacb94c96476e2ea73e..3aae3b41bd8e8f48ed4af639b312690d7c6f9a33 100644 (file)
@@ -5,7 +5,8 @@ on the board).
 
 Required properties:
 
-  - compatible : One of "ti,pcm5121" or "ti,pcm5122"
+  - compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141" or
+                 "ti,pcm5142"
 
   - reg : the I2C address of the device for I2C, the chip select
           number for SPI.
@@ -16,9 +17,16 @@ Required properties:
 Optional properties:
 
   - clocks : A clock specifier for the clock connected as SCLK.  If this
-    is absent the device will be configured to clock from BCLK.
+    is absent the device will be configured to clock from BCLK.  If pll-in
+    and pll-out are specified in addition to a clock, the device is
+    configured to accept clock input on a specified gpio pin.
 
-Example:
+  - pll-in, pll-out : gpio pins used to connect the pll using <1>
+    through <6>.  The device will be configured for clock input on the
+    given pll-in pin and PLL output on the given pll-out pin.  An
+    external connection from the pll-out pin to the SCLK pin is assumed.
+
+Examples:
 
        pcm5122: pcm5122@4c {
                compatible = "ti,pcm5122";
@@ -28,3 +36,17 @@ Example:
                DVDD-supply = <&reg_1v8>;
                CPVDD-supply = <&reg_3v3>;
        };
+
+
+       pcm5142: pcm5142@4c {
+               compatible = "ti,pcm5142";
+               reg = <0x4c>;
+
+               AVDD-supply = <&reg_3v3_analog>;
+               DVDD-supply = <&reg_1v8>;
+               CPVDD-supply = <&reg_3v3>;
+
+               clocks = <&sck>;
+               pll-in = <3>;
+               pll-out = <6>;
+       };
index d188296bb6ec301fd49bec5cd61da0729b1ecd5e..09e0e18591ae26edd867ccd1fd263559f32400c1 100644 (file)
@@ -33,6 +33,25 @@ Required SoC Specific Properties:
   "iis" is the i2s bus clock and i2s_opclk0, i2s_opclk1 are sources of the root
   clk. i2s0 has internal mux to select the source of root clk and i2s1 and i2s2
   doesn't have any such mux.
+- #clock-cells: should be 1, this property must be present if the I2S device
+  is a clock provider in terms of the common clock bindings, described in
+  ../clock/clock-bindings.txt.
+- clock-output-names: from the common clock bindings, names of the CDCLK
+  I2S output clocks, suggested values are "i2s_cdclk0", "i2s_cdclk1",
+  "i2s_cdclk3" for the I2S0, I2S1, I2S2 devices recpectively.
+
+There are following clocks available at the I2S device nodes:
+ CLK_I2S_CDCLK    - the CDCLK (CODECLKO) gate clock,
+ CLK_I2S_RCLK_PSR - the RCLK prescaler divider clock (corresponding to the
+                   IISPSR register),
+ CLK_I2S_RCLK_SRC - the RCLKSRC mux clock (corresponding to RCLKSRC bit in
+                   IISMOD register).
+
+Refer to the SoC datasheet for availability of the above clocks.
+The CLK_I2S_RCLK_PSR and CLK_I2S_RCLK_SRC clocks are usually only available
+in the IIS Multi Audio Interface (I2S0).
+Note: Old DTs may not have the #clock-cells, clock-output-names properties
+and then not use the I2S node as a clock supplier.
 
 Optional SoC Specific Properties:
 
@@ -41,6 +60,7 @@ Optional SoC Specific Properties:
 - pinctrl-0: Should specify pin control groups used for this controller.
 - pinctrl-names: Should contain only one value - "default".
 
+
 Example:
 
 i2s0: i2s@03830000 {
@@ -54,6 +74,8 @@ i2s0: i2s@03830000 {
                <&clock_audss EXYNOS_I2S_BUS>,
                <&clock_audss EXYNOS_SCLK_I2S>;
        clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
+       #clock-cells;
+       clock-output-names = "i2s_cdclk0";
        samsung,idma-addr = <0x03000000>;
        pinctrl-names = "default";
        pinctrl-0 = <&i2s0_bus>;
index c3cba600bf112b70b4667e2001fe6c02ccb8da93..73bf314f7240483514db27980ef6aa63dd0298f2 100644 (file)
@@ -75,6 +75,11 @@ Optional CPU/CODEC subnodes properties:
                                          it can be specified via "clocks" if system has
                                          clock node (= common clock), or "system-clock-frequency"
                                          (if system doens't support common clock)
+                                         If a clock is specified, it is
+                                         enabled with clk_prepare_enable()
+                                         in dai startup() and disabled with
+                                         clk_disable_unprepare() in dai
+                                         shutdown().
 
 Example 1 - single DAI link:
 
diff --git a/Documentation/devicetree/bindings/sound/st,sta32x.txt b/Documentation/devicetree/bindings/sound/st,sta32x.txt
new file mode 100644 (file)
index 0000000..255de3a
--- /dev/null
@@ -0,0 +1,92 @@
+STA32X audio CODEC
+
+The driver for this device only supports I2C.
+
+Required properties:
+
+  - compatible: "st,sta32x"
+  - reg: the I2C address of the device for I2C
+  - reset-gpios: a GPIO spec for the reset pin. If specified, it will be
+                deasserted before communication to the codec starts.
+
+  - power-down-gpios: a GPIO spec for the power down pin. If specified,
+                     it will be deasserted before communication to the codec
+                     starts.
+
+  - Vdda-supply: regulator spec, providing 3.3V
+  - Vdd3-supply: regulator spec, providing 3.3V
+  - Vcc-supply: regulator spec, providing 5V - 26V
+
+Optional properties:
+
+  -  st,output-conf: number, Selects the output configuration:
+       0: 2-channel (full-bridge) power, 2-channel data-out
+       1: 2 (half-bridge). 1 (full-bridge) on-board power
+       2: 2 Channel (Full-Bridge) Power, 1 Channel FFX
+       3: 1 Channel Mono-Parallel
+       If parameter is missing, mode 0 will be enabled.
+       This property has to be specified as '/bits/ 8' value.
+
+  -  st,ch1-output-mapping: Channel 1 output mapping
+  -  st,ch2-output-mapping: Channel 2 output mapping
+  -  st,ch3-output-mapping: Channel 3 output mapping
+       0: Channel 1
+       1: Channel 2
+       2: Channel 3
+       If parameter is missing, channel 1 is chosen.
+       This properties have to be specified as '/bits/ 8' values.
+
+  -  st,thermal-warning-recover:
+       If present, thermal warning recovery is enabled.
+
+  -  st,thermal-warning-adjustment:
+       If present, thermal warning adjustment is enabled.
+
+  -  st,fault-detect-recovery:
+       If present, then fault recovery will be enabled.
+
+  -  st,drop-compensation-ns: number
+       Only required for "st,ffx-power-output-mode" ==
+       "variable-drop-compensation".
+       Specifies the drop compensation in nanoseconds.
+       The value must be in the range of 0..300, and only
+       multiples of 20 are allowed. Default is 140ns.
+
+  -  st,max-power-use-mpcc:
+       If present, then MPCC bits are used for MPC coefficients,
+       otherwise standard MPC coefficients are used.
+
+  -  st,max-power-corr:
+       If present, power bridge correction for THD reduction near maximum
+       power output is enabled.
+
+  -  st,am-reduction-mode:
+       If present, FFX mode runs in AM reduction mode, otherwise normal
+       FFX mode is used.
+
+  -  st,odd-pwm-speed-mode:
+       If present, PWM speed mode run on odd speed mode (341.3 kHz) on all
+       channels. If not present, normal PWM spped mode (384 kHz) will be used.
+
+  -  st,invalid-input-detect-mute:
+       If present, automatic invalid input detect mute is enabled.
+
+Example:
+
+codec: sta32x@38 {
+       compatible = "st,sta32x";
+       reg = <0x1c>;
+       reset-gpios = <&gpio1 19 0>;
+       power-down-gpios = <&gpio1 16 0>;
+       st,output-conf = /bits/ 8  <0x3>;       // set output to 2-channel
+                                               // (full-bridge) power,
+                                               // 2-channel data-out
+       st,ch1-output-mapping = /bits/ 8 <0>;   // set channel 1 output ch 1
+       st,ch2-output-mapping = /bits/ 8 <0>;   // set channel 2 output ch 1
+       st,ch3-output-mapping = /bits/ 8 <0>;   // set channel 3 output ch 1
+       st,max-power-correction;                // enables power bridge
+                                               // correction for THD reduction
+                                               // near maximum power output
+       st,invalid-input-detect-mute;           // mute if no valid digital
+                                               // audio signal is provided.
+};
index 5e6040c2c2e9c34019dceb93e439504e4e5af9ad..47a213c411ce922321e692ecca849390cbcd53e8 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
     "ti,tlv320aic33" - TLV320AIC33
     "ti,tlv320aic3007" - TLV320AIC3007
     "ti,tlv320aic3106" - TLV320AIC3106
+    "ti,tlv320aic3104" - TLV320AIC3104
 
 
 - reg - <int> -  I2C slave address
@@ -18,6 +19,7 @@ Optional properties:
 
 - gpio-reset - gpio pin number used for codec reset
 - ai3x-gpio-func - <array of 2 int> - AIC3X_GPIO1 & AIC3X_GPIO2 Functionality
+                                   - Not supported on tlv320aic3104
 - ai3x-micbias-vg - MicBias Voltage required.
        1 - MICBIAS output is powered to 2.0V,
        2 - MICBIAS output is powered to 2.5V,
@@ -36,7 +38,13 @@ CODEC output pins:
   * HPLCOM
   * HPRCOM
 
-CODEC input pins:
+CODEC input pins for TLV320AIC3104:
+  * MIC2L
+  * MIC2R
+  * LINE1L
+  * LINE1R
+
+CODEC input pins for other compatible codecs:
   * MIC3L
   * MIC3R
   * LINE1L
index e8bf23eb1803f6497224ef4ade437f6eae74111f..a836881d96085895619a122d2f1614aa62c93836 100644 (file)
@@ -13,6 +13,11 @@ Required properties:
  - interrupt-parent:   The parent interrupt controller
  - interrupts:         Interrupt number for /INT pin from the 227e
 
+Optional properies:
+ - ti,micbias:   Intended MICBIAS voltage (datasheet section 9.6.7).
+      Select 0/1/2/3/4/5/6/7 to specify MACBIAS voltage
+      2.1V/2.2V/2.3V/2.4V/2.5V/2.6V/2.7V/2.8V
+      Default value is "1" (2.2V).
 
 Examples:
 
index b1df0ad1306c73e89a4d4be90ef4892b511b6cf3..d443279c95dca76539d60e3c55ce3f9f54d61478 100644 (file)
@@ -9,7 +9,6 @@ ad      Avionic Design GmbH
 adapteva       Adapteva, Inc.
 adi    Analog Devices, Inc.
 aeroflexgaisler        Aeroflex Gaisler AB
-ak     Asahi Kasei Corp.
 allwinner      Allwinner Technology Co., Ltd.
 altr   Altera Corp.
 amcc   Applied Micro Circuits Corporation (APM, formally AMCC)
@@ -20,6 +19,7 @@ amstaos       AMS-Taos Inc.
 apm    Applied Micro Circuits Corporation (APM)
 arm    ARM Ltd.
 armadeus       ARMadeus Systems SARL
+asahi-kasei    Asahi Kasei Corp.
 atmel  Atmel Corporation
 auo    AU Optronics Corporation
 avago  Avago Technologies
@@ -127,6 +127,7 @@ pixcir  PIXCIR MICROELECTRONICS Co., Ltd
 powervr        PowerVR (deprecated, use img)
 qca    Qualcomm Atheros, Inc.
 qcom   Qualcomm Technologies, Inc
+qemu   QEMU, a generic and open source machine emulator and virtualizer
 qnap   QNAP Systems, Inc.
 radxa  Radxa
 raidsonic      RaidSonic Technology GmbH
@@ -168,6 +169,7 @@ usi Universal Scientific Industrial Co., Ltd.
 v3     V3 Semiconductor
 variscite      Variscite Ltd.
 via    VIA Technologies, Inc.
+virtio Virtual I/O Device Specification, developed by the OASIS consortium
 voipac Voipac Technologies s.r.o.
 winbond Winbond Electronics corp.
 wlf    Wolfson Microelectronics
index 4df73da11adc586344ad6474ccb66f09ee22d66e..176d4fe4f076be0c785de56ade5cbca399e591e2 100644 (file)
@@ -1277,6 +1277,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        i8042.notimeout [HW] Ignore timeout condition signalled by controller
        i8042.reset     [HW] Reset the controller during init and cleanup
        i8042.unlock    [HW] Unlock (ignore) the keylock
+       i8042.kbdreset  [HW] Reset device connected to KBD port
 
        i810=           [HW,DRM]
 
index 9bffdfc648dc66149401296d73eb6fc04564ebd1..85b0221791048aabb65bcee8090562384ab1c628 100644 (file)
@@ -66,6 +66,8 @@ fwmark_reflect - BOOLEAN
 route/max_size - INTEGER
        Maximum number of routes allowed in the kernel.  Increase
        this when using large numbers of interfaces and/or routes.
+       From linux kernel 3.6 onwards, this is deprecated for ipv4
+       as route cache is no longer used.
 
 neigh/default/gc_thresh1 - INTEGER
        Minimum number of entries to keep.  Garbage collector will not
index 230ce71f4d75529ff4e071ed25e7bf0b4f72cd3c..2b47704f75cb3bfedf836cf02c75afd82c91e405 100755 (executable)
@@ -389,9 +389,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .release_cmd                    = " + fabric_mod_name + "_release_cmd,\n"
        buf += "        .shutdown_session               = " + fabric_mod_name + "_shutdown_session,\n"
        buf += "        .close_session                  = " + fabric_mod_name + "_close_session,\n"
-       buf += "        .stop_session                   = " + fabric_mod_name + "_stop_session,\n"
-       buf += "        .fall_back_to_erl0              = " + fabric_mod_name + "_reset_nexus,\n"
-       buf += "        .sess_logged_in                 = " + fabric_mod_name + "_sess_logged_in,\n"
        buf += "        .sess_get_index                 = " + fabric_mod_name + "_sess_get_index,\n"
        buf += "        .sess_get_initiator_sid         = NULL,\n"
        buf += "        .write_pending                  = " + fabric_mod_name + "_write_pending,\n"
@@ -402,7 +399,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        .queue_data_in                  = " + fabric_mod_name + "_queue_data_in,\n"
        buf += "        .queue_status                   = " + fabric_mod_name + "_queue_status,\n"
        buf += "        .queue_tm_rsp                   = " + fabric_mod_name + "_queue_tm_rsp,\n"
-       buf += "        .is_state_remove                = " + fabric_mod_name + "_is_state_remove,\n"
+       buf += "        .aborted_task                   = " + fabric_mod_name + "_aborted_task,\n"
        buf += "        /*\n"
        buf += "         * Setup function pointers for generic logic in target_core_fabric_configfs.c\n"
        buf += "         */\n"
@@ -428,7 +425,7 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
        buf += "        /*\n"
        buf += "         * Register the top level struct config_item_type with TCM core\n"
        buf += "         */\n"
-       buf += "        fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name[4:] + "\");\n"
+       buf += "        fabric = target_fabric_configfs_init(THIS_MODULE, \"" + fabric_mod_name + "\");\n"
        buf += "        if (IS_ERR(fabric)) {\n"
        buf += "                printk(KERN_ERR \"target_fabric_configfs_init() failed\\n\");\n"
        buf += "                return PTR_ERR(fabric);\n"
@@ -595,7 +592,7 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                if re.search('get_fabric_name', fo):
                        buf += "char *" + fabric_mod_name + "_get_fabric_name(void)\n"
                        buf += "{\n"
-                       buf += "        return \"" + fabric_mod_name[4:] + "\";\n"
+                       buf += "        return \"" + fabric_mod_name + "\";\n"
                        buf += "}\n\n"
                        bufi += "char *" + fabric_mod_name + "_get_fabric_name(void);\n"
                        continue
@@ -820,27 +817,6 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        buf += "}\n\n"
                        bufi += "void " + fabric_mod_name + "_close_session(struct se_session *);\n"
 
-               if re.search('stop_session\)\(', fo):
-                       buf += "void " + fabric_mod_name + "_stop_session(struct se_session *se_sess, int sess_sleep , int conn_sleep)\n"
-                       buf += "{\n"
-                       buf += "        return;\n"
-                       buf += "}\n\n"
-                       bufi += "void " + fabric_mod_name + "_stop_session(struct se_session *, int, int);\n"
-
-               if re.search('fall_back_to_erl0\)\(', fo):
-                       buf += "void " + fabric_mod_name + "_reset_nexus(struct se_session *se_sess)\n"
-                       buf += "{\n"
-                       buf += "        return;\n"
-                       buf += "}\n\n"
-                       bufi += "void " + fabric_mod_name + "_reset_nexus(struct se_session *);\n"
-
-               if re.search('sess_logged_in\)\(', fo):
-                       buf += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *se_sess)\n"
-                       buf += "{\n"
-                       buf += "        return 0;\n"
-                       buf += "}\n\n"
-                       bufi += "int " + fabric_mod_name + "_sess_logged_in(struct se_session *);\n"
-
                if re.search('sess_get_index\)\(', fo):
                        buf += "u32 " + fabric_mod_name + "_sess_get_index(struct se_session *se_sess)\n"
                        buf += "{\n"
@@ -898,19 +874,18 @@ def tcm_mod_dump_fabric_ops(proto_ident, fabric_mod_dir_var, fabric_mod_name):
                        bufi += "int " + fabric_mod_name + "_queue_status(struct se_cmd *);\n"
 
                if re.search('queue_tm_rsp\)\(', fo):
-                       buf += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *se_cmd)\n"
+                       buf += "void " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *se_cmd)\n"
                        buf += "{\n"
-                       buf += "        return 0;\n"
+                       buf += "        return;\n"
                        buf += "}\n\n"
-                       bufi += "int " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n"
+                       bufi += "void " + fabric_mod_name + "_queue_tm_rsp(struct se_cmd *);\n"
 
-               if re.search('is_state_remove\)\(', fo):
-                       buf += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *se_cmd)\n"
+               if re.search('aborted_task\)\(', fo):
+                       buf += "void " + fabric_mod_name + "_aborted_task(struct se_cmd *se_cmd)\n"
                        buf += "{\n"
-                       buf += "        return 0;\n"
+                       buf += "        return;\n"
                        buf += "}\n\n"
-                       bufi += "int " + fabric_mod_name + "_is_state_remove(struct se_cmd *);\n"
-
+                       bufi += "void " + fabric_mod_name + "_aborted_task(struct se_cmd *);\n"
 
        ret = p.write(buf)
        if ret:
@@ -1018,11 +993,11 @@ def main(modname, proto_ident):
        tcm_mod_build_kbuild(fabric_mod_dir, fabric_mod_name)
        tcm_mod_build_kconfig(fabric_mod_dir, fabric_mod_name)
 
-       input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Makefile..? [yes,no]: ")
+       input = raw_input("Would you like to add " + fabric_mod_name + " to drivers/target/Makefile..? [yes,no]: ")
        if input == "yes" or input == "y":
                tcm_mod_add_kbuild(tcm_dir, fabric_mod_name)
 
-       input = raw_input("Would you like to add " + fabric_mod_name + "to drivers/target/Kconfig..? [yes,no]: ")
+       input = raw_input("Would you like to add " + fabric_mod_name + " to drivers/target/Kconfig..? [yes,no]: ")
        if input == "yes" or input == "y":
                tcm_mod_add_kconfig(tcm_dir, fabric_mod_name)
 
index fca24c931ec8dcb737012b6b67f6b88a8fef2223..753e47cc2e2036cd53e176241f579addd3b43ec1 100644 (file)
@@ -3,7 +3,7 @@ CPU cooling APIs How To
 
 Written by Amit Daniel Kachhap <amit.kachhap@linaro.org>
 
-Updated: 12 May 2012
+Updated: 6 Jan 2015
 
 Copyright (c)  2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
 
@@ -25,7 +25,18 @@ the user. The registration APIs returns the cooling device pointer.
 
    clip_cpus: cpumask of cpus where the frequency constraints will happen.
 
-1.1.2 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
+1.1.2 struct thermal_cooling_device *of_cpufreq_cooling_register(
+       struct device_node *np, const struct cpumask *clip_cpus)
+
+    This interface function registers the cpufreq cooling device with
+    the name "thermal-cpufreq-%x" linking it with a device tree node, in
+    order to bind it via the thermal DT code. This api can support multiple
+    instances of cpufreq cooling devices.
+
+    np: pointer to the cooling device device tree node
+    clip_cpus: cpumask of cpus where the frequency constraints will happen.
+
+1.1.3 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 
     This interface function unregisters the "thermal-cpufreq-%x" cooling device.
 
index ddb9ac8d32b3eddc46d66bd408392ae09b637ea7..4871639b939f3efd7076be3e4fed588975e63851 100644 (file)
@@ -696,7 +696,7 @@ L:  alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://blackfin.uclinux.org/
 S:     Supported
 F:     sound/soc/blackfin/*
+
 ANALOG DEVICES INC IIO DRIVERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
 M:     Michael Hennerich <Michael.Hennerich@analog.com>
@@ -708,6 +708,16 @@ X: drivers/iio/*/adjd*
 F:     drivers/staging/iio/*/ad*
 F:     staging/iio/trigger/iio-trig-bfin-timer.c
 
+ANDROID DRIVERS
+M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+M:     Arve HjønnevÃ¥g <arve@android.com>
+M:     Riley Andrews <riandrews@android.com>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/gregkh/staging.git
+L:     devel@driverdev.osuosl.org
+S:     Supported
+F:     drivers/android/
+F:     drivers/staging/android/
+
 AOA (Apple Onboard Audio) ALSA DRIVER
 M:     Johannes Berg <johannes@sipsolutions.net>
 L:     linuxppc-dev@lists.ozlabs.org
@@ -724,15 +734,15 @@ F:        include/uapi/linux/apm_bios.h
 F:     drivers/char/apm-emulation.c
 
 APPLE BCM5974 MULTITOUCH DRIVER
-M:     Henrik Rydberg <rydberg@euromail.se>
+M:     Henrik Rydberg <rydberg@bitmath.org>
 L:     linux-input@vger.kernel.org
-S:     Maintained
+S:     Odd fixes
 F:     drivers/input/mouse/bcm5974.c
 
 APPLE SMC DRIVER
-M:     Henrik Rydberg <rydberg@euromail.se>
+M:     Henrik Rydberg <rydberg@bitmath.org>
 L:     lm-sensors@lm-sensors.org
-S:     Maintained
+S:     Odd fixes
 F:     drivers/hwmon/applesmc.c
 
 APPLETALK NETWORK LAYER
@@ -754,13 +764,6 @@ L: linux-media@vger.kernel.org
 S:     Maintained
 F:     drivers/media/i2c/aptina-pll.*
 
-ARASAN COMPACT FLASH PATA CONTROLLER
-M:     Viresh Kumar <viresh.linux@gmail.com>
-L:     linux-ide@vger.kernel.org
-S:     Maintained
-F:     include/linux/pata_arasan_cf_data.h
-F:     drivers/ata/pata_arasan_cf.c
-
 ARC FRAMEBUFFER DRIVER
 M:     Jaya Kumar <jayalk@intworks.biz>
 S:     Maintained
@@ -2259,6 +2262,7 @@ F:        drivers/gpio/gpio-bt8xx.c
 BTRFS FILE SYSTEM
 M:     Chris Mason <clm@fb.com>
 M:     Josef Bacik <jbacik@fb.com>
+M:     David Sterba <dsterba@suse.cz>
 L:     linux-btrfs@vger.kernel.org
 W:     http://btrfs.wiki.kernel.org/
 Q:     http://patchwork.kernel.org/project/linux-btrfs/list/
@@ -2345,7 +2349,8 @@ CAN NETWORK LAYER
 M:     Oliver Hartkopp <socketcan@hartkopp.net>
 L:     linux-can@vger.kernel.org
 W:     http://gitorious.org/linux-can
-T:     git git://gitorious.org/linux-can/linux-can-next.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
 S:     Maintained
 F:     Documentation/networking/can.txt
 F:     net/can/
@@ -2360,7 +2365,8 @@ M:        Wolfgang Grandegger <wg@grandegger.com>
 M:     Marc Kleine-Budde <mkl@pengutronix.de>
 L:     linux-can@vger.kernel.org
 W:     http://gitorious.org/linux-can
-T:     git git://gitorious.org/linux-can/linux-can-next.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
 S:     Maintained
 F:     drivers/net/can/
 F:     include/linux/can/dev.h
@@ -3182,7 +3188,7 @@ L:        dmaengine@vger.kernel.org
 Q:     https://patchwork.kernel.org/project/linux-dmaengine/list/
 S:     Maintained
 F:     drivers/dma/
-F:     include/linux/dma*
+F:     include/linux/dmaengine.h
 F:     Documentation/dmaengine/
 T:     git git://git.infradead.org/users/vkoul/slave-dma.git
 
@@ -4748,20 +4754,20 @@ S:      Supported
 F:     drivers/scsi/ipr.*
 
 IBM Power Virtual Ethernet Device Driver
-M:     Santiago Leon <santil@linux.vnet.ibm.com>
+M:     Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/ibm/ibmveth.*
 
 IBM Power Virtual SCSI Device Drivers
-M:     Nathan Fontenot <nfont@linux.vnet.ibm.com>
+M:     Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/ibmvscsi/ibmvscsi*
 F:     drivers/scsi/ibmvscsi/viosrp.h
 
 IBM Power Virtual FC Device Drivers
-M:     Brian King <brking@linux.vnet.ibm.com>
+M:     Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     drivers/scsi/ibmvscsi/ibmvfc*
@@ -4929,7 +4935,6 @@ F:        include/uapi/linux/inotify.h
 
 INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
 M:     Dmitry Torokhov <dmitry.torokhov@gmail.com>
-M:     Dmitry Torokhov <dtor@mail.ru>
 L:     linux-input@vger.kernel.org
 Q:     http://patchwork.kernel.org/project/linux-input/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
@@ -4940,18 +4945,27 @@ F:      include/uapi/linux/input.h
 F:     include/linux/input/
 
 INPUT MULTITOUCH (MT) PROTOCOL
-M:     Henrik Rydberg <rydberg@euromail.se>
+M:     Henrik Rydberg <rydberg@bitmath.org>
 L:     linux-input@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt.git
-S:     Maintained
+S:     Odd fixes
 F:     Documentation/input/multi-touch-protocol.txt
 F:     drivers/input/input-mt.c
 K:     \b(ABS|SYN)_MT_
 
+INTEL ASoC BDW/HSW DRIVERS
+M:     Jie Yang <yang.jie@linux.intel.com>
+L:     alsa-devel@alsa-project.org
+S:     Supported
+F:     sound/soc/intel/sst-haswell*
+F:     sound/soc/intel/sst-dsp*
+F:     sound/soc/intel/sst-firmware.c
+F:     sound/soc/intel/broadwell.c
+F:     sound/soc/intel/haswell.c
+
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:     Intel SCU Linux support <intel-linux-scu@intel.com>
 M:     Artur Paszkiewicz <artur.paszkiewicz@intel.com>
-M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-scsi@vger.kernel.org
 T:     git git://git.code.sf.net/p/intel-sas/isci
 S:     Supported
@@ -5279,6 +5293,15 @@ W:       www.open-iscsi.org
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
 F:     drivers/infiniband/ulp/iser/
 
+ISCSI EXTENSIONS FOR RDMA (ISER) TARGET
+M:     Sagi Grimberg <sagig@mellanox.com>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending.git master
+L:     linux-rdma@vger.kernel.org
+L:     target-devel@vger.kernel.org
+S:     Supported
+W:     http://www.linux-iscsi.org
+F:     drivers/infiniband/ulp/isert
+
 ISDN SUBSYSTEM
 M:     Karsten Keil <isdn@linux-pingi.de>
 L:     isdn4linux@listserv.isdn4linux.de (subscribers-only)
@@ -5693,6 +5716,49 @@ F:       drivers/lguest/
 F:     include/linux/lguest*.h
 F:     tools/lguest/
 
+LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
+M:     Tejun Heo <tj@kernel.org>
+L:     linux-ide@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S:     Maintained
+F:     drivers/ata/
+F:     include/linux/ata.h
+F:     include/linux/libata.h
+
+LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
+M:     Viresh Kumar <viresh.linux@gmail.com>
+L:     linux-ide@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S:     Maintained
+F:     include/linux/pata_arasan_cf_data.h
+F:     drivers/ata/pata_arasan_cf.c
+
+LIBATA PATA DRIVERS
+M:     Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+M:     Tejun Heo <tj@kernel.org>
+L:     linux-ide@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S:     Maintained
+F:     drivers/ata/pata_*.c
+F:     drivers/ata/ata_generic.c
+
+LIBATA SATA AHCI PLATFORM devices support
+M:     Hans de Goede <hdegoede@redhat.com>
+M:     Tejun Heo <tj@kernel.org>
+L:     linux-ide@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S:     Maintained
+F:     drivers/ata/ahci_platform.c
+F:     drivers/ata/libahci_platform.c
+F:     include/linux/ahci_platform.h
+
+LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
+M:     Mikael Pettersson <mikpelinux@gmail.com>
+L:     linux-ide@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
+S:     Maintained
+F:     drivers/ata/sata_promise.*
+
 LIBLOCKDEP
 M:     Sasha Levin <sasha.levin@oracle.com>
 S:     Maintained
@@ -6977,14 +7043,12 @@ OPEN FIRMWARE AND FLATTENED DEVICE TREE
 M:     Grant Likely <grant.likely@linaro.org>
 M:     Rob Herring <robh+dt@kernel.org>
 L:     devicetree@vger.kernel.org
-W:     http://fdt.secretlab.ca
-T:     git git://git.secretlab.ca/git/linux-2.6.git
+W:     http://www.devicetree.org/
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux.git
 S:     Maintained
 F:     drivers/of/
 F:     include/linux/of*.h
 F:     scripts/dtc/
-K:     of_get_property
-K:     of_match_table
 
 OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
 M:     Rob Herring <robh+dt@kernel.org>
@@ -7229,7 +7293,7 @@ S:        Maintained
 F:     drivers/pci/host/*layerscape*
 
 PCI DRIVER FOR IMX6
-M:     Richard Zhu <r65037@freescale.com>
+M:     Richard Zhu <Richard.Zhu@freescale.com>
 M:     Lucas Stach <l.stach@pengutronix.de>
 L:     linux-pci@vger.kernel.org
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -7399,6 +7463,7 @@ F:        drivers/crypto/picoxcell*
 PIN CONTROL SUBSYSTEM
 M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-gpio@vger.kernel.org
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
 S:     Maintained
 F:     drivers/pinctrl/
 F:     include/linux/pinctrl/
@@ -7566,12 +7631,6 @@ W:       http://wireless.kernel.org/en/users/Drivers/p54
 S:     Obsolete
 F:     drivers/net/wireless/prism54/
 
-PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER
-M:     Mikael Pettersson <mikpelinux@gmail.com>
-L:     linux-ide@vger.kernel.org
-S:     Maintained
-F:     drivers/ata/sata_promise.*
-
 PS3 NETWORK SUPPORT
 M:     Geoff Levand <geoff@infradead.org>
 L:     netdev@vger.kernel.org
@@ -7737,8 +7796,7 @@ F:        Documentation/scsi/LICENSE.qla2xxx
 F:     drivers/scsi/qla2xxx/
 
 QLOGIC QLA4XXX iSCSI DRIVER
-M:     Vikas Chaudhary <vikas.chaudhary@qlogic.com>
-M:     iscsi-driver@qlogic.com
+M:     QLogic-Storage-Upstream@qlogic.com
 L:     linux-scsi@vger.kernel.org
 S:     Supported
 F:     Documentation/scsi/LICENSE.qla4xxx
@@ -8546,25 +8604,6 @@ S:       Maintained
 F:     drivers/misc/phantom.c
 F:     include/uapi/linux/phantom.h
 
-SERIAL ATA (SATA) SUBSYSTEM
-M:     Tejun Heo <tj@kernel.org>
-L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
-S:     Supported
-F:     drivers/ata/
-F:     include/linux/ata.h
-F:     include/linux/libata.h
-
-SERIAL ATA AHCI PLATFORM devices support
-M:     Hans de Goede <hdegoede@redhat.com>
-M:     Tejun Heo <tj@kernel.org>
-L:     linux-ide@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
-S:     Supported
-F:     drivers/ata/ahci_platform.c
-F:     drivers/ata/libahci_platform.c
-F:     include/linux/ahci_platform.h
-
 SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
 M:     Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
 L:     linux-scsi@vger.kernel.org
@@ -9533,7 +9572,8 @@ F:        drivers/platform/x86/thinkpad_acpi.c
 TI BANDGAP AND THERMAL DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
 L:     linux-pm@vger.kernel.org
-S:     Supported
+L:     linux-omap@vger.kernel.org
+S:     Maintained
 F:     drivers/thermal/ti-soc-thermal/
 
 TI CLOCK DRIVER
@@ -10146,6 +10186,7 @@ USERSPACE I/O (UIO)
 M:     "Hans J. Koch" <hjk@hansjkoch.de>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
 F:     Documentation/DocBook/uio-howto.tmpl
 F:     drivers/uio/
 F:     include/linux/uio*.h
index b1c3254441f3f3353465ef8b3cf2e563abe70bf4..c8e17c05f9163ae74dd9434e4f68b15188190558 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 19
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc7
 NAME = Diseased Newt
 
 # *DOCUMENTATION*
@@ -391,6 +391,7 @@ USERINCLUDE    := \
 # Needed to be compatible with the O= option
 LINUXINCLUDE    := \
                -I$(srctree)/arch/$(hdr-arch)/include \
+               -Iarch/$(hdr-arch)/include/generated/uapi \
                -Iarch/$(hdr-arch)/include/generated \
                $(if $(KBUILD_SRC), -I$(srctree)/include) \
                -Iinclude \
index 076c35cd6cde7c2d782a46fe3942b8962369230e..98a1525fa164df0178fd4cb5fc0267129b2844e3 100644 (file)
@@ -285,8 +285,12 @@ pcibios_claim_one_bus(struct pci_bus *b)
                        if (r->parent || !r->start || !r->flags)
                                continue;
                        if (pci_has_flag(PCI_PROBE_ONLY) ||
-                           (r->flags & IORESOURCE_PCI_FIXED))
-                               pci_claim_resource(dev, i);
+                           (r->flags & IORESOURCE_PCI_FIXED)) {
+                               if (pci_claim_resource(dev, i) == 0)
+                                       continue;
+
+                               pci_claim_bridge_resource(dev, i);
+                       }
                }
        }
 
index 98838a05ba6d89f0459742131010f57c38cbed05..9d0ac091a52a7d16cf1f78f402ab48c511924a24 100644 (file)
@@ -156,6 +156,8 @@ retry:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 6f7e3a68803a097461d27ace9fa940ba3211ab6b..563cb27e37f55f3f99badc9b99e64aca6ee397b7 100644 (file)
@@ -161,6 +161,8 @@ good_area:
 
        if (fault & VM_FAULT_OOM)
                goto out_of_memory;
+       else if (fault & VM_FAULT_SIGSEGV)
+               goto bad_area;
        else if (fault & VM_FAULT_SIGBUS)
                goto do_sigbus;
 
index 1466580be2954996c43fc189bc263967b37a49fc..70b1943a86b104502449c1c58153d9ed68c7c469 100644 (file)
                compatible = "linux,spdif-dir";
        };
 };
-
-&pinctrl {
-       /*
-        * These pins might be muxed as I2S by
-        * the bootloader, but it conflicts
-        * with the real I2S pins that are
-        * muxed using i2s_pins. We must mux
-        * those pins to a function other than
-        * I2S.
-        */
-       pinctrl-0 = <&hog_pins1 &hog_pins2>;
-       pinctrl-names = "default";
-
-       hog_pins1: hog-pins1 {
-               marvell,pins = "mpp6",  "mpp8", "mpp10",
-                              "mpp12", "mpp13";
-               marvell,function = "gpio";
-       };
-
-       hog_pins2: hog-pins2 {
-               marvell,pins = "mpp5", "mpp7", "mpp9";
-               marvell,function = "gpo";
-       };
-};
index 1467750e3377d161bddff0cfcce1f35d91c9261b..e8c6c600a5b69335bbea0fdabf70e7ccee7ff163 100644 (file)
                        interrupts = <26 IRQ_TYPE_LEVEL_HIGH 3>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_fb>;
+                       clocks = <&lcd_clk>, <&lcd_clk>;
+                       clock-names = "lcdc_clk", "hclk";
                        status = "disabled";
                };
 
index 28e7e2060c3399c204f547b37fc325fa1069e8d8..a98ac1bd8f65124fe69d43aa8e8b467a2a7c911c 100644 (file)
@@ -65,6 +65,8 @@
 };
 
 &sdhci2 {
+       broken-cd;
+       bus-width = <8>;
        non-removable;
        status = "okay";
 };
index 35253c947a7cd0002211dac773d7f1f9723d6fce..e2f61f27944e24fd45cc65518126f932409ea610 100644 (file)
@@ -83,7 +83,8 @@
                        compatible = "mrvl,pxav3-mmc";
                        reg = <0xab1000 0x200>;
                        interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&chip CLKID_SDIO1XIN>;
+                       clocks = <&chip CLKID_NFC_ECC>, <&chip CLKID_NFC>;
+                       clock-names = "io", "core";
                        status = "disabled";
                };
 
                                interrupt-parent = <&gic>;
                                interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
                        };
-
-                       gpio4: gpio@5000 {
-                               compatible = "snps,dw-apb-gpio";
-                               reg = <0x5000 0x400>;
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
-                               porte: gpio-port@4 {
-                                       compatible = "snps,dw-apb-gpio-port";
-                                       gpio-controller;
-                                       #gpio-cells = <2>;
-                                       snps,nr-gpios = <32>;
-                                       reg = <0>;
-                               };
-                       };
-
-                       gpio5: gpio@c000 {
-                               compatible = "snps,dw-apb-gpio";
-                               reg = <0xc000 0x400>;
-                               #address-cells = <1>;
-                               #size-cells = <0>;
-
-                               portf: gpio-port@5 {
-                                       compatible = "snps,dw-apb-gpio-port";
-                                       gpio-controller;
-                                       #gpio-cells = <2>;
-                                       snps,nr-gpios = <32>;
-                                       reg = <0>;
-                               };
-                       };
                };
 
                chip: chip-control@ea0000 {
                        ranges = <0 0xfc0000 0x10000>;
                        interrupt-parent = <&sic>;
 
+                       sm_gpio1: gpio@5000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0x5000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               portf: gpio-port@5 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                               };
+                       };
+
                        i2c2: i2c@7000 {
                                compatible = "snps,designware-i2c";
                                #address-cells = <1>;
                                status = "disabled";
                        };
 
+                       sm_gpio0: gpio@c000 {
+                               compatible = "snps,dw-apb-gpio";
+                               reg = <0xc000 0x400>;
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               porte: gpio-port@4 {
+                                       compatible = "snps,dw-apb-gpio-port";
+                                       gpio-controller;
+                                       #gpio-cells = <2>;
+                                       snps,nr-gpios = <32>;
+                                       reg = <0>;
+                               };
+                       };
+
                        sysctrl: pin-controller@d000 {
                                compatible = "marvell,berlin2q-system-ctrl";
                                reg = <0xd000 0x100>;
index 10b725c7bfc02fc79e8c694150ec1e23c5493175..ad4118f7e1a6106139af2a6bfe56d3534c306af9 100644 (file)
                };
                partition@5 {
                        label = "QSPI.u-boot-spl-os";
-                       reg = <0x00140000 0x00010000>;
+                       reg = <0x00140000 0x00080000>;
                };
                partition@6 {
                        label = "QSPI.u-boot-env";
-                       reg = <0x00150000 0x00010000>;
+                       reg = <0x001c0000 0x00010000>;
                };
                partition@7 {
                        label = "QSPI.u-boot-env.backup1";
-                       reg = <0x00160000 0x0010000>;
+                       reg = <0x001d0000 0x0010000>;
                };
                partition@8 {
                        label = "QSPI.kernel";
-                       reg = <0x00170000 0x0800000>;
+                       reg = <0x001e0000 0x0800000>;
                };
                partition@9 {
                        label = "QSPI.file-system";
-                       reg = <0x00970000 0x01690000>;
+                       reg = <0x009e0000 0x01620000>;
                };
        };
 };
index 22771bc1643afcd7652773f058e6ace90df5d2a9..63f8b007bdc51358d53cdd57b58c8fe1a21f617a 100644 (file)
                                tx-fifo-resize;
                                maximum-speed = "super-speed";
                                dr_mode = "otg";
+                               snps,dis_u3_susphy_quirk;
+                               snps,dis_u2_susphy_quirk;
                        };
                };
 
                                tx-fifo-resize;
                                maximum-speed = "high-speed";
                                dr_mode = "otg";
+                               snps,dis_u3_susphy_quirk;
+                               snps,dis_u2_susphy_quirk;
                        };
                };
 
                                tx-fifo-resize;
                                maximum-speed = "high-speed";
                                dr_mode = "otg";
+                               snps,dis_u3_susphy_quirk;
+                               snps,dis_u2_susphy_quirk;
                        };
                };
 
index 0a229fcd7acfdfff4e07b4359cf0c7776e510efc..d75c89d7666a0a0bea5fff5139439f8090eee793 100644 (file)
 
        dp_phy: video-phy@10040720 {
                compatible = "samsung,exynos5250-dp-video-phy";
-               reg = <0x10040720 4>;
+               samsung,pmu-syscon = <&pmu_system_controller>;
                #phy-cells = <0>;
        };
 
index aa7a7d727a7e80033df0cddb0b9cce8596d48ddc..db2c1c4cd90076b5c7bb47d12737e46bf4938264 100644 (file)
 &usbdrd_dwc3_1 {
        dr_mode = "host";
 };
+
+&cci {
+       status = "disabled";
+};
index 517e50f6760b0cf4d77bc55bf899f0aa5e3667a1..6d38f8bfd0e68e71358608a9af0ec32dbc5a53c2 100644 (file)
                };
        };
 
-       cci@10d20000 {
+       cci: cci@10d20000 {
                compatible = "arm,cci-400";
                #address-cells = <1>;
                #size-cells = <1>;
        };
 
        dp_phy: video-phy@10040728 {
-               compatible = "samsung,exynos5250-dp-video-phy";
-               reg = <0x10040728 4>;
+               compatible = "samsung,exynos5420-dp-video-phy";
+               samsung,pmu-syscon = <&pmu_system_controller>;
                #phy-cells = <0>;
        };
 
index 58d3c3cf2923f5ffae5e1657140fc7b94f4090c1..e4d3aecc4ed2c0fd61b1c68a93f20a24b808bd8c 100644 (file)
                                #size-cells = <0>;
                                compatible = "fsl,imx25-cspi", "fsl,imx35-cspi";
                                reg = <0x43fa4000 0x4000>;
-                               clocks = <&clks 62>, <&clks 62>;
+                               clocks = <&clks 78>, <&clks 78>;
                                clock-names = "ipg", "per";
                                interrupts = <14>;
                                status = "disabled";
                                compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
                                #pwm-cells = <2>;
                                reg = <0x53fa0000 0x4000>;
-                               clocks = <&clks 106>, <&clks 36>;
+                               clocks = <&clks 106>, <&clks 52>;
                                clock-names = "ipg", "per";
                                interrupts = <36>;
                        };
                                compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
                                #pwm-cells = <2>;
                                reg = <0x53fa8000 0x4000>;
-                               clocks = <&clks 107>, <&clks 36>;
+                               clocks = <&clks 107>, <&clks 52>;
                                clock-names = "ipg", "per";
                                interrupts = <41>;
                        };
                        pwm4: pwm@53fc8000 {
                                compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
                                reg = <0x53fc8000 0x4000>;
-                               clocks = <&clks 108>, <&clks 36>;
+                               clocks = <&clks 108>, <&clks 52>;
                                clock-names = "ipg", "per";
                                interrupts = <42>;
                        };
                                compatible = "fsl,imx25-pwm", "fsl,imx27-pwm";
                                #pwm-cells = <2>;
                                reg = <0x53fe0000 0x4000>;
-                               clocks = <&clks 105>, <&clks 36>;
+                               clocks = <&clks 105>, <&clks 52>;
                                clock-names = "ipg", "per";
                                interrupts = <26>;
                        };
index 56569cecaa7852795ab94f6046321f13bddd837e..649befeb2cf96ef4b968f809a98d5d718227b002 100644 (file)
                #address-cells = <1>;
                #size-cells = <0>;
 
-               reg_usbh1_vbus: regulator@0 {
-                       compatible = "regulator-fixed";
-                       pinctrl-names = "default";
-                       pinctrl-0 = <&pinctrl_usbh1reg>;
-                       reg = <0>;
-                       regulator-name = "usbh1_vbus";
-                       regulator-min-microvolt = <5000000>;
-                       regulator-max-microvolt = <5000000>;
-                       gpio = <&gpio2 5 GPIO_ACTIVE_HIGH>;
-                       enable-active-high;
-               };
-
-               reg_usbotg_vbus: regulator@1 {
+               reg_hub_reset: regulator@0 {
                        compatible = "regulator-fixed";
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_usbotgreg>;
-                       reg = <1>;
-                       regulator-name = "usbotg_vbus";
+                       reg = <0>;
+                       regulator-name = "hub_reset";
                        regulator-min-microvolt = <5000000>;
                        regulator-max-microvolt = <5000000>;
                        gpio = <&gpio1 7 GPIO_ACTIVE_HIGH>;
                        reg = <0>;
                        clocks = <&clks IMX5_CLK_DUMMY>;
                        clock-names = "main_clk";
+                       reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
                };
        };
 };
 &usbh1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usbh1>;
-       vbus-supply = <&reg_usbh1_vbus>;
+       vbus-supply = <&reg_hub_reset>;
        fsl,usbphy = <&usbh1phy>;
        phy_type = "ulpi";
        status = "okay";
        dr_mode = "otg";
        disable-over-current;
        phy_type = "utmi_wide";
-       vbus-supply = <&reg_usbotg_vbus>;
        status = "okay";
 };
 
index 4fc03b7f1ceec52fe5d327974cd2929127de21f9..2109d0763c1b6dca448449ba74709c6ced666cbb 100644 (file)
                        vpu: vpu@02040000 {
                                compatible = "cnm,coda960";
                                reg = <0x02040000 0x3c000>;
-                               interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>,
-                                            <0 12 IRQ_TYPE_LEVEL_HIGH>;
+                               interrupts = <0 12 IRQ_TYPE_LEVEL_HIGH>,
+                                            <0 3 IRQ_TYPE_LEVEL_HIGH>;
                                interrupt-names = "bit", "jpeg";
                                clocks = <&clks IMX6QDL_CLK_VPU_AXI>,
                                         <&clks IMX6QDL_CLK_MMDC_CH0_AXI>,
index 1e6e5cc1c14cf283fb8b3bd9321f44218fbe4fb3..c108bb451337ee4c5108847192d2991d78a4c68b 100644 (file)
        pinctrl-0 = <&pinctrl_enet1>;
        phy-supply = <&reg_enet_3v3>;
        phy-mode = "rgmii";
+       phy-handle = <&ethphy1>;
        status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy1: ethernet-phy@1 {
+                       reg = <1>;
+               };
+
+               ethphy2: ethernet-phy@2 {
+                       reg = <2>;
+               };
+       };
 };
 
 &fec2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_enet2>;
        phy-mode = "rgmii";
+       phy-handle = <&ethphy2>;
        status = "okay";
 };
 
index 657da14cb4b5b2cc96bc1b4139c871f5fac65307..c70bb27ac65a63e1f197408e4a9ccb822d3407c4 100644 (file)
                scfg: scfg@1570000 {
                        compatible = "fsl,ls1021a-scfg", "syscon";
                        reg = <0x0 0x1570000 0x0 0x10000>;
+                       big-endian;
                };
 
                clockgen: clocking@1ee1000 {
index 53f3ca064140470866dbfe12773af1ddb76d1632..b550c41b46f1ecc83fcc9abf551fbeff4f44e2a0 100644 (file)
                };
        };
 
+       /* Ethernet is on some early development boards and qemu */
        ethernet@gpmc {
                compatible = "smsc,lan91c94";
-
-               status = "disabled";
-
                interrupt-parent = <&gpio2>;
                interrupts = <22 IRQ_TYPE_LEVEL_HIGH>;  /* gpio54 */
                reg = <1 0x300 0xf>;            /* 16 byte IO range at offset 0x300 */
index 3e067dd65d0c87d7845809bd121859f86de1a879..6194d673e80be828c7067bccf498569c121b2a74 100644 (file)
 };
 
 &pinctrl {
+       pcfg_pull_none_drv_8ma: pcfg-pull-none-drv-8ma {
+               drive-strength = <8>;
+       };
+
+       pcfg_pull_up_drv_8ma: pcfg-pull-up-drv-8ma {
+               bias-pull-up;
+               drive-strength = <8>;
+       };
+
        backlight {
                bl_en: bl-en {
                        rockchip,pins = <7 2 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
 
+       sdmmc {
+               /*
+                * Default drive strength isn't enough to achieve even
+                * high-speed mode on EVB board so bump up to 8ma.
+                */
+               sdmmc_bus4: sdmmc-bus4 {
+                       rockchip,pins = <6 16 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
+                                       <6 17 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
+                                       <6 18 RK_FUNC_1 &pcfg_pull_up_drv_8ma>,
+                                       <6 19 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+               };
+
+               sdmmc_clk: sdmmc-clk {
+                       rockchip,pins = <6 20 RK_FUNC_1 &pcfg_pull_none_drv_8ma>;
+               };
+
+               sdmmc_cmd: sdmmc-cmd {
+                       rockchip,pins = <6 21 RK_FUNC_1 &pcfg_pull_up_drv_8ma>;
+               };
+       };
+
        usb {
                host_vbus_drv: host-vbus-drv {
                        rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
index 49c10d33df302b7d967f0861c1424f636026a943..77e03655aca3626ad369b81b572b755987fd1609 100644 (file)
                        "Headphone Jack", "HPOUTR",
                        "IN2L", "Line In Jack",
                        "IN2R", "Line In Jack",
-                       "MICBIAS", "IN1L",
+                       "Mic", "MICBIAS",
                        "IN1L", "Mic";
 
                atmel,ssc-controller = <&ssc0>;
index 1b0f30c2c4a58d907aafd9d54e80d11e80d5722c..b94995d1889fc3ca780d69ac79a9c3be53620189 100644 (file)
 
                        pit: timer@fc068630 {
                                compatible = "atmel,at91sam9260-pit";
-                               reg = <0xfc068630 0xf>;
+                               reg = <0xfc068630 0x10>;
                                interrupts = <3 IRQ_TYPE_LEVEL_HIGH 5>;
                                clocks = <&h32ck>;
                        };
index a8c00ee7522a1872ee5af06debe66c6acdba49f8..3d0b8755caeee62f77ac214d343ab40cebba2ce0 100644 (file)
                stmpe2401_1 {
                        stmpe2401_1_nhk_mode: stmpe2401_1_nhk {
                                nhk_cfg1 {
-                                       ste,pins = "GPIO76_B20"; // IRQ line
+                                       pins = "GPIO76_B20"; // IRQ line
                                        ste,input = <0>;
                                };
                                nhk_cfg2 {
-                                       ste,pins = "GPIO77_B8"; // reset line
+                                       pins = "GPIO77_B8"; // reset line
                                        ste,output = <1>;
                                };
                        };
                stmpe2401_2 {
                        stmpe2401_2_nhk_mode: stmpe2401_2_nhk {
                                nhk_cfg1 {
-                                       ste,pins = "GPIO78_A8"; // IRQ line
+                                       pins = "GPIO78_A8"; // IRQ line
                                        ste,input = <0>;
                                };
                                nhk_cfg2 {
-                                       ste,pins = "GPIO79_C9"; // reset line
+                                       pins = "GPIO79_C9"; // reset line
                                        ste,output = <1>;
                                };
                        };
index 7b4099fcf81788714def505ff009e2b7a4948db2..d5c4669224b1734178f1a04efd42e9d5ec9cda27 100644 (file)
 
        aliases {
                ethernet0 = &emac;
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-               serial3 = &uart3;
-               serial4 = &uart4;
-               serial5 = &uart5;
-               serial6 = &uart6;
-               serial7 = &uart7;
        };
 
        chosen {
                                 <&ahb_gates 44>;
                        status = "disabled";
                };
+
+               framebuffer@1 {
+                       compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+                       allwinner,pipeline = "de_fe0-de_be0-lcd0-hdmi";
+                       clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+                                <&ahb_gates 44>, <&ahb_gates 46>;
+                       status = "disabled";
+               };
        };
 
        cpus {
                        reg-names = "phy_ctrl", "pmu1", "pmu2";
                        clocks = <&usb_clk 8>;
                        clock-names = "usb_phy";
-                       resets = <&usb_clk 1>, <&usb_clk 2>;
-                       reset-names = "usb1_reset", "usb2_reset";
+                       resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>;
+                       reset-names = "usb0_reset", "usb1_reset", "usb2_reset";
                        status = "disabled";
                };
 
index fe3c559ca6a8e6d24412abe6d2a81c2a6b97bdda..bfa742817690d823d2044d3e6397f2237abb8cd9 100644 (file)
        model = "Olimex A10s-Olinuxino Micro";
        compatible = "olimex,a10s-olinuxino-micro", "allwinner,sun5i-a10s";
 
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart2;
+               serial2 = &uart3;
+       };
+
        soc@01c00000 {
                emac: ethernet@01c0b000 {
                        pinctrl-names = "default";
index 1b76667f3182694ffb7d055cb8f8e7230809a0bf..2e7d8263799d77fe864a4776285844deb6a21fa3 100644 (file)
 
        aliases {
                ethernet0 = &emac;
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-               serial3 = &uart3;
        };
 
        chosen {
                        reg-names = "phy_ctrl", "pmu1";
                        clocks = <&usb_clk 8>;
                        clock-names = "usb_phy";
-                       resets = <&usb_clk 1>;
-                       reset-names = "usb1_reset";
+                       resets = <&usb_clk 0>, <&usb_clk 1>;
+                       reset-names = "usb0_reset", "usb1_reset";
                        status = "disabled";
                };
 
index eeed1f236ee8c400465cbe87824516462dc6ec63..c7be3abd9fcc31a9ab3280b0a7b4a01ba73880b4 100644 (file)
        model = "HSG H702";
        compatible = "hsg,h702", "allwinner,sun5i-a13";
 
+       aliases {
+               serial0 = &uart1;
+       };
+
        soc@01c00000 {
                mmc0: mmc@01c0f000 {
                        pinctrl-names = "default";
index 916ee8bb826f7186380ecaf967d55488f84db6aa..3decefb3c37ac438c27574e7aed940fa2a684ea8 100644 (file)
        model = "Olimex A13-Olinuxino Micro";
        compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
 
+       aliases {
+               serial0 = &uart1;
+       };
+
        soc@01c00000 {
                mmc0: mmc@01c0f000 {
                        pinctrl-names = "default";
index e31d291d14cbcd22add60622a9a2e83b8206ea11..b421f7fa197b475f7e0e3e23637c1acf6a7624ec 100644 (file)
        model = "Olimex A13-Olinuxino";
        compatible = "olimex,a13-olinuxino", "allwinner,sun5i-a13";
 
+       aliases {
+               serial0 = &uart1;
+       };
+
        soc@01c00000 {
                mmc0: mmc@01c0f000 {
                        pinctrl-names = "default";
index c35217ea1f6473653b4d67ce953f3c761fa043a0..c556688f8b8ba400a7bef986690e40a633f836e2 100644 (file)
 / {
        interrupt-parent = <&intc>;
 
-       aliases {
-               serial0 = &uart1;
-               serial1 = &uart3;
-       };
-
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
                        reg-names = "phy_ctrl", "pmu1";
                        clocks = <&usb_clk 8>;
                        clock-names = "usb_phy";
-                       resets = <&usb_clk 1>;
-                       reset-names = "usb1_reset";
+                       resets = <&usb_clk 0>, <&usb_clk 1>;
+                       reset-names = "usb0_reset", "usb1_reset";
                        status = "disabled";
                };
 
index f47156b6572bbaf09872686b70f09268200c3cc9..1e7e7bcf83071f005b2fd57c5fc8112432104f35 100644 (file)
        interrupt-parent = <&gic>;
 
        aliases {
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-               serial3 = &uart3;
-               serial4 = &uart4;
-               serial5 = &uart5;
                ethernet0 = &gmac;
        };
 
index 1cf1214cc068f2e197335cfbfc10d1bf9054636d..bd7b15add6972d26fbcffdfa010fe3435141c0b5 100644 (file)
        model = "LeMaker Banana Pi";
        compatible = "lemaker,bananapi", "allwinner,sun7i-a20";
 
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart3;
+               serial2 = &uart7;
+       };
+
        soc@01c00000 {
                spi0: spi@01c05000 {
                        pinctrl-names = "default";
index 0e4bfa3b2b8540b361b07f9cf1c943c4cba8a9c6..0bcefcbbb756e0b7d7e8ad7450413e0c01c2a273 100644 (file)
        model = "Merrii A20 Hummingbird";
        compatible = "merrii,a20-hummingbird", "allwinner,sun7i-a20";
 
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart2;
+               serial2 = &uart3;
+               serial3 = &uart4;
+               serial4 = &uart5;
+       };
+
        soc@01c00000 {
                mmc0: mmc@01c0f000 {
                        pinctrl-names = "default";
index 9d669cdf031d1aa1ea78c2d8a7c23b713dff3f98..66cc7770719867d8331b30b296611a1921bfac9b 100644 (file)
@@ -20,6 +20,9 @@
        compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20";
 
        aliases {
+               serial0 = &uart0;
+               serial1 = &uart6;
+               serial2 = &uart7;
                spi0 = &spi1;
                spi1 = &spi2;
        };
index e21ce5992d565c348ae3b798ad232cd8f6c16c6b..89749ce34a844ef8777649a712232631534467d1 100644 (file)
 
        aliases {
                ethernet0 = &gmac;
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-               serial3 = &uart3;
-               serial4 = &uart4;
-               serial5 = &uart5;
-               serial6 = &uart6;
-               serial7 = &uart7;
        };
 
        chosen {
index 7f2117ce6985b1de46cfd2fbfbc42fb76e19a1d7..32ad80804dbbc3d31adb703b373c62e9cf597beb 100644 (file)
        model = "Ippo Q8H Dual Core Tablet (v5)";
        compatible = "ippo,q8h-v5", "allwinner,sun8i-a23";
 
+       aliases {
+               serial0 = &r_uart;
+       };
+
        chosen {
                bootargs = "earlyprintk console=ttyS0,115200";
        };
index 0746cd1024d7a73b32bcbf6002954a4859d77ee5..86584fcf5e323bc43489c79be74e43ef8931d3a2 100644 (file)
 / {
        interrupt-parent = <&gic>;
 
-       aliases {
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-               serial3 = &uart3;
-               serial4 = &uart4;
-               serial5 = &r_uart;
-       };
-
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
index 506948f582eee37a11fdb17ea5a7f5eb7277b390..11ec71072e815ac5b4e54a3db3cace2ee81b78b8 100644 (file)
        model = "Merrii A80 Optimus Board";
        compatible = "merrii,a80-optimus", "allwinner,sun9i-a80";
 
+       aliases {
+               serial0 = &uart0;
+               serial1 = &uart4;
+       };
+
        chosen {
                bootargs = "earlyprintk console=ttyS0,115200";
        };
index 494714f67b57821816f1b484659765aca58b8eb0..9ef4438206a9986ed82b733ebeaf961f474b742a 100644 (file)
 / {
        interrupt-parent = <&gic>;
 
-       aliases {
-               serial0 = &uart0;
-               serial1 = &uart1;
-               serial2 = &uart2;
-               serial3 = &uart3;
-               serial4 = &uart4;
-               serial5 = &uart5;
-               serial6 = &r_uart;
-       };
-
        cpus {
                #address-cells = <1>;
                #size-cells = <0>;
index ea282c7c0ca5645394a28e313fbad1deac339882..e2fed27122497b6f330904f43de95739b6cbe6cb 100644 (file)
                clock-frequency = <400000>;
 
                magnetometer@c {
-                       compatible = "ak,ak8975";
+                       compatible = "asahi-kasei,ak8975";
                        reg = <0xc>;
                        interrupt-parent = <&gpio>;
                        interrupts = <TEGRA_GPIO(N, 5) IRQ_TYPE_LEVEL_HIGH>;
index a0f762159cb26501b517a1af0d529da8abc42283..f2b64b1b00fa5231fc2493164fcc89f434687cd1 100644 (file)
 
 &fec0 {
        phy-mode = "rmii";
+       phy-handle = <&ethphy0>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec0>;
        status = "okay";
+
+       mdio {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               ethphy0: ethernet-phy@0 {
+                       reg = <0>;
+               };
+
+               ethphy1: ethernet-phy@1 {
+                       reg = <1>;
+               };
+       };
 };
 
 &fec1 {
        phy-mode = "rmii";
+       phy-handle = <&ethphy1>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_fec1>;
        status = "okay";
index 5ef14de00a29ba2f433fc93a47d95912569817c8..3d0c5d65c741933fad5947aa028dfdf11f7eda4d 100644 (file)
@@ -84,7 +84,8 @@ CONFIG_DEBUG_GPIO=y
 CONFIG_POWER_SUPPLY=y
 CONFIG_BATTERY_SBS=y
 CONFIG_CHARGER_TPS65090=y
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
+CONFIG_SENSORS_LM90=y
 CONFIG_THERMAL=y
 CONFIG_EXYNOS_THERMAL=y
 CONFIG_EXYNOS_THERMAL_CORE=y
@@ -109,11 +110,26 @@ CONFIG_REGULATOR_S2MPA01=y
 CONFIG_REGULATOR_S2MPS11=y
 CONFIG_REGULATOR_S5M8767=y
 CONFIG_REGULATOR_TPS65090=y
+CONFIG_DRM=y
+CONFIG_DRM_BRIDGE=y
+CONFIG_DRM_PTN3460=y
+CONFIG_DRM_PS8622=y
+CONFIG_DRM_EXYNOS=y
+CONFIG_DRM_EXYNOS_FIMD=y
+CONFIG_DRM_EXYNOS_DP=y
+CONFIG_DRM_PANEL=y
+CONFIG_DRM_PANEL_SIMPLE=y
 CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_SIMPLE=y
 CONFIG_EXYNOS_VIDEO=y
 CONFIG_EXYNOS_MIPI_DSI=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
+CONFIG_BACKLIGHT_PWM=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONT_7x14=y
index 2328fe752e9c5ed6066534a0332724b3c4f8d8e5..bc393b7e5ece1f1f985d994e01312f8cf5814837 100644 (file)
@@ -338,6 +338,7 @@ CONFIG_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_MVEBU=y
 CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_EXYNOS=y
 CONFIG_USB_EHCI_TEGRA=y
 CONFIG_USB_EHCI_HCD_STI=y
 CONFIG_USB_EHCI_HCD_PLATFORM=y
index c2c3a852af9fcb28a4fc03bf69322fad6cf52f79..667d9d52aa01aaa230bd2e12a9b4575778285f38 100644 (file)
@@ -68,7 +68,7 @@ CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
-CONFIG_GENERIC_CPUFREQ_CPU0=y
+CONFIG_CPUFREQ_DT=y
 # CONFIG_ARM_OMAP2PLUS_CPUFREQ is not set
 CONFIG_CPU_IDLE=y
 CONFIG_BINFMT_MISC=y
index 66ce17655bb9e29a73f58ebd9a4716735fcf9739..7b0152321b20baa3178d6f9135f12cb62a27987f 100644 (file)
@@ -38,6 +38,16 @@ static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
        vcpu->arch.hcr = HCR_GUEST_MASK;
 }
 
+static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.hcr;
+}
+
+static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
+{
+       vcpu->arch.hcr = hcr;
+}
+
 static inline bool vcpu_mode_is_32bit(struct kvm_vcpu *vcpu)
 {
        return 1;
index 254e0650e48bbc1d07a81d091c8e33570f983851..04b4ea0b550a111811876369bce25358f4d1965e 100644 (file)
@@ -125,9 +125,6 @@ struct kvm_vcpu_arch {
         * Anything that is not used directly from assembly code goes
         * here.
         */
-       /* dcache set/way operation pending */
-       int last_pcpu;
-       cpumask_t require_dcache_flush;
 
        /* Don't run the guest on this vcpu */
        bool pause;
index 63e0ecc0490180e8b8b5e548b6b6a17b95b725e1..1bca8f8af4424154d69289bb32793a42ff223d30 100644 (file)
@@ -44,6 +44,7 @@
 
 #ifndef __ASSEMBLY__
 
+#include <linux/highmem.h>
 #include <asm/cacheflush.h>
 #include <asm/pgalloc.h>
 
@@ -161,13 +162,10 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
        return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
 }
 
-static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
-                                            unsigned long size,
-                                            bool ipa_uncached)
+static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+                                              unsigned long size,
+                                              bool ipa_uncached)
 {
-       if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
-               kvm_flush_dcache_to_poc((void *)hva, size);
-       
        /*
         * If we are going to insert an instruction page and the icache is
         * either VIPT or PIPT, there is a potential problem where the host
@@ -179,18 +177,77 @@ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
         *
         * VIVT caches are tagged using both the ASID and the VMID and doesn't
         * need any kind of flushing (DDI 0406C.b - Page B3-1392).
+        *
+        * We need to do this through a kernel mapping (using the
+        * user-space mapping has proved to be the wrong
+        * solution). For that, we need to kmap one page at a time,
+        * and iterate over the range.
         */
-       if (icache_is_pipt()) {
-               __cpuc_coherent_user_range(hva, hva + size);
-       } else if (!icache_is_vivt_asid_tagged()) {
+
+       bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
+
+       VM_BUG_ON(size & PAGE_MASK);
+
+       if (!need_flush && !icache_is_pipt())
+               goto vipt_cache;
+
+       while (size) {
+               void *va = kmap_atomic_pfn(pfn);
+
+               if (need_flush)
+                       kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+
+               if (icache_is_pipt())
+                       __cpuc_coherent_user_range((unsigned long)va,
+                                                  (unsigned long)va + PAGE_SIZE);
+
+               size -= PAGE_SIZE;
+               pfn++;
+
+               kunmap_atomic(va);
+       }
+
+vipt_cache:
+       if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) {
                /* any kind of VIPT cache */
                __flush_icache_all();
        }
 }
 
+static inline void __kvm_flush_dcache_pte(pte_t pte)
+{
+       void *va = kmap_atomic(pte_page(pte));
+
+       kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+
+       kunmap_atomic(va);
+}
+
+static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
+{
+       unsigned long size = PMD_SIZE;
+       pfn_t pfn = pmd_pfn(pmd);
+
+       while (size) {
+               void *va = kmap_atomic_pfn(pfn);
+
+               kvm_flush_dcache_to_poc(va, PAGE_SIZE);
+
+               pfn++;
+               size -= PAGE_SIZE;
+
+               kunmap_atomic(va);
+       }
+}
+
+static inline void __kvm_flush_dcache_pud(pud_t pud)
+{
+}
+
 #define kvm_virt_to_phys(x)            virt_to_idmap((unsigned long)(x))
 
-void stage2_flush_vm(struct kvm *kvm);
+void kvm_set_way_flush(struct kvm_vcpu *vcpu);
+void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
 
 #endif /* !__ASSEMBLY__ */
 
index 705bb7620673a10222e3258d94158ab8ec1555c9..0c3f5a0dafd32c04af58eec20e6af09f2efca0fe 100644 (file)
 #define __NR_getrandom                 (__NR_SYSCALL_BASE+384)
 #define __NR_memfd_create              (__NR_SYSCALL_BASE+385)
 #define __NR_bpf                       (__NR_SYSCALL_BASE+386)
+#define __NR_execveat                  (__NR_SYSCALL_BASE+387)
 
 /*
  * The following SWIs are ARM private.
index e51833f8cc387118ae3826a0a78a533f4ff90a5f..05745eb838c599dc2dd6034a71b8ebec619b9995 100644 (file)
                CALL(sys_getrandom)
 /* 385 */      CALL(sys_memfd_create)
                CALL(sys_bpf)
+               CALL(sys_execveat)
 #ifndef syscalls_counted
 .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
 #define syscalls_counted
index 4176df721bf09bace95bad96d1c194e5b6b7a038..1a0045abead7562be1e27163e0aee3c6afbe9b40 100644 (file)
        .endm
 
        .macro  restore_user_regs, fast = 0, offset = 0
-       ldr     r1, [sp, #\offset + S_PSR]      @ get calling cpsr
-       ldr     lr, [sp, #\offset + S_PC]!      @ get pc
+       mov     r2, sp
+       ldr     r1, [r2, #\offset + S_PSR]      @ get calling cpsr
+       ldr     lr, [r2, #\offset + S_PC]!      @ get pc
        msr     spsr_cxsf, r1                   @ save in spsr_svc
 #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K)
        @ We must avoid clrex due to Cortex-A15 erratum #830321
-       strex   r1, r2, [sp]                    @ clear the exclusive monitor
+       strex   r1, r2, [r2]                    @ clear the exclusive monitor
 #endif
        .if     \fast
-       ldmdb   sp, {r1 - lr}^                  @ get calling r1 - lr
+       ldmdb   r2, {r1 - lr}^                  @ get calling r1 - lr
        .else
-       ldmdb   sp, {r0 - lr}^                  @ get calling r0 - lr
+       ldmdb   r2, {r0 - lr}^                  @ get calling r0 - lr
        .endif
        mov     r0, r0                          @ ARMv5T and earlier require a nop
                                                @ after ldm {}^
-       add     sp, sp, #S_FRAME_SIZE - S_PC
+       add     sp, sp, #\offset + S_FRAME_SIZE
        movs    pc, lr                          @ return & move spsr_svc into cpsr
        .endm
 
index f7c65adaa428c9eabd2c5080ae097a374c2206f5..557e128e4df08ce711d4bab89952eae0f1d6d7ea 100644 (file)
@@ -116,8 +116,14 @@ int armpmu_event_set_period(struct perf_event *event)
                ret = 1;
        }
 
-       if (left > (s64)armpmu->max_period)
-               left = armpmu->max_period;
+       /*
+        * Limit the maximum period to prevent the counter value
+        * from overtaking the one we are about to program. In
+        * effect we are reducing max_period to account for
+        * interrupt latency (and we are being very conservative).
+        */
+       if (left > (armpmu->max_period >> 1))
+               left = armpmu->max_period >> 1;
 
        local64_set(&hwc->prev_count, (u64)-left);
 
index 6e4379c67cbc191e58fa28c4dbf25b10f887c536..592dda3f21fff05f7024abbcebbe2e55bc44947f 100644 (file)
@@ -28,3 +28,11 @@ u64 perf_reg_abi(struct task_struct *task)
 {
        return PERF_SAMPLE_REGS_ABI_32;
 }
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs,
+                       struct pt_regs *regs_user_copy)
+{
+       regs_user->regs = task_pt_regs(current);
+       regs_user->abi = perf_reg_abi(current);
+}
index f9c863911038ac7d2cbdb5c3d154edd482df8d8a..e55408e965596964ff8c8708dcfec529a559b1bc 100644 (file)
@@ -657,10 +657,13 @@ int __init arm_add_memory(u64 start, u64 size)
 
        /*
         * Ensure that start/size are aligned to a page boundary.
-        * Size is appropriately rounded down, start is rounded up.
+        * Size is rounded down, start is rounded up.
         */
-       size -= start & ~PAGE_MASK;
        aligned_start = PAGE_ALIGN(start);
+       if (aligned_start > start + size)
+               size = 0;
+       else
+               size -= aligned_start - start;
 
 #ifndef CONFIG_ARCH_PHYS_ADDR_T_64BIT
        if (aligned_start > ULONG_MAX) {
@@ -1046,6 +1049,15 @@ static int c_show(struct seq_file *m, void *v)
                seq_printf(m, "model name\t: %s rev %d (%s)\n",
                           cpu_name, cpuid & 15, elf_platform);
 
+#if defined(CONFIG_SMP)
+               seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
+                          per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ),
+                          (per_cpu(cpu_data, i).loops_per_jiffy / (5000UL/HZ)) % 100);
+#else
+               seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
+                          loops_per_jiffy / (500000/HZ),
+                          (loops_per_jiffy / (5000/HZ)) % 100);
+#endif
                /* dump out the processor features */
                seq_puts(m, "Features\t: ");
 
index 5e6052e18850a9d04071bbaf03f595fc8ecf00e0..86ef244c5a24b4fa80b20da26c5d522832a61d59 100644 (file)
@@ -387,6 +387,18 @@ asmlinkage void secondary_start_kernel(void)
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
+       int cpu;
+       unsigned long bogosum = 0;
+
+       for_each_online_cpu(cpu)
+               bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy;
+
+       printk(KERN_INFO "SMP: Total of %d processors activated "
+              "(%lu.%02lu BogoMIPS).\n",
+              num_online_cpus(),
+              bogosum / (500000/HZ),
+              (bogosum / (5000/HZ)) % 100);
+
        hyp_mode_check();
 }
 
index 2d6d91001062f975981dd9beed2b43815f73c238..0b0d58a905c43ba05afc61ca06341bfab348b528 100644 (file)
@@ -281,15 +281,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        vcpu->cpu = cpu;
        vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
 
-       /*
-        * Check whether this vcpu requires the cache to be flushed on
-        * this physical CPU. This is a consequence of doing dcache
-        * operations by set/way on this vcpu. We do it here to be in
-        * a non-preemptible section.
-        */
-       if (cpumask_test_and_clear_cpu(cpu, &vcpu->arch.require_dcache_flush))
-               flush_cache_all(); /* We'd really want v7_flush_dcache_all() */
-
        kvm_arm_set_running_vcpu(vcpu);
 }
 
@@ -541,7 +532,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
 
                vcpu->mode = OUTSIDE_GUEST_MODE;
-               vcpu->arch.last_pcpu = smp_processor_id();
                kvm_guest_exit();
                trace_kvm_exit(*vcpu_pc(vcpu));
                /*
index 7928dbdf210239a71f4f35e8ef289e9c2e8f0375..f3d88dc388bc560778d49dacfded70aebde44a89 100644 (file)
@@ -189,82 +189,40 @@ static bool access_l2ectlr(struct kvm_vcpu *vcpu,
        return true;
 }
 
-/* See note at ARM ARM B1.14.4 */
+/*
+ * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
+ */
 static bool access_dcsw(struct kvm_vcpu *vcpu,
                        const struct coproc_params *p,
                        const struct coproc_reg *r)
 {
-       unsigned long val;
-       int cpu;
-
        if (!p->is_write)
                return read_from_write_only(vcpu, p);
 
-       cpu = get_cpu();
-
-       cpumask_setall(&vcpu->arch.require_dcache_flush);
-       cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
-
-       /* If we were already preempted, take the long way around */
-       if (cpu != vcpu->arch.last_pcpu) {
-               flush_cache_all();
-               goto done;
-       }
-
-       val = *vcpu_reg(vcpu, p->Rt1);
-
-       switch (p->CRm) {
-       case 6:                 /* Upgrade DCISW to DCCISW, as per HCR.SWIO */
-       case 14:                /* DCCISW */
-               asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r" (val));
-               break;
-
-       case 10:                /* DCCSW */
-               asm volatile("mcr p15, 0, %0, c7, c10, 2" : : "r" (val));
-               break;
-       }
-
-done:
-       put_cpu();
-
+       kvm_set_way_flush(vcpu);
        return true;
 }
 
 /*
  * Generic accessor for VM registers. Only called as long as HCR_TVM
- * is set.
+ * is set.  If the guest enables the MMU, we stop trapping the VM
+ * sys_regs and leave it in complete control of the caches.
+ *
+ * Used by the cpu-specific code.
  */
-static bool access_vm_reg(struct kvm_vcpu *vcpu,
-                         const struct coproc_params *p,
-                         const struct coproc_reg *r)
+bool access_vm_reg(struct kvm_vcpu *vcpu,
+                  const struct coproc_params *p,
+                  const struct coproc_reg *r)
 {
+       bool was_enabled = vcpu_has_cache_enabled(vcpu);
+
        BUG_ON(!p->is_write);
 
        vcpu->arch.cp15[r->reg] = *vcpu_reg(vcpu, p->Rt1);
        if (p->is_64bit)
                vcpu->arch.cp15[r->reg + 1] = *vcpu_reg(vcpu, p->Rt2);
 
-       return true;
-}
-
-/*
- * SCTLR accessor. Only called as long as HCR_TVM is set.  If the
- * guest enables the MMU, we stop trapping the VM sys_regs and leave
- * it in complete control of the caches.
- *
- * Used by the cpu-specific code.
- */
-bool access_sctlr(struct kvm_vcpu *vcpu,
-                 const struct coproc_params *p,
-                 const struct coproc_reg *r)
-{
-       access_vm_reg(vcpu, p, r);
-
-       if (vcpu_has_cache_enabled(vcpu)) {     /* MMU+Caches enabled? */
-               vcpu->arch.hcr &= ~HCR_TVM;
-               stage2_flush_vm(vcpu->kvm);
-       }
-
+       kvm_toggle_cache(vcpu, was_enabled);
        return true;
 }
 
index 1a44bbe39643f519ec986d43dcd3e416881d13a9..88d24a3a977812b512e8e0c03144fec796727f8b 100644 (file)
@@ -153,8 +153,8 @@ static inline int cmp_reg(const struct coproc_reg *i1,
 #define is64           .is_64 = true
 #define is32           .is_64 = false
 
-bool access_sctlr(struct kvm_vcpu *vcpu,
-                 const struct coproc_params *p,
-                 const struct coproc_reg *r);
+bool access_vm_reg(struct kvm_vcpu *vcpu,
+                  const struct coproc_params *p,
+                  const struct coproc_reg *r);
 
 #endif /* __ARM_KVM_COPROC_LOCAL_H__ */
index e6f4ae48bda968f8cac7caf6c94ffd1413631436..a7136757d3731534fd169e06938c74b85803cdfc 100644 (file)
@@ -34,7 +34,7 @@
 static const struct coproc_reg a15_regs[] = {
        /* SCTLR: swapped by interrupt.S. */
        { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
-                       access_sctlr, reset_val, c1_SCTLR, 0x00C50078 },
+                       access_vm_reg, reset_val, c1_SCTLR, 0x00C50078 },
 };
 
 static struct kvm_coproc_target_table a15_target_table = {
index 17fc7cd479d3e75d322c207ffa35d42f8785d7ee..b19e46d1b2c08187cc70d4e86742ea4a470ec83f 100644 (file)
@@ -37,7 +37,7 @@
 static const struct coproc_reg a7_regs[] = {
        /* SCTLR: swapped by interrupt.S. */
        { CRn( 1), CRm( 0), Op1( 0), Op2( 0), is32,
-                       access_sctlr, reset_val, c1_SCTLR, 0x00C50878 },
+                       access_vm_reg, reset_val, c1_SCTLR, 0x00C50878 },
 };
 
 static struct kvm_coproc_target_table a7_target_table = {
index 1dc9778a00af358431bbed021ba2d5244642debb..136662547ca6298f0fd5b6f2c73c7aea557ff472 100644 (file)
@@ -58,6 +58,26 @@ static void kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
                kvm_call_hyp(__kvm_tlb_flush_vmid_ipa, kvm, ipa);
 }
 
+/*
+ * D-Cache management functions. They take the page table entries by
+ * value, as they are flushing the cache using the kernel mapping (or
+ * kmap on 32bit).
+ */
+static void kvm_flush_dcache_pte(pte_t pte)
+{
+       __kvm_flush_dcache_pte(pte);
+}
+
+static void kvm_flush_dcache_pmd(pmd_t pmd)
+{
+       __kvm_flush_dcache_pmd(pmd);
+}
+
+static void kvm_flush_dcache_pud(pud_t pud)
+{
+       __kvm_flush_dcache_pud(pud);
+}
+
 static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
                                  int min, int max)
 {
@@ -119,6 +139,26 @@ static void clear_pmd_entry(struct kvm *kvm, pmd_t *pmd, phys_addr_t addr)
        put_page(virt_to_page(pmd));
 }
 
+/*
+ * Unmapping vs dcache management:
+ *
+ * If a guest maps certain memory pages as uncached, all writes will
+ * bypass the data cache and go directly to RAM.  However, the CPUs
+ * can still speculate reads (not writes) and fill cache lines with
+ * data.
+ *
+ * Those cache lines will be *clean* cache lines though, so a
+ * clean+invalidate operation is equivalent to an invalidate
+ * operation, because no cache lines are marked dirty.
+ *
+ * Those clean cache lines could be filled prior to an uncached write
+ * by the guest, and the cache coherent IO subsystem would therefore
+ * end up writing old data to disk.
+ *
+ * This is why right after unmapping a page/section and invalidating
+ * the corresponding TLBs, we call kvm_flush_dcache_p*() to make sure
+ * the IO subsystem will never hit in the cache.
+ */
 static void unmap_ptes(struct kvm *kvm, pmd_t *pmd,
                       phys_addr_t addr, phys_addr_t end)
 {
@@ -128,9 +168,16 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd,
        start_pte = pte = pte_offset_kernel(pmd, addr);
        do {
                if (!pte_none(*pte)) {
+                       pte_t old_pte = *pte;
+
                        kvm_set_pte(pte, __pte(0));
-                       put_page(virt_to_page(pte));
                        kvm_tlb_flush_vmid_ipa(kvm, addr);
+
+                       /* No need to invalidate the cache for device mappings */
+                       if ((pte_val(old_pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE)
+                               kvm_flush_dcache_pte(old_pte);
+
+                       put_page(virt_to_page(pte));
                }
        } while (pte++, addr += PAGE_SIZE, addr != end);
 
@@ -149,8 +196,13 @@ static void unmap_pmds(struct kvm *kvm, pud_t *pud,
                next = kvm_pmd_addr_end(addr, end);
                if (!pmd_none(*pmd)) {
                        if (kvm_pmd_huge(*pmd)) {
+                               pmd_t old_pmd = *pmd;
+
                                pmd_clear(pmd);
                                kvm_tlb_flush_vmid_ipa(kvm, addr);
+
+                               kvm_flush_dcache_pmd(old_pmd);
+
                                put_page(virt_to_page(pmd));
                        } else {
                                unmap_ptes(kvm, pmd, addr, next);
@@ -173,8 +225,13 @@ static void unmap_puds(struct kvm *kvm, pgd_t *pgd,
                next = kvm_pud_addr_end(addr, end);
                if (!pud_none(*pud)) {
                        if (pud_huge(*pud)) {
+                               pud_t old_pud = *pud;
+
                                pud_clear(pud);
                                kvm_tlb_flush_vmid_ipa(kvm, addr);
+
+                               kvm_flush_dcache_pud(old_pud);
+
                                put_page(virt_to_page(pud));
                        } else {
                                unmap_pmds(kvm, pud, addr, next);
@@ -209,10 +266,9 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
 
        pte = pte_offset_kernel(pmd, addr);
        do {
-               if (!pte_none(*pte)) {
-                       hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
-                       kvm_flush_dcache_to_poc((void*)hva, PAGE_SIZE);
-               }
+               if (!pte_none(*pte) &&
+                   (pte_val(*pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE)
+                       kvm_flush_dcache_pte(*pte);
        } while (pte++, addr += PAGE_SIZE, addr != end);
 }
 
@@ -226,12 +282,10 @@ static void stage2_flush_pmds(struct kvm *kvm, pud_t *pud,
        do {
                next = kvm_pmd_addr_end(addr, end);
                if (!pmd_none(*pmd)) {
-                       if (kvm_pmd_huge(*pmd)) {
-                               hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
-                               kvm_flush_dcache_to_poc((void*)hva, PMD_SIZE);
-                       } else {
+                       if (kvm_pmd_huge(*pmd))
+                               kvm_flush_dcache_pmd(*pmd);
+                       else
                                stage2_flush_ptes(kvm, pmd, addr, next);
-                       }
                }
        } while (pmd++, addr = next, addr != end);
 }
@@ -246,12 +300,10 @@ static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
        do {
                next = kvm_pud_addr_end(addr, end);
                if (!pud_none(*pud)) {
-                       if (pud_huge(*pud)) {
-                               hva_t hva = gfn_to_hva(kvm, addr >> PAGE_SHIFT);
-                               kvm_flush_dcache_to_poc((void*)hva, PUD_SIZE);
-                       } else {
+                       if (pud_huge(*pud))
+                               kvm_flush_dcache_pud(*pud);
+                       else
                                stage2_flush_pmds(kvm, pud, addr, next);
-                       }
                }
        } while (pud++, addr = next, addr != end);
 }
@@ -278,7 +330,7 @@ static void stage2_flush_memslot(struct kvm *kvm,
  * Go through the stage 2 page tables and invalidate any cache lines
  * backing memory already mapped to the VM.
  */
-void stage2_flush_vm(struct kvm *kvm)
+static void stage2_flush_vm(struct kvm *kvm)
 {
        struct kvm_memslots *slots;
        struct kvm_memory_slot *memslot;
@@ -905,6 +957,12 @@ static bool kvm_is_device_pfn(unsigned long pfn)
        return !pfn_valid(pfn);
 }
 
+static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+                                     unsigned long size, bool uncached)
+{
+       __coherent_cache_guest_page(vcpu, pfn, size, uncached);
+}
+
 static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                          struct kvm_memory_slot *memslot, unsigned long hva,
                          unsigned long fault_status)
@@ -994,8 +1052,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                        kvm_set_s2pmd_writable(&new_pmd);
                        kvm_set_pfn_dirty(pfn);
                }
-               coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE,
-                                         fault_ipa_uncached);
+               coherent_cache_guest_page(vcpu, pfn, PMD_SIZE, fault_ipa_uncached);
                ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
        } else {
                pte_t new_pte = pfn_pte(pfn, mem_type);
@@ -1003,8 +1060,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                        kvm_set_s2pte_writable(&new_pte);
                        kvm_set_pfn_dirty(pfn);
                }
-               coherent_cache_guest_page(vcpu, hva, PAGE_SIZE,
-                                         fault_ipa_uncached);
+               coherent_cache_guest_page(vcpu, pfn, PAGE_SIZE, fault_ipa_uncached);
                ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte,
                        pgprot_val(mem_type) == pgprot_val(PAGE_S2_DEVICE));
        }
@@ -1411,3 +1467,71 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
        unmap_stage2_range(kvm, gpa, size);
        spin_unlock(&kvm->mmu_lock);
 }
+
+/*
+ * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
+ *
+ * Main problems:
+ * - S/W ops are local to a CPU (not broadcast)
+ * - We have line migration behind our back (speculation)
+ * - System caches don't support S/W at all (damn!)
+ *
+ * In the face of the above, the best we can do is to try and convert
+ * S/W ops to VA ops. Because the guest is not allowed to infer the
+ * S/W to PA mapping, it can only use S/W to nuke the whole cache,
+ * which is a rather good thing for us.
+ *
+ * Also, it is only used when turning caches on/off ("The expected
+ * usage of the cache maintenance instructions that operate by set/way
+ * is associated with the cache maintenance instructions associated
+ * with the powerdown and powerup of caches, if this is required by
+ * the implementation.").
+ *
+ * We use the following policy:
+ *
+ * - If we trap a S/W operation, we enable VM trapping to detect
+ *   caches being turned on/off, and do a full clean.
+ *
+ * - We flush the caches on both caches being turned on and off.
+ *
+ * - Once the caches are enabled, we stop trapping VM ops.
+ */
+void kvm_set_way_flush(struct kvm_vcpu *vcpu)
+{
+       unsigned long hcr = vcpu_get_hcr(vcpu);
+
+       /*
+        * If this is the first time we do a S/W operation
+        * (i.e. HCR_TVM not set) flush the whole memory, and set the
+        * VM trapping.
+        *
+        * Otherwise, rely on the VM trapping to wait for the MMU +
+        * Caches to be turned off. At that point, we'll be able to
+        * clean the caches again.
+        */
+       if (!(hcr & HCR_TVM)) {
+               trace_kvm_set_way_flush(*vcpu_pc(vcpu),
+                                       vcpu_has_cache_enabled(vcpu));
+               stage2_flush_vm(vcpu->kvm);
+               vcpu_set_hcr(vcpu, hcr | HCR_TVM);
+       }
+}
+
+void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled)
+{
+       bool now_enabled = vcpu_has_cache_enabled(vcpu);
+
+       /*
+        * If switching the MMU+caches on, need to invalidate the caches.
+        * If switching it off, need to clean the caches.
+        * Clean + invalidate does the trick always.
+        */
+       if (now_enabled != was_enabled)
+               stage2_flush_vm(vcpu->kvm);
+
+       /* Caches are now on, stop trapping VM ops (until a S/W op) */
+       if (now_enabled)
+               vcpu_set_hcr(vcpu, vcpu_get_hcr(vcpu) & ~HCR_TVM);
+
+       trace_kvm_toggle_cache(*vcpu_pc(vcpu), was_enabled, now_enabled);
+}
index b1d640f78623971337ad08072efdcc981c124c0f..b6a6e71022010bf09ae9b52aad981e745c67ef74 100644 (file)
@@ -223,6 +223,45 @@ TRACE_EVENT(kvm_hvc,
                  __entry->vcpu_pc, __entry->r0, __entry->imm)
 );
 
+TRACE_EVENT(kvm_set_way_flush,
+           TP_PROTO(unsigned long vcpu_pc, bool cache),
+           TP_ARGS(vcpu_pc, cache),
+
+           TP_STRUCT__entry(
+                   __field(    unsigned long,  vcpu_pc         )
+                   __field(    bool,           cache           )
+           ),
+
+           TP_fast_assign(
+                   __entry->vcpu_pc            = vcpu_pc;
+                   __entry->cache              = cache;
+           ),
+
+           TP_printk("S/W flush at 0x%016lx (cache %s)",
+                     __entry->vcpu_pc, __entry->cache ? "on" : "off")
+);
+
+TRACE_EVENT(kvm_toggle_cache,
+           TP_PROTO(unsigned long vcpu_pc, bool was, bool now),
+           TP_ARGS(vcpu_pc, was, now),
+
+           TP_STRUCT__entry(
+                   __field(    unsigned long,  vcpu_pc         )
+                   __field(    bool,           was             )
+                   __field(    bool,           now             )
+           ),
+
+           TP_fast_assign(
+                   __entry->vcpu_pc            = vcpu_pc;
+                   __entry->was                = was;
+                   __entry->now                = now;
+           ),
+
+           TP_printk("VM op at 0x%016lx (cache was %s, now %s)",
+                     __entry->vcpu_pc, __entry->was ? "on" : "off",
+                     __entry->now ? "on" : "off")
+);
+
 #endif /* _TRACE_KVM_H */
 
 #undef TRACE_INCLUDE_PATH
index 8fb9ef5333f17648d8a28aaa0385badc9c0ed65a..97f7367d32b8a2b9af60abb3f6b4df68dd860489 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/of_platform.h>
 #include <linux/phy.h>
 #include <linux/clk-provider.h>
+#include <linux/phy.h>
 
 #include <asm/setup.h>
 #include <asm/irq.h>
 
 #include "generic.h"
 
+static int ksz8081_phy_fixup(struct phy_device *phy)
+{
+       int value;
+
+       value = phy_read(phy, 0x16);
+       value &= ~0x20;
+       phy_write(phy, 0x16, value);
+
+       return 0;
+}
+
 static void __init sama5_dt_device_init(void)
 {
+       if (of_machine_is_compatible("atmel,sama5d4ek") &&
+          IS_ENABLED(CONFIG_PHYLIB)) {
+               phy_register_fixup_for_id("fc028000.etherne:00",
+                                               ksz8081_phy_fixup);
+       }
+
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
 }
 
index 5951660d1bd2363db0326cd83b07fcec7cc908f1..2daef619d0534d626daef9ac2bfd8fcacbb91a19 100644 (file)
@@ -144,7 +144,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
                post_div_table[1].div = 1;
                post_div_table[2].div = 1;
                video_div_table[1].div = 1;
-               video_div_table[2].div = 1;
+               video_div_table[3].div = 1;
        }
 
        clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
index 17354a11356fbd0291ca5629db26446370c951d2..5a3e5a159e708b35a13427b6c766d48bc8cf15b0 100644 (file)
@@ -558,6 +558,9 @@ static void __init imx6sx_clocks_init(struct device_node *ccm_node)
        clk_set_parent(clks[IMX6SX_CLK_GPU_CORE_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
        clk_set_parent(clks[IMX6SX_CLK_GPU_AXI_SEL], clks[IMX6SX_CLK_PLL3_PFD0]);
 
+       clk_set_parent(clks[IMX6SX_CLK_QSPI1_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+       clk_set_parent(clks[IMX6SX_CLK_QSPI2_SEL], clks[IMX6SX_CLK_PLL2_BUS]);
+
        /* Set initial power mode */
        imx6q_set_lpm(WAIT_CLOCKED);
 }
index 3585cb394e9b952388e4f26bfb5e950bfd0ad9eb..ccef8806bb58771b16a87dc80edc32e585597d29 100644 (file)
@@ -189,6 +189,13 @@ static void __init armada_375_380_coherency_init(struct device_node *np)
        coherency_cpu_base = of_iomap(np, 0);
        arch_ioremap_caller = armada_pcie_wa_ioremap_caller;
 
+       /*
+        * We should switch the PL310 to I/O coherency mode only if
+        * I/O coherency is actually enabled.
+        */
+       if (!coherency_available())
+               return;
+
        /*
         * Add the PL310 property "arm,io-coherent". This makes sure the
         * outer sync operation is not used, which allows to
@@ -246,9 +253,14 @@ static int coherency_type(void)
        return type;
 }
 
+/*
+ * As a precaution, we currently completely disable hardware I/O
+ * coherency, until enough testing is done with automatic I/O
+ * synchronization barriers to validate that it is a proper solution.
+ */
 int coherency_available(void)
 {
-       return coherency_type() != COHERENCY_FABRIC_TYPE_NONE;
+       return false;
 }
 
 int __init coherency_init(void)
index 608079a1aba6774e5ff6682354ecc08ba2d7a882..b61c049f92d6a361de57b16fe11c4773c12b88c6 100644 (file)
@@ -77,6 +77,24 @@ MACHINE_END
 #endif
 
 #ifdef CONFIG_ARCH_OMAP3
+/* Some boards need board name for legacy userspace in /proc/cpuinfo */
+static const char *const n900_boards_compat[] __initconst = {
+       "nokia,omap3-n900",
+       NULL,
+};
+
+DT_MACHINE_START(OMAP3_N900_DT, "Nokia RX-51 board")
+       .reserve        = omap_reserve,
+       .map_io         = omap3_map_io,
+       .init_early     = omap3430_init_early,
+       .init_machine   = omap_generic_init,
+       .init_late      = omap3_init_late,
+       .init_time      = omap3_sync32k_timer_init,
+       .dt_compat      = n900_boards_compat,
+       .restart        = omap3xxx_restart,
+MACHINE_END
+
+/* Generic omap3 boards, most boards can use these */
 static const char *const omap3_boards_compat[] __initconst = {
        "ti,omap3430",
        "ti,omap3",
index 377eea849e7bcdaf1142f6b1087ed6857a92b046..64e44d6d07c0c89ba5aa4fc3114111b32b261857 100644 (file)
@@ -211,6 +211,7 @@ extern struct device *omap2_get_iva_device(void);
 extern struct device *omap2_get_l3_device(void);
 extern struct device *omap4_get_dsp_device(void);
 
+unsigned int omap4_xlate_irq(unsigned int hwirq);
 void omap_gic_of_init(void);
 
 #ifdef CONFIG_CACHE_L2X0
@@ -249,6 +250,7 @@ extern void omap4_cpu_die(unsigned int cpu);
 extern struct smp_operations omap4_smp_ops;
 
 extern void omap5_secondary_startup(void);
+extern void omap5_secondary_hyp_startup(void);
 #endif
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PM)
index a3c013345c45fa3b495924edaaa8628e636e147d..a80ac2d70bb1bca42084187851c09b914cd51871 100644 (file)
 #define OMAP5XXX_CONTROL_STATUS                0x134
 #define OMAP5_DEVICETYPE_MASK          (0x7 << 6)
 
+/* DRA7XX CONTROL CORE BOOTSTRAP */
+#define DRA7_CTRL_CORE_BOOTSTRAP       0x6c4
+#define DRA7_SPEEDSELECT_MASK          (0x3 << 8)
+
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
  * that should be added.
index 4993d4bfe9b2a579d7adcc37726cb6828a78f130..6d1dffca6c7b6d68f3bd6e29a16bf5334c54a5fb 100644 (file)
@@ -22,6 +22,7 @@
 
 /* Physical address needed since MMU not enabled yet on secondary core */
 #define AUX_CORE_BOOT0_PA                      0x48281800
+#define API_HYP_ENTRY                          0x102
 
 /*
  * OMAP5 specific entry point for secondary CPU to jump from ROM
@@ -40,6 +41,26 @@ wait:        ldr     r2, =AUX_CORE_BOOT0_PA  @ read from AuxCoreBoot0
        bne     wait
        b       secondary_startup
 ENDPROC(omap5_secondary_startup)
+/*
+ * Same as omap5_secondary_startup except we call into the ROM to
+ * enable HYP mode first.  This is called instead of
+ * omap5_secondary_startup if the primary CPU was put into HYP mode by
+ * the boot loader.
+ */
+ENTRY(omap5_secondary_hyp_startup)
+wait_2:        ldr     r2, =AUX_CORE_BOOT0_PA  @ read from AuxCoreBoot0
+       ldr     r0, [r2]
+       mov     r0, r0, lsr #5
+       mrc     p15, 0, r4, c0, c0, 5
+       and     r4, r4, #0x0f
+       cmp     r0, r4
+       bne     wait_2
+       ldr     r12, =API_HYP_ENTRY
+       adr     r0, hyp_boot
+       smc     #0
+hyp_boot:
+       b       secondary_startup
+ENDPROC(omap5_secondary_hyp_startup)
 /*
  * OMAP4 specific entry point for secondary CPU to jump from ROM
  * code.  This routine also provides a holding flag into which
index 256e84ef0f679072324892a04d90817b81ceee36..5305ec7341eca5579398a10b72f263a2fbbe8e0e 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/irqchip/arm-gic.h>
 
 #include <asm/smp_scu.h>
+#include <asm/virt.h>
 
 #include "omap-secure.h"
 #include "omap-wakeupgen.h"
@@ -227,8 +228,16 @@ static void __init omap4_smp_prepare_cpus(unsigned int max_cpus)
        if (omap_secure_apis_support())
                omap_auxcoreboot_addr(virt_to_phys(startup_addr));
        else
-               writel_relaxed(virt_to_phys(omap5_secondary_startup),
-                              base + OMAP_AUX_CORE_BOOT_1);
+               /*
+                * If the boot CPU is in HYP mode then start secondary
+                * CPU in HYP mode as well.
+                */
+               if ((__boot_cpu_mode & MODE_MASK) == HYP_MODE)
+                       writel_relaxed(virt_to_phys(omap5_secondary_hyp_startup),
+                                      base + OMAP_AUX_CORE_BOOT_1);
+               else
+                       writel_relaxed(virt_to_phys(omap5_secondary_startup),
+                                      base + OMAP_AUX_CORE_BOOT_1);
 
 }
 
index b7cb44abe49b35a7a03c3c9f172eca5daeb7b4a7..cc30e49a4cc278d08a44895fbf28797a94b6cfbd 100644 (file)
@@ -256,6 +256,38 @@ static int __init omap4_sar_ram_init(void)
 }
 omap_early_initcall(omap4_sar_ram_init);
 
+static struct of_device_id gic_match[] = {
+       { .compatible = "arm,cortex-a9-gic", },
+       { .compatible = "arm,cortex-a15-gic", },
+       { },
+};
+
+static struct device_node *gic_node;
+
+unsigned int omap4_xlate_irq(unsigned int hwirq)
+{
+       struct of_phandle_args irq_data;
+       unsigned int irq;
+
+       if (!gic_node)
+               gic_node = of_find_matching_node(NULL, gic_match);
+
+       if (WARN_ON(!gic_node))
+               return hwirq;
+
+       irq_data.np = gic_node;
+       irq_data.args_count = 3;
+       irq_data.args[0] = 0;
+       irq_data.args[1] = hwirq - OMAP44XX_IRQ_GIC_START;
+       irq_data.args[2] = IRQ_TYPE_LEVEL_HIGH;
+
+       irq = irq_create_of_mapping(&irq_data);
+       if (WARN_ON(!irq))
+               irq = hwirq;
+
+       return irq;
+}
+
 void __init omap_gic_of_init(void)
 {
        struct device_node *np;
index cbb908dc5cf0e09bec45ce7fbf7814936883d9fc..9025ffffd2dc1d066fcb54a2cf44f2bf9a73525c 100644 (file)
@@ -3534,9 +3534,15 @@ int omap_hwmod_fill_resources(struct omap_hwmod *oh, struct resource *res)
 
        mpu_irqs_cnt = _count_mpu_irqs(oh);
        for (i = 0; i < mpu_irqs_cnt; i++) {
+               unsigned int irq;
+
+               if (oh->xlate_irq)
+                       irq = oh->xlate_irq((oh->mpu_irqs + i)->irq);
+               else
+                       irq = (oh->mpu_irqs + i)->irq;
                (res + r)->name = (oh->mpu_irqs + i)->name;
-               (res + r)->start = (oh->mpu_irqs + i)->irq;
-               (res + r)->end = (oh->mpu_irqs + i)->irq;
+               (res + r)->start = irq;
+               (res + r)->end = irq;
                (res + r)->flags = IORESOURCE_IRQ;
                r++;
        }
index 35ca6efbec31eb533ce039761024a7260371b2a1..5b42fafcaf55102fc5631b4095b920353c4329c8 100644 (file)
@@ -676,6 +676,7 @@ struct omap_hwmod {
        spinlock_t                      _lock;
        struct list_head                node;
        struct omap_hwmod_ocp_if        *_mpu_port;
+       unsigned int                    (*xlate_irq)(unsigned int);
        u16                             flags;
        u8                              mpu_rt_idx;
        u8                              response_lat;
index c314b3c31117e8cbee248db6aec7c0feb64f4fa9..f5e68a7820251360dc1aad459e259ee1c6d217ae 100644 (file)
@@ -479,6 +479,7 @@ static struct omap_hwmod omap44xx_dma_system_hwmod = {
        .class          = &omap44xx_dma_hwmod_class,
        .clkdm_name     = "l3_dma_clkdm",
        .mpu_irqs       = omap44xx_dma_system_irqs,
+       .xlate_irq      = omap4_xlate_irq,
        .main_clk       = "l3_div_ck",
        .prcm = {
                .omap4 = {
@@ -640,6 +641,7 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
        .class          = &omap44xx_dispc_hwmod_class,
        .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_dispc_irqs,
+       .xlate_irq      = omap4_xlate_irq,
        .sdma_reqs      = omap44xx_dss_dispc_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
@@ -693,6 +695,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
        .class          = &omap44xx_dsi_hwmod_class,
        .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_dsi1_irqs,
+       .xlate_irq      = omap4_xlate_irq,
        .sdma_reqs      = omap44xx_dss_dsi1_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
@@ -726,6 +729,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
        .class          = &omap44xx_dsi_hwmod_class,
        .clkdm_name     = "l3_dss_clkdm",
        .mpu_irqs       = omap44xx_dss_dsi2_irqs,
+       .xlate_irq      = omap4_xlate_irq,
        .sdma_reqs      = omap44xx_dss_dsi2_sdma_reqs,
        .main_clk       = "dss_dss_clk",
        .prcm = {
@@ -784,6 +788,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
         */
        .flags          = HWMOD_SWSUP_SIDLE,
        .mpu_irqs       = omap44xx_dss_hdmi_irqs,
+       .xlate_irq      = omap4_xlate_irq,
        .sdma_reqs      = omap44xx_dss_hdmi_sdma_reqs,
        .main_clk       = "dss_48mhz_clk",
        .prcm = {
index 3e9523084b2ace3005adbd18ceae347eaef3e66a..7c3fac035e936884febd606bcb9d0218428fd91c 100644 (file)
@@ -288,6 +288,7 @@ static struct omap_hwmod omap54xx_dma_system_hwmod = {
        .class          = &omap54xx_dma_hwmod_class,
        .clkdm_name     = "dma_clkdm",
        .mpu_irqs       = omap54xx_dma_system_irqs,
+       .xlate_irq      = omap4_xlate_irq,
        .main_clk       = "l3_iclk_div",
        .prcm = {
                .omap4 = {
index a8e4b582c527476972de36917c144570dd3665b4..6163d66102a3561890240487a592964874cb260c 100644 (file)
@@ -498,6 +498,7 @@ struct omap_prcm_irq_setup {
        u8 nr_irqs;
        const struct omap_prcm_irq *irqs;
        int irq;
+       unsigned int (*xlate_irq)(unsigned int);
        void (*read_pending_irqs)(unsigned long *events);
        void (*ocp_barrier)(void);
        void (*save_and_clear_irqen)(u32 *saved_mask);
index cc170fb81ff76dc018ad6eee2c0e9931ab575f08..408c64efb80700868fa4c8b0138a2763a78bc161 100644 (file)
@@ -49,6 +49,7 @@ static struct omap_prcm_irq_setup omap4_prcm_irq_setup = {
        .irqs                   = omap4_prcm_irqs,
        .nr_irqs                = ARRAY_SIZE(omap4_prcm_irqs),
        .irq                    = 11 + OMAP44XX_IRQ_GIC_START,
+       .xlate_irq              = omap4_xlate_irq,
        .read_pending_irqs      = &omap44xx_prm_read_pending_irqs,
        .ocp_barrier            = &omap44xx_prm_ocp_barrier,
        .save_and_clear_irqen   = &omap44xx_prm_save_and_clear_irqen,
@@ -751,8 +752,10 @@ static int omap44xx_prm_late_init(void)
                }
 
                /* Once OMAP4 DT is filled as well */
-               if (irq_num >= 0)
+               if (irq_num >= 0) {
                        omap4_prcm_irq_setup.irq = irq_num;
+                       omap4_prcm_irq_setup.xlate_irq = NULL;
+               }
        }
 
        omap44xx_prm_enable_io_wakeup();
index 779940cb6e5651d4d5c486878b5cbbef060af1dc..dea2833ca627c84ca67db08d77c24f834c3a0340 100644 (file)
@@ -187,6 +187,7 @@ int omap_prcm_event_to_irq(const char *name)
  */
 void omap_prcm_irq_cleanup(void)
 {
+       unsigned int irq;
        int i;
 
        if (!prcm_irq_setup) {
@@ -211,7 +212,11 @@ void omap_prcm_irq_cleanup(void)
        kfree(prcm_irq_setup->priority_mask);
        prcm_irq_setup->priority_mask = NULL;
 
-       irq_set_chained_handler(prcm_irq_setup->irq, NULL);
+       if (prcm_irq_setup->xlate_irq)
+               irq = prcm_irq_setup->xlate_irq(prcm_irq_setup->irq);
+       else
+               irq = prcm_irq_setup->irq;
+       irq_set_chained_handler(irq, NULL);
 
        if (prcm_irq_setup->base_irq > 0)
                irq_free_descs(prcm_irq_setup->base_irq,
@@ -259,6 +264,7 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
        int offset, i;
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
+       unsigned int irq;
 
        if (!irq_setup)
                return -EINVAL;
@@ -298,7 +304,11 @@ int omap_prcm_register_chain_handler(struct omap_prcm_irq_setup *irq_setup)
                                1 << (offset & 0x1f);
        }
 
-       irq_set_chained_handler(irq_setup->irq, omap_prcm_irq_handler);
+       if (irq_setup->xlate_irq)
+               irq = irq_setup->xlate_irq(irq_setup->irq);
+       else
+               irq = irq_setup->irq;
+       irq_set_chained_handler(irq, omap_prcm_irq_handler);
 
        irq_setup->base_irq = irq_alloc_descs(-1, 0, irq_setup->nr_regs * 32,
                0);
index 4f61148ec1689b667f30a5259aa98037c5fa06ec..7d45c84c69ba38a3da362456c941bb39ef90d7a2 100644 (file)
@@ -54,6 +54,7 @@
 
 #include "soc.h"
 #include "common.h"
+#include "control.h"
 #include "powerdomain.h"
 #include "omap-secure.h"
 
@@ -496,7 +497,8 @@ static void __init realtime_counter_init(void)
        void __iomem *base;
        static struct clk *sys_clk;
        unsigned long rate;
-       unsigned int reg, num, den;
+       unsigned int reg;
+       unsigned long long num, den;
 
        base = ioremap(REALTIME_COUNTER_BASE, SZ_32);
        if (!base) {
@@ -511,13 +513,42 @@ static void __init realtime_counter_init(void)
        }
 
        rate = clk_get_rate(sys_clk);
+
+       if (soc_is_dra7xx()) {
+               /*
+                * Errata i856 says the 32.768KHz crystal does not start at
+                * power on, so the CPU falls back to an emulated 32KHz clock
+                * based on sysclk / 610 instead. This causes the master counter
+                * frequency to not be 6.144MHz but at sysclk / 610 * 375 / 2
+                * (OR sysclk * 75 / 244)
+                *
+                * This affects at least the DRA7/AM572x 1.0, 1.1 revisions.
+                * Of course any board built without a populated 32.768KHz
+                * crystal would also need this fix even if the CPU is fixed
+                * later.
+                *
+                * Either case can be detected by using the two speedselect bits
+                * If they are not 0, then the 32.768KHz clock driving the
+                * coarse counter that corrects the fine counter every time it
+                * ticks is actually rate/610 rather than 32.768KHz and we
+                * should compensate to avoid the 570ppm (at 20MHz, much worse
+                * at other rates) too fast system time.
+                */
+               reg = omap_ctrl_readl(DRA7_CTRL_CORE_BOOTSTRAP);
+               if (reg & DRA7_SPEEDSELECT_MASK) {
+                       num = 75;
+                       den = 244;
+                       goto sysclk1_based;
+               }
+       }
+
        /* Numerator/denumerator values refer TRM Realtime Counter section */
        switch (rate) {
-       case 1200000:
+       case 12000000:
                num = 64;
                den = 125;
                break;
-       case 1300000:
+       case 13000000:
                num = 768;
                den = 1625;
                break;
@@ -529,11 +560,11 @@ static void __init realtime_counter_init(void)
                num = 192;
                den = 625;
                break;
-       case 2600000:
+       case 26000000:
                num = 384;
                den = 1625;
                break;
-       case 2700000:
+       case 27000000:
                num = 256;
                den = 1125;
                break;
@@ -545,6 +576,7 @@ static void __init realtime_counter_init(void)
                break;
        }
 
+sysclk1_based:
        /* Program numerator and denumerator registers */
        reg = readl_relaxed(base + INCREMENTER_NUMERATOR_OFFSET) &
                        NUMERATOR_DENUMERATOR_MASK;
@@ -556,7 +588,7 @@ static void __init realtime_counter_init(void)
        reg |= den;
        writel_relaxed(reg, base + INCREMENTER_DENUMERATOR_RELOAD_OFFSET);
 
-       arch_timer_freq = (rate / den) * num;
+       arch_timer_freq = DIV_ROUND_UP_ULL(rate * num, den);
        set_cntfreq();
 
        iounmap(base);
index 4457e731f7a4f0029cb3fe4e3811d5396097d2f2..292eca0e78ed07e3f7358c99671f8573b16aaecf 100644 (file)
@@ -66,19 +66,24 @@ void __init omap_pmic_init(int bus, u32 clkrate,
        omap_register_i2c_bus(bus, clkrate, &pmic_i2c_board_info, 1);
 }
 
+#ifdef CONFIG_ARCH_OMAP4
 void __init omap4_pmic_init(const char *pmic_type,
                    struct twl4030_platform_data *pmic_data,
                    struct i2c_board_info *devices, int nr_devices)
 {
        /* PMIC part*/
+       unsigned int irq;
+
        omap_mux_init_signal("sys_nirq1", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
        omap_mux_init_signal("fref_clk0_out.sys_drm_msecure", OMAP_PIN_OUTPUT);
-       omap_pmic_init(1, 400, pmic_type, 7 + OMAP44XX_IRQ_GIC_START, pmic_data);
+       irq = omap4_xlate_irq(7 + OMAP44XX_IRQ_GIC_START);
+       omap_pmic_init(1, 400, pmic_type, irq, pmic_data);
 
        /* Register additional devices on i2c1 bus if needed */
        if (devices)
                i2c_register_board_info(1, devices, nr_devices);
 }
+#endif
 
 void __init omap_pmic_late_init(void)
 {
index d226b71d21d5c6c0bdb702af93323f59934b22d4..a611f48525828fcef5cb1dbacc9d2430f5de8867 100644 (file)
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <linux/irqchip.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/hardware/cache-l2x0.h>
 #include "core.h"
 
+#define RK3288_GRF_SOC_CON0 0x244
+
+static void __init rockchip_timer_init(void)
+{
+       if (of_machine_is_compatible("rockchip,rk3288")) {
+               struct regmap *grf;
+
+               /*
+                * Disable auto jtag/sdmmc switching that causes issues
+                * with the mmc controllers making them unreliable
+                */
+               grf = syscon_regmap_lookup_by_compatible("rockchip,rk3288-grf");
+               if (!IS_ERR(grf))
+                       regmap_write(grf, RK3288_GRF_SOC_CON0, 0x10000000);
+               else
+                       pr_err("rockchip: could not get grf syscon\n");
+       }
+
+       of_clk_init(NULL);
+       clocksource_of_init();
+}
+
 static void __init rockchip_dt_init(void)
 {
        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
@@ -42,6 +68,7 @@ static const char * const rockchip_board_dt_compat[] = {
 DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
        .l2c_aux_val    = 0,
        .l2c_aux_mask   = ~0,
+       .init_time      = rockchip_timer_init,
        .dt_compat      = rockchip_board_dt_compat,
        .init_machine   = rockchip_dt_init,
 MACHINE_END
index 66f67816a844623977a4595ef23642ed381b3549..444f22d370f0ef7a4e35957abfc3d458e3d7e49e 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/kernel.h>
 #include <linux/mfd/tmio.h>
 #include <linux/mmc/host.h>
@@ -273,6 +275,22 @@ static void __init ape6evm_add_standard_devices(void)
                                      sizeof(ape6evm_leds_pdata));
 }
 
+static void __init ape6evm_legacy_init_time(void)
+{
+       /* Do not invoke DT-based timers via clocksource_of_init() */
+}
+
+static void __init ape6evm_legacy_init_irq(void)
+{
+       void __iomem *gic_dist_base = ioremap_nocache(0xf1001000, 0x1000);
+       void __iomem *gic_cpu_base = ioremap_nocache(0xf1002000, 0x1000);
+
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
+
+       /* Do not invoke DT-based interrupt code via irqchip_init() */
+}
+
+
 static const char *ape6evm_boards_compat_dt[] __initdata = {
        "renesas,ape6evm",
        NULL,
@@ -280,7 +298,9 @@ static const char *ape6evm_boards_compat_dt[] __initdata = {
 
 DT_MACHINE_START(APE6EVM_DT, "ape6evm")
        .init_early     = shmobile_init_delay,
+       .init_irq       = ape6evm_legacy_init_irq,
        .init_machine   = ape6evm_add_standard_devices,
        .init_late      = shmobile_init_late,
        .dt_compat      = ape6evm_boards_compat_dt,
+       .init_time      = ape6evm_legacy_init_time,
 MACHINE_END
index f8197eb6e5669ada1b8ddd57e7bb09e42bedfe62..65b128dd4072b8070fb1bb65edd97b7abb4c3d5e 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/kernel.h>
 #include <linux/leds.h>
 #include <linux/mfd/tmio.h>
@@ -811,6 +813,16 @@ static void __init lager_init(void)
                                          lager_ksz8041_fixup);
 }
 
+static void __init lager_legacy_init_irq(void)
+{
+       void __iomem *gic_dist_base = ioremap_nocache(0xf1001000, 0x1000);
+       void __iomem *gic_cpu_base = ioremap_nocache(0xf1002000, 0x1000);
+
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
+
+       /* Do not invoke DT-based interrupt code via irqchip_init() */
+}
+
 static const char * const lager_boards_compat_dt[] __initconst = {
        "renesas,lager",
        NULL,
@@ -819,6 +831,7 @@ static const char * const lager_boards_compat_dt[] __initconst = {
 DT_MACHINE_START(LAGER_DT, "lager")
        .smp            = smp_ops(r8a7790_smp_ops),
        .init_early     = shmobile_init_delay,
+       .init_irq       = lager_legacy_init_irq,
        .init_time      = rcar_gen2_timer_init,
        .init_machine   = lager_init,
        .init_late      = shmobile_init_late,
index 79ad93dfdae4ee7083f2c2f1351ee863355d20c4..d191cf4197313482b961f1a6ed91f11954eff9a4 100644 (file)
@@ -800,7 +800,14 @@ void __init r8a7740_init_irq_of(void)
        void __iomem *intc_msk_base = ioremap_nocache(0xe6900040, 0x10);
        void __iomem *pfc_inta_ctrl = ioremap_nocache(0xe605807c, 0x4);
 
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+       void __iomem *gic_dist_base = ioremap_nocache(0xc2800000, 0x1000);
+       void __iomem *gic_cpu_base = ioremap_nocache(0xc2000000, 0x1000);
+
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
+#else
        irqchip_init();
+#endif
 
        /* route signals to GIC */
        iowrite32(0x0, pfc_inta_ctrl);
index 170bd146ba1796b801f27e0ca74e2cfd79f0c7e8..cef8895a9b8271dcd27549b7a5f6209cc4cb9abb 100644 (file)
@@ -576,11 +576,18 @@ void __init r8a7778_init_irq_extpin(int irlm)
 void __init r8a7778_init_irq_dt(void)
 {
        void __iomem *base = ioremap_nocache(0xfe700000, 0x00100000);
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+       void __iomem *gic_dist_base = ioremap_nocache(0xfe438000, 0x1000);
+       void __iomem *gic_cpu_base = ioremap_nocache(0xfe430000, 0x1000);
+#endif
 
        BUG_ON(!base);
 
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
+#else
        irqchip_init();
-
+#endif
        /* route all interrupts to ARM */
        __raw_writel(0x73ffffff, base + INT2NTSR0);
        __raw_writel(0xffffffff, base + INT2NTSR1);
index 6156d172cf3108d79c44a397931037a53f1c5266..27dceaf9e688c174910004fc80598f4beb130075 100644 (file)
@@ -720,10 +720,17 @@ static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
 
 void __init r8a7779_init_irq_dt(void)
 {
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+       void __iomem *gic_dist_base = ioremap_nocache(0xf0001000, 0x1000);
+       void __iomem *gic_cpu_base = ioremap_nocache(0xf0000100, 0x1000);
+#endif
        gic_arch_extn.irq_set_wake = r8a7779_set_wake;
 
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+       gic_init(0, 29, gic_dist_base, gic_cpu_base);
+#else
        irqchip_init();
-
+#endif
        /* route all interrupts to ARM */
        __raw_writel(0xffffffff, INT2NTSR0);
        __raw_writel(0x3fffffff, INT2NTSR1);
index 3dd6edd9bd1d3dfe5b6bb7787e4d672c1a6f63be..cc9470dfb1cee51eb50d0597603c6a195d67af5f 100644 (file)
@@ -133,7 +133,9 @@ void __init rcar_gen2_timer_init(void)
 #ifdef CONFIG_COMMON_CLK
        rcar_gen2_clocks_init(mode);
 #endif
+#ifdef CONFIG_ARCH_SHMOBILE_MULTI
        clocksource_of_init();
+#endif
 }
 
 struct memory_reserve_config {
index 93ebe3430bfe707ac234b35f37deb54a1998a531..fb5e1bb34be80b1d5c529a728e55b7a7d41fa8c8 100644 (file)
@@ -595,6 +595,7 @@ static struct platform_device ipmmu_device = {
 
 static struct renesas_intc_irqpin_config irqpin0_platform_data = {
        .irq_base = irq_pin(0), /* IRQ0 -> IRQ7 */
+       .control_parent = true,
 };
 
 static struct resource irqpin0_resources[] = {
@@ -656,6 +657,7 @@ static struct platform_device irqpin1_device = {
 
 static struct renesas_intc_irqpin_config irqpin2_platform_data = {
        .irq_base = irq_pin(16), /* IRQ16 -> IRQ23 */
+       .control_parent = true,
 };
 
 static struct resource irqpin2_resources[] = {
@@ -686,6 +688,7 @@ static struct platform_device irqpin2_device = {
 
 static struct renesas_intc_irqpin_config irqpin3_platform_data = {
        .irq_base = irq_pin(24), /* IRQ24 -> IRQ31 */
+       .control_parent = true,
 };
 
 static struct resource irqpin3_resources[] = {
index f1d027aa7a81ac3361401380553771bdb37d47d2..0edf2a6d2bbef7f78fcb8f5c0396445dde21618c 100644 (file)
@@ -70,6 +70,18 @@ void __init shmobile_init_delay(void)
        if (!max_freq)
                return;
 
+#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
+       /* Non-multiplatform r8a73a4 SoC cannot use arch timer due
+        * to GIC being initialized from C and arch timer via DT */
+       if (of_machine_is_compatible("renesas,r8a73a4"))
+               has_arch_timer = false;
+
+       /* Non-multiplatform r8a7790 SoC cannot use arch timer due
+        * to GIC being initialized from C and arch timer via DT */
+       if (of_machine_is_compatible("renesas,r8a7790"))
+               has_arch_timer = false;
+#endif
+
        if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) {
                if (is_a7_a8_a9)
                        shmobile_setup_delay_hz(max_freq, 1, 3);
index 7864797609b3849628455782c79949f094f6997e..a673c7f7e208efe1bc9b2e2d4ff0cb8ab6a1c5da 100644 (file)
@@ -1940,13 +1940,32 @@ void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
 }
 EXPORT_SYMBOL_GPL(arm_iommu_release_mapping);
 
+static int __arm_iommu_attach_device(struct device *dev,
+                                    struct dma_iommu_mapping *mapping)
+{
+       int err;
+
+       err = iommu_attach_device(mapping->domain, dev);
+       if (err)
+               return err;
+
+       kref_get(&mapping->kref);
+       dev->archdata.mapping = mapping;
+
+       pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
+       return 0;
+}
+
 /**
  * arm_iommu_attach_device
  * @dev: valid struct device pointer
  * @mapping: io address space mapping structure (returned from
  *     arm_iommu_create_mapping)
  *
- * Attaches specified io address space mapping to the provided device,
+ * Attaches specified io address space mapping to the provided device.
+ * This replaces the dma operations (dma_map_ops pointer) with the
+ * IOMMU aware version.
+ *
  * More than one client might be attached to the same io address space
  * mapping.
  */
@@ -1955,25 +1974,16 @@ int arm_iommu_attach_device(struct device *dev,
 {
        int err;
 
-       err = iommu_attach_device(mapping->domain, dev);
+       err = __arm_iommu_attach_device(dev, mapping);
        if (err)
                return err;
 
-       kref_get(&mapping->kref);
-       dev->archdata.mapping = mapping;
-
-       pr_debug("Attached IOMMU controller to %s device.\n", dev_name(dev));
+       set_dma_ops(dev, &iommu_ops);
        return 0;
 }
 EXPORT_SYMBOL_GPL(arm_iommu_attach_device);
 
-/**
- * arm_iommu_detach_device
- * @dev: valid struct device pointer
- *
- * Detaches the provided device from a previously attached map.
- */
-void arm_iommu_detach_device(struct device *dev)
+static void __arm_iommu_detach_device(struct device *dev)
 {
        struct dma_iommu_mapping *mapping;
 
@@ -1989,6 +1999,19 @@ void arm_iommu_detach_device(struct device *dev)
 
        pr_debug("Detached IOMMU controller from %s device.\n", dev_name(dev));
 }
+
+/**
+ * arm_iommu_detach_device
+ * @dev: valid struct device pointer
+ *
+ * Detaches the provided device from a previously attached map.
+ * This voids the dma operations (dma_map_ops pointer)
+ */
+void arm_iommu_detach_device(struct device *dev)
+{
+       __arm_iommu_detach_device(dev);
+       set_dma_ops(dev, NULL);
+}
 EXPORT_SYMBOL_GPL(arm_iommu_detach_device);
 
 static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent)
@@ -2011,7 +2034,7 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size,
                return false;
        }
 
-       if (arm_iommu_attach_device(dev, mapping)) {
+       if (__arm_iommu_attach_device(dev, mapping)) {
                pr_warn("Failed to attached device %s to IOMMU_mapping\n",
                                dev_name(dev));
                arm_iommu_release_mapping(mapping);
@@ -2025,7 +2048,7 @@ static void arm_teardown_iommu_dma_ops(struct device *dev)
 {
        struct dma_iommu_mapping *mapping = dev->archdata.mapping;
 
-       arm_iommu_detach_device(dev);
+       __arm_iommu_detach_device(dev);
        arm_iommu_release_mapping(mapping);
 }
 
index 59424937e52b8839c4fb4504aedbc93584b4304e..9fe8e241335c6edcb0db5077f5d4621aefb68944 100644 (file)
@@ -220,9 +220,6 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level, u
        static const char units[] = "KMGTPE";
        u64 prot = val & pg_level[level].mask;
 
-       if (addr < USER_PGTABLES_CEILING)
-               return;
-
        if (!st->level) {
                st->level = level;
                st->current_prot = prot;
@@ -308,15 +305,13 @@ static void walk_pgd(struct seq_file *m)
        pgd_t *pgd = swapper_pg_dir;
        struct pg_state st;
        unsigned long addr;
-       unsigned i, pgdoff = USER_PGTABLES_CEILING / PGDIR_SIZE;
+       unsigned i;
 
        memset(&st, 0, sizeof(st));
        st.seq = m;
        st.marker = address_markers;
 
-       pgd += pgdoff;
-
-       for (i = pgdoff; i < PTRS_PER_PGD; i++, pgd++) {
+       for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
                addr = i * PGDIR_SIZE;
                if (!pgd_none(*pgd)) {
                        walk_pud(&st, pgd, addr);
index 98ad9c79ea0e6a1e980a5f0c09e4c25389e060e2..2495c8cb47baaddcdb15a209406a9e4b9b4f1f25 100644 (file)
@@ -658,8 +658,8 @@ static struct section_perm ro_perms[] = {
                .start  = (unsigned long)_stext,
                .end    = (unsigned long)__init_begin,
 #ifdef CONFIG_ARM_LPAE
-               .mask   = ~PMD_SECT_RDONLY,
-               .prot   = PMD_SECT_RDONLY,
+               .mask   = ~L_PMD_SECT_RDONLY,
+               .prot   = L_PMD_SECT_RDONLY,
 #else
                .mask   = ~(PMD_SECT_APX | PMD_SECT_AP_WRITE),
                .prot   = PMD_SECT_APX | PMD_SECT_AP_WRITE,
index cda7c40999b6692fef5cb4a4b869b5608d87c5ec..4e6ef896c6195db73f770957e9df619a0be05e06 100644 (file)
@@ -1329,8 +1329,8 @@ static void __init kmap_init(void)
 static void __init map_lowmem(void)
 {
        struct memblock_region *reg;
-       unsigned long kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
-       unsigned long kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
+       phys_addr_t kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
+       phys_addr_t kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
 
        /* Map all the lowmem memory banks. */
        for_each_memblock(memory, reg) {
index 1c43cec971b5cd7196b367d1917baa25a10078bd..0666888639202f4beeb0d0086d969841a96f1700 100644 (file)
@@ -85,6 +85,7 @@ vdso_install:
 # We use MRPROPER_FILES and CLEAN_FILES now
 archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
+       $(Q)$(MAKE) $(clean)=$(boot)/dts
 
 define archhelp
   echo  '* Image.gz      - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
index 3b8d427c398599c85c8d12e3f67f20095ec43bac..c62b0f4d9ef65bf4dfa8503d581c159e5fe9b16b 100644 (file)
@@ -3,6 +3,4 @@ dts-dirs += apm
 dts-dirs += arm
 dts-dirs += cavium
 
-always         := $(dtb-y)
 subdir-y       := $(dts-dirs)
-clean-files    := *.dtb
index cb3073e4e7a83e555992ea544abb658607512ab5..d429129ecb3d03fe3a7460ecd3ed9d02950cb193 100644 (file)
@@ -22,7 +22,7 @@
        };
 
        chosen {
-               stdout-path = &soc_uart0;
+               stdout-path = "serial0:115200n8";
        };
 
        psci {
index dd301be89ecccfb6fe9f1d7c02a69bafcfea1559..5376d908eabedbdc496648c1fe2f4316fcd1cbe3 100644 (file)
@@ -1,6 +1,7 @@
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_FHANDLE=y
 CONFIG_AUDIT=y
 CONFIG_NO_HZ_IDLE=y
 CONFIG_HIGH_RES_TIMERS=y
@@ -13,14 +14,12 @@ CONFIG_TASK_IO_ACCOUNTING=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_RESOURCE_COUNTERS=y
 CONFIG_MEMCG=y
 CONFIG_MEMCG_SWAP=y
 CONFIG_MEMCG_KMEM=y
 CONFIG_CGROUP_HUGETLB=y
 # CONFIG_UTS_NS is not set
 # CONFIG_IPC_NS is not set
-# CONFIG_PID_NS is not set
 # CONFIG_NET_NS is not set
 CONFIG_SCHED_AUTOGROUP=y
 CONFIG_BLK_DEV_INITRD=y
@@ -92,7 +91,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_VIRTIO_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
-# CONFIG_HMC_DRV is not set
 CONFIG_SPI=y
 CONFIG_SPI_PL022=y
 CONFIG_GPIO_PL061=y
@@ -133,6 +131,8 @@ CONFIG_EXT3_FS=y
 CONFIG_EXT4_FS=y
 CONFIG_FANOTIFY=y
 CONFIG_FANOTIFY_ACCESS_PERMISSIONS=y
+CONFIG_QUOTA=y
+CONFIG_AUTOFS4_FS=y
 CONFIG_FUSE_FS=y
 CONFIG_CUSE=y
 CONFIG_VFAT_FS=y
@@ -152,14 +152,15 @@ CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_KERNEL=y
 CONFIG_LOCKUP_DETECTOR=y
 # CONFIG_SCHED_DEBUG is not set
+# CONFIG_DEBUG_PREEMPT is not set
 # CONFIG_FTRACE is not set
+CONFIG_KEYS=y
 CONFIG_SECURITY=y
 CONFIG_CRYPTO_ANSI_CPRNG=y
 CONFIG_ARM64_CRYPTO=y
 CONFIG_CRYPTO_SHA1_ARM64_CE=y
 CONFIG_CRYPTO_SHA2_ARM64_CE=y
 CONFIG_CRYPTO_GHASH_ARM64_CE=y
-CONFIG_CRYPTO_AES_ARM64_CE=y
 CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
 CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
 CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
index b1fa4e61471814f78e4c5f99ed349afc98541121..fbe0ca31a99cafc0769a6d6b93622016af637ee4 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <asm/barrier.h>
 
+#include <linux/bug.h>
 #include <linux/init.h>
 #include <linux/types.h>
 
index ace70682499b69b3e23e36215bb8760c6ea67cb3..8e797b2fcc0186b6f5f505303b51fbea0eff2e94 100644 (file)
@@ -39,6 +39,7 @@ struct cpuinfo_arm64 {
        u64             reg_id_aa64pfr0;
        u64             reg_id_aa64pfr1;
 
+       u32             reg_id_dfr0;
        u32             reg_id_isar0;
        u32             reg_id_isar1;
        u32             reg_id_isar2;
@@ -51,6 +52,10 @@ struct cpuinfo_arm64 {
        u32             reg_id_mmfr3;
        u32             reg_id_pfr0;
        u32             reg_id_pfr1;
+
+       u32             reg_mvfr0;
+       u32             reg_mvfr1;
+       u32             reg_mvfr2;
 };
 
 DECLARE_PER_CPU(struct cpuinfo_arm64, cpu_data);
index d34189bceff7760a83b6095339bd3bce7646d4ac..9ce3e680ae1c6f2b78dab11bf5d89384f5366f23 100644 (file)
@@ -52,13 +52,14 @@ static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops)
        dev->archdata.dma_ops = ops;
 }
 
-static inline int set_arch_dma_coherent_ops(struct device *dev)
+static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
+                                     struct iommu_ops *iommu, bool coherent)
 {
-       dev->archdata.dma_coherent = true;
-       set_dma_ops(dev, &coherent_swiotlb_dma_ops);
-       return 0;
+       dev->archdata.dma_coherent = coherent;
+       if (coherent)
+               set_dma_ops(dev, &coherent_swiotlb_dma_ops);
 }
-#define set_arch_dma_coherent_ops      set_arch_dma_coherent_ops
+#define arch_setup_dma_ops     arch_setup_dma_ops
 
 /* do not use this function in a driver */
 static inline bool is_device_dma_coherent(struct device *dev)
index 8127e45e263752821c833d1c354a8033372b2a47..3cb4c856b10da40a73c88138d97a2586b21eb6ff 100644 (file)
@@ -41,6 +41,18 @@ void kvm_inject_pabt(struct kvm_vcpu *vcpu, unsigned long addr);
 static inline void vcpu_reset_hcr(struct kvm_vcpu *vcpu)
 {
        vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS;
+       if (test_bit(KVM_ARM_VCPU_EL1_32BIT, vcpu->arch.features))
+               vcpu->arch.hcr_el2 &= ~HCR_RW;
+}
+
+static inline unsigned long vcpu_get_hcr(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.hcr_el2;
+}
+
+static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
+{
+       vcpu->arch.hcr_el2 = hcr;
 }
 
 static inline unsigned long *vcpu_pc(const struct kvm_vcpu *vcpu)
index 0b7dfdb931dff6f9610df181015ce7ecc1a7f16a..acd101a9014d374d2c235f5936a2b6a5c1d7c28f 100644 (file)
@@ -116,9 +116,6 @@ struct kvm_vcpu_arch {
         * Anything that is not used directly from assembly code goes
         * here.
         */
-       /* dcache set/way operation pending */
-       int last_pcpu;
-       cpumask_t require_dcache_flush;
 
        /* Don't run the guest */
        bool pause;
index 14a74f136272b94852d86901ae75c4f329ee2ee3..adcf49547301b1acc598e72722752b36240220be 100644 (file)
@@ -243,24 +243,46 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
        return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
 }
 
-static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
-                                            unsigned long size,
-                                            bool ipa_uncached)
+static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
+                                              unsigned long size,
+                                              bool ipa_uncached)
 {
+       void *va = page_address(pfn_to_page(pfn));
+
        if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
-               kvm_flush_dcache_to_poc((void *)hva, size);
+               kvm_flush_dcache_to_poc(va, size);
 
        if (!icache_is_aliasing()) {            /* PIPT */
-               flush_icache_range(hva, hva + size);
+               flush_icache_range((unsigned long)va,
+                                  (unsigned long)va + size);
        } else if (!icache_is_aivivt()) {       /* non ASID-tagged VIVT */
                /* any kind of VIPT cache */
                __flush_icache_all();
        }
 }
 
+static inline void __kvm_flush_dcache_pte(pte_t pte)
+{
+       struct page *page = pte_page(pte);
+       kvm_flush_dcache_to_poc(page_address(page), PAGE_SIZE);
+}
+
+static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
+{
+       struct page *page = pmd_page(pmd);
+       kvm_flush_dcache_to_poc(page_address(page), PMD_SIZE);
+}
+
+static inline void __kvm_flush_dcache_pud(pud_t pud)
+{
+       struct page *page = pud_page(pud);
+       kvm_flush_dcache_to_poc(page_address(page), PUD_SIZE);
+}
+
 #define kvm_virt_to_phys(x)            __virt_to_phys((unsigned long)(x))
 
-void stage2_flush_vm(struct kvm *kvm);
+void kvm_set_way_flush(struct kvm_vcpu *vcpu);
+void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
 
 #endif /* __ASSEMBLY__ */
 #endif /* __ARM64_KVM_MMU_H__ */
index df22314f57cfda8972fff87a3071f6b82eb0ad71..210d632aa5ad38b44a6a0b49d876e0c9cab5ca6a 100644 (file)
@@ -298,7 +298,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
 #define pfn_pmd(pfn,prot)      (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
 #define mk_pmd(page,prot)      pfn_pmd(page_to_pfn(page),prot)
 
-#define pmd_page(pmd)           pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
 #define pud_write(pud)         pte_write(pud_pte(pud))
 #define pud_pfn(pud)           (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
 
@@ -401,7 +400,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
        return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(addr);
 }
 
-#define pud_page(pud)           pmd_page(pud_pmd(pud))
+#define pud_page(pud)          pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
 
 #endif /* CONFIG_ARM64_PGTABLE_LEVELS > 2 */
 
@@ -437,6 +436,8 @@ static inline pud_t *pud_offset(pgd_t *pgd, unsigned long addr)
        return (pud_t *)pgd_page_vaddr(*pgd) + pud_index(addr);
 }
 
+#define pgd_page(pgd)          pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
+
 #endif  /* CONFIG_ARM64_PGTABLE_LEVELS > 3 */
 
 #define pgd_ERROR(pgd)         __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
index 286b1bec547ce2a060d01cf816893b2b4aef9d12..f9be30ea1cbd8bc5b00cf2627c2e0be47ab54d98 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <asm/fpsimd.h>
 #include <asm/hw_breakpoint.h>
+#include <asm/pgtable-hwdef.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
 
@@ -123,9 +124,6 @@ struct task_struct;
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
 
-/* Prepare to copy thread state - unlazy all lazy status */
-#define prepare_to_copy(tsk)   do { } while (0)
-
 unsigned long get_wchan(struct task_struct *p);
 
 #define cpu_relax()                    barrier()
index 49c9aefd24a50e1892c4df018e784fc44be4617e..23e9432ac11240a15b5dc4fecfe7d275cdfb10db 100644 (file)
@@ -44,7 +44,7 @@
 #define __ARM_NR_compat_cacheflush     (__ARM_NR_COMPAT_BASE+2)
 #define __ARM_NR_compat_set_tls                (__ARM_NR_COMPAT_BASE+5)
 
-#define __NR_compat_syscalls           386
+#define __NR_compat_syscalls           388
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
index 8893cebcea5b8d903fed25db1a6dcb6effa14cef..27224426e0bf920de713c22cd4b6ca125c84d9bf 100644 (file)
@@ -795,3 +795,5 @@ __SYSCALL(__NR_getrandom, sys_getrandom)
 __SYSCALL(__NR_memfd_create, sys_memfd_create)
 #define __NR_bpf 386
 __SYSCALL(__NR_bpf, sys_bpf)
+#define __NR_execveat 387
+__SYSCALL(__NR_execveat, compat_sys_execveat)
index 57b641747534a4bb7a8e0901b685d092b89fbfdc..07d435cf2eea6ee4da81e158b4e26a6be5b14c29 100644 (file)
@@ -147,6 +147,7 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur)
         * If we have AArch32, we care about 32-bit features for compat. These
         * registers should be RES0 otherwise.
         */
+       diff |= CHECK(id_dfr0, boot, cur, cpu);
        diff |= CHECK(id_isar0, boot, cur, cpu);
        diff |= CHECK(id_isar1, boot, cur, cpu);
        diff |= CHECK(id_isar2, boot, cur, cpu);
@@ -165,6 +166,10 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur)
        diff |= CHECK(id_pfr0, boot, cur, cpu);
        diff |= CHECK(id_pfr1, boot, cur, cpu);
 
+       diff |= CHECK(mvfr0, boot, cur, cpu);
+       diff |= CHECK(mvfr1, boot, cur, cpu);
+       diff |= CHECK(mvfr2, boot, cur, cpu);
+
        /*
         * Mismatched CPU features are a recipe for disaster. Don't even
         * pretend to support them.
@@ -189,6 +194,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
        info->reg_id_aa64pfr0 = read_cpuid(ID_AA64PFR0_EL1);
        info->reg_id_aa64pfr1 = read_cpuid(ID_AA64PFR1_EL1);
 
+       info->reg_id_dfr0 = read_cpuid(ID_DFR0_EL1);
        info->reg_id_isar0 = read_cpuid(ID_ISAR0_EL1);
        info->reg_id_isar1 = read_cpuid(ID_ISAR1_EL1);
        info->reg_id_isar2 = read_cpuid(ID_ISAR2_EL1);
@@ -202,6 +208,10 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
        info->reg_id_pfr0 = read_cpuid(ID_PFR0_EL1);
        info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
 
+       info->reg_mvfr0 = read_cpuid(MVFR0_EL1);
+       info->reg_mvfr1 = read_cpuid(MVFR1_EL1);
+       info->reg_mvfr2 = read_cpuid(MVFR2_EL1);
+
        cpuinfo_detect_icache_policy(info);
 
        check_local_cpu_errata();
index 6fac253bc783a44066630643c0b57153825d0be9..2bb4347d0edfd9d703fb96768fcdf6a58ea9aad0 100644 (file)
@@ -326,6 +326,7 @@ void __init efi_idmap_init(void)
 
        /* boot time idmap_pg_dir is incomplete, so fill in missing parts */
        efi_setup_idmap();
+       early_memunmap(memmap.map, memmap.map_end - memmap.map);
 }
 
 static int __init remap_region(efi_memory_desc_t *md, void **new)
@@ -380,7 +381,6 @@ static int __init arm64_enter_virtual_mode(void)
        }
 
        mapsize = memmap.map_end - memmap.map;
-       early_memunmap(memmap.map, mapsize);
 
        if (efi_runtime_disabled()) {
                pr_info("EFI runtime services will be disabled.\n");
index fd027b101de59fd350ed45d2ec928693e4b9be41..9b6f71db270952ad72cbfb30c767fcf2320092f9 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mm.h>
 #include <linux/moduleloader.h>
 #include <linux/vmalloc.h>
+#include <asm/alternative.h>
 #include <asm/insn.h>
 #include <asm/sections.h>
 
index 6762ad705587fa34fff0281546273a6930ddbcbf..3f62b35fb6f157c49c1adb8b4cc3ec2744cc1e48 100644 (file)
@@ -50,3 +50,11 @@ u64 perf_reg_abi(struct task_struct *task)
        else
                return PERF_SAMPLE_REGS_ABI_64;
 }
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs,
+                       struct pt_regs *regs_user_copy)
+{
+       regs_user->regs = task_pt_regs(current);
+       regs_user->abi = perf_reg_abi(current);
+}
index b8099116675459b933b290fd3fda5fd3cd3ecdb3..20fe2932ad0c47d50d0c836acd35686c8777b98a 100644 (file)
@@ -402,6 +402,7 @@ void __init setup_arch(char **cmdline_p)
        request_standard_resources();
 
        efi_idmap_init();
+       early_ioremap_reset();
 
        unflatten_device_tree();
 
index 4f93c67e63de34293dadc0baeb23fe944b27888c..14944e5b28dace9ea083e74f4849d4f40eadef95 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/cacheflush.h>
 #include <asm/cpu_ops.h>
 #include <asm/cputype.h>
+#include <asm/io.h>
 #include <asm/smp_plat.h>
 
 extern void secondary_holding_pen(void);
index 3771b72b6569fbf87acefb6de0741a5af8ec6548..2d6b6065fe7f4ea7ceaf9e728066edb23dae5a0b 100644 (file)
@@ -5,6 +5,7 @@
 #include <asm/debug-monitors.h>
 #include <asm/pgtable.h>
 #include <asm/memory.h>
+#include <asm/mmu_context.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
@@ -98,7 +99,18 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
         */
        ret = __cpu_suspend_enter(arg, fn);
        if (ret == 0) {
-               cpu_switch_mm(mm->pgd, mm);
+               /*
+                * We are resuming from reset with TTBR0_EL1 set to the
+                * idmap to enable the MMU; restore the active_mm mappings in
+                * TTBR0_EL1 unless the active_mm == &init_mm, in which case
+                * the thread entered __cpu_suspend with TTBR0_EL1 set to
+                * reserved TTBR0 page tables and should be restored as such.
+                */
+               if (mm == &init_mm)
+                       cpu_set_reserved_ttbr0();
+               else
+                       cpu_switch_mm(mm->pgd, mm);
+
                flush_tlb_all();
 
                /*
index fbe909fb0a1a8b95ab4f6e3ade19daaa21c70436..c3ca89c27c6b351839ec62f763ca99d34ac5b3c2 100644 (file)
@@ -1014,6 +1014,7 @@ ENTRY(__kvm_tlb_flush_vmid_ipa)
         * Instead, we invalidate Stage-2 for this IPA, and the
         * whole of Stage-1. Weep...
         */
+       lsr     x1, x1, #12
        tlbi    ipas2e1is, x1
        /*
         * We have to ensure completion of the invalidation at Stage-2,
index 70a7816535cd4a9bf575b9767a9a9fd62dbe21e6..0b43265789858cbe71f761eebbc48927834b7fe8 100644 (file)
@@ -90,7 +90,6 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
                        if (!cpu_has_32bit_el1())
                                return -EINVAL;
                        cpu_reset = &default_regs_reset32;
-                       vcpu->arch.hcr_el2 &= ~HCR_RW;
                } else {
                        cpu_reset = &default_regs_reset;
                }
index 3d7c2df89946cc1d1606a4b3401115f10e44ab71..f31e8bb2bc5bd0c7aec76e654fce52f5723e527b 100644 (file)
@@ -69,68 +69,31 @@ static u32 get_ccsidr(u32 csselr)
        return ccsidr;
 }
 
-static void do_dc_cisw(u32 val)
-{
-       asm volatile("dc cisw, %x0" : : "r" (val));
-       dsb(ish);
-}
-
-static void do_dc_csw(u32 val)
-{
-       asm volatile("dc csw, %x0" : : "r" (val));
-       dsb(ish);
-}
-
-/* See note at ARM ARM B1.14.4 */
+/*
+ * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
+ */
 static bool access_dcsw(struct kvm_vcpu *vcpu,
                        const struct sys_reg_params *p,
                        const struct sys_reg_desc *r)
 {
-       unsigned long val;
-       int cpu;
-
        if (!p->is_write)
                return read_from_write_only(vcpu, p);
 
-       cpu = get_cpu();
-
-       cpumask_setall(&vcpu->arch.require_dcache_flush);
-       cpumask_clear_cpu(cpu, &vcpu->arch.require_dcache_flush);
-
-       /* If we were already preempted, take the long way around */
-       if (cpu != vcpu->arch.last_pcpu) {
-               flush_cache_all();
-               goto done;
-       }
-
-       val = *vcpu_reg(vcpu, p->Rt);
-
-       switch (p->CRm) {
-       case 6:                 /* Upgrade DCISW to DCCISW, as per HCR.SWIO */
-       case 14:                /* DCCISW */
-               do_dc_cisw(val);
-               break;
-
-       case 10:                /* DCCSW */
-               do_dc_csw(val);
-               break;
-       }
-
-done:
-       put_cpu();
-
+       kvm_set_way_flush(vcpu);
        return true;
 }
 
 /*
  * Generic accessor for VM registers. Only called as long as HCR_TVM
- * is set.
+ * is set. If the guest enables the MMU, we stop trapping the VM
+ * sys_regs and leave it in complete control of the caches.
  */
 static bool access_vm_reg(struct kvm_vcpu *vcpu,
                          const struct sys_reg_params *p,
                          const struct sys_reg_desc *r)
 {
        unsigned long val;
+       bool was_enabled = vcpu_has_cache_enabled(vcpu);
 
        BUG_ON(!p->is_write);
 
@@ -143,25 +106,7 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
                vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL;
        }
 
-       return true;
-}
-
-/*
- * SCTLR_EL1 accessor. Only called as long as HCR_TVM is set.  If the
- * guest enables the MMU, we stop trapping the VM sys_regs and leave
- * it in complete control of the caches.
- */
-static bool access_sctlr(struct kvm_vcpu *vcpu,
-                        const struct sys_reg_params *p,
-                        const struct sys_reg_desc *r)
-{
-       access_vm_reg(vcpu, p, r);
-
-       if (vcpu_has_cache_enabled(vcpu)) {     /* MMU+Caches enabled? */
-               vcpu->arch.hcr_el2 &= ~HCR_TVM;
-               stage2_flush_vm(vcpu->kvm);
-       }
-
+       kvm_toggle_cache(vcpu, was_enabled);
        return true;
 }
 
@@ -377,7 +322,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
          NULL, reset_mpidr, MPIDR_EL1 },
        /* SCTLR_EL1 */
        { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b000),
-         access_sctlr, reset_val, SCTLR_EL1, 0x00C50078 },
+         access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 },
        /* CPACR_EL1 */
        { Op0(0b11), Op1(0b000), CRn(0b0001), CRm(0b0000), Op2(0b010),
          NULL, reset_val, CPACR_EL1, 0 },
@@ -657,7 +602,7 @@ static const struct sys_reg_desc cp14_64_regs[] = {
  * register).
  */
 static const struct sys_reg_desc cp15_regs[] = {
-       { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR },
+       { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, c1_SCTLR },
        { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 },
        { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 },
        { Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, c2_TTBCR },
index cf33f33333ccd230720207a071399863bd4eb0de..d54dc9ac4b70874af52e4c94054c850b576c9f0d 100644 (file)
@@ -15,6 +15,7 @@
  */
 #include <linux/debugfs.h>
 #include <linux/fs.h>
+#include <linux/io.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
index bac492c12fcc4bd054e09f8db8022b64dcaa8f74..c95464a33f36175d1f7905ad61bd5176654efd0f 100644 (file)
@@ -335,14 +335,8 @@ static int keep_initrd;
 
 void free_initrd_mem(unsigned long start, unsigned long end)
 {
-       if (!keep_initrd) {
-               if (start == initrd_start)
-                       start = round_down(start, PAGE_SIZE);
-               if (end == initrd_end)
-                       end = round_up(end, PAGE_SIZE);
-
+       if (!keep_initrd)
                free_reserved_area((void *)start, (void *)end, 0, "initrd");
-       }
 }
 
 static int __init keepinitrd_setup(char *__unused)
index 2c9412908024d4ce88d8945cf953b0d24437dcaf..164efa009e5be776a52ae16b024d71c8e288ab5c 100644 (file)
 #include <linux/moduleloader.h>
 #include <linux/vmalloc.h>
 
-void module_free(struct module *mod, void *module_region)
+void module_arch_freeing_init(struct module *mod)
 {
        vfree(mod->arch.syminfo);
        mod->arch.syminfo = NULL;
-
-       vfree(module_region);
 }
 
 static inline int check_rela(Elf32_Rela *rela, struct module *module,
@@ -291,12 +289,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
 
        return ret;
 }
-
-int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
-                   struct module *module)
-{
-       vfree(module->arch.syminfo);
-       module->arch.syminfo = NULL;
-
-       return 0;
-}
index 0eca93327195077ec16bdfd99efd7294c6ab2de6..d223a8b57c1eaad282289e75089654153ab598d6 100644 (file)
@@ -142,6 +142,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 6f4bac969bf72e360a6476c55a9e7f667d2d21fb..23eada79439c7abe2734ffdb0945ec66318dff9f 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
index 08a313fc22418c326987dc36c9c9203de639e270..f772068d9e797e0c236e512ac80254063de07802 100644 (file)
@@ -604,7 +604,7 @@ static ssize_t __sync_serial_read(struct file *file,
                                  struct timespec *ts)
 {
        unsigned long flags;
-       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       int dev = MINOR(file_inode(file)->i_rdev);
        int avail;
        struct sync_port *port;
        unsigned char *start;
index 51123f985eb5862a83bf7afcfc22e4bce2ecbda7..af04cb6b6dc9a3777930bd6974a401988cccafcc 100644 (file)
@@ -36,7 +36,7 @@ void *module_alloc(unsigned long size)
 }
 
 /* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_memfree(void *module_region)
 {
        kfree(module_region);
 }
index 1790f22e71a21a859b2b7b1942cbbc503c2d557e..2686a7aa8ec82c50f29592840185b519522c53a7 100644 (file)
@@ -176,6 +176,8 @@ retry:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 67b1d16857593ddc083bf45cc8fd9e19d5430994..0635bd6c2af392fc372b0e02002b1a669a88e33c 100644 (file)
@@ -94,7 +94,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
                                r = &dev->resource[idx];
                                if (!r->start)
                                        continue;
-                               pci_claim_resource(dev, idx);
+                               pci_claim_bridge_resource(dev, idx);
                        }
                }
                pcibios_allocate_bus_resources(&bus->children);
index 9a66372fc7c76019ca874a9c3780c2fc8392266c..ec4917ddf67872aa46b60c6b067b0a67ec5417a4 100644 (file)
@@ -168,6 +168,8 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index f3b51b57740af91e097a7b4b37b4067b5873cd44..95c39b95e97e24f1ed3d7a58cf56dbbefc2ff419 100644 (file)
@@ -11,7 +11,7 @@
 
 
 
-#define NR_syscalls                    318 /* length of syscall table */
+#define NR_syscalls                    319 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 4c2240c1b0cb4b81e219631750c4e61f82ffb750..461079560c78728848b7631de5efbe700d146620 100644 (file)
 #define __NR_getrandom                 1339
 #define __NR_memfd_create              1340
 #define __NR_bpf                       1341
+#define __NR_execveat                  1342
 
 #endif /* _UAPI_ASM_IA64_UNISTD_H */
index 615ef81def494ee804deb7252e343dee3cbd7e56..e795cb848154a451bf12c83ce221123686b238b5 100644 (file)
@@ -893,13 +893,13 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
 }
 
 /* wrapper to silence section mismatch warning */
-int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
+int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu)
 {
        return _acpi_map_lsapic(handle, physid, pcpu);
 }
-EXPORT_SYMBOL(acpi_map_lsapic);
+EXPORT_SYMBOL(acpi_map_cpu);
 
-int acpi_unmap_lsapic(int cpu)
+int acpi_unmap_cpu(int cpu)
 {
        ia64_cpu_to_sapicid[cpu] = -1;
        set_cpu_present(cpu, false);
@@ -910,8 +910,7 @@ int acpi_unmap_lsapic(int cpu)
 
        return (0);
 }
-
-EXPORT_SYMBOL(acpi_unmap_lsapic);
+EXPORT_SYMBOL(acpi_unmap_cpu);
 #endif                         /* CONFIG_ACPI_HOTPLUG_CPU */
 
 #ifdef CONFIG_ACPI_NUMA
index f5e96dffc63c3d0ce54399759ceb9a5fefacde15..fcf8b8cbca0be79607808c81aad2b37456bbef89 100644 (file)
@@ -1779,6 +1779,7 @@ sys_call_table:
        data8 sys_getrandom
        data8 sys_memfd_create                  // 1340
        data8 sys_bpf
+       data8 sys_execveat
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 24603be24c14acbbcb29874b45fb55518fed3cc7..29754aae5177a94ec257021ab00c57f688a61de8 100644 (file)
@@ -305,14 +305,12 @@ plt_target (struct plt_entry *plt)
 #endif /* !USE_BRL */
 
 void
-module_free (struct module *mod, void *module_region)
+module_arch_freeing_init (struct module *mod)
 {
-       if (mod && mod->arch.init_unw_table &&
-           module_region == mod->module_init) {
+       if (mod->arch.init_unw_table) {
                unw_remove_unwind_table(mod->arch.init_unw_table);
                mod->arch.init_unw_table = NULL;
        }
-       vfree(module_region);
 }
 
 /* Have we already seen one of these relocations? */
index 7225dad87094d81e89459e5a61909fa5b2d10ca0..ba5ba7accd0d6bb4dbab34f7fc307c4306347f4a 100644 (file)
@@ -172,6 +172,8 @@ retry:
                 */
                if (fault & VM_FAULT_OOM) {
                        goto out_of_memory;
+               } else if (fault & VM_FAULT_SIGSEGV) {
+                       goto bad_area;
                } else if (fault & VM_FAULT_SIGBUS) {
                        signal = SIGBUS;
                        goto bad_area;
index 291a582777cf3dd0320f4757ea1f9c1fc39dd17c..900cc93e540961903816fd8d69769a3311fdbbf3 100644 (file)
@@ -487,45 +487,39 @@ int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
        return 0;
 }
 
-static int is_valid_resource(struct pci_dev *dev, int idx)
+void pcibios_fixup_device_resources(struct pci_dev *dev)
 {
-       unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
-       struct resource *devr = &dev->resource[idx], *busr;
+       int idx;
 
        if (!dev->bus)
-               return 0;
-
-       pci_bus_for_each_resource(dev->bus, busr, i) {
-               if (!busr || ((busr->flags ^ devr->flags) & type_mask))
-                       continue;
-               if ((devr->start) && (devr->start >= busr->start) &&
-                               (devr->end <= busr->end))
-                       return 1;
-       }
-       return 0;
-}
+               return;
 
-static void pcibios_fixup_resources(struct pci_dev *dev, int start, int limit)
-{
-       int i;
+       for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) {
+               struct resource *r = &dev->resource[idx];
 
-       for (i = start; i < limit; i++) {
-               if (!dev->resource[i].flags)
+               if (!r->flags || r->parent || !r->start)
                        continue;
-               if ((is_valid_resource(dev, i)))
-                       pci_claim_resource(dev, i);
-       }
-}
 
-void pcibios_fixup_device_resources(struct pci_dev *dev)
-{
-       pcibios_fixup_resources(dev, 0, PCI_BRIDGE_RESOURCES);
+               pci_claim_resource(dev, idx);
+       }
 }
 EXPORT_SYMBOL_GPL(pcibios_fixup_device_resources);
 
 static void pcibios_fixup_bridge_resources(struct pci_dev *dev)
 {
-       pcibios_fixup_resources(dev, PCI_BRIDGE_RESOURCES, PCI_NUM_RESOURCES);
+       int idx;
+
+       if (!dev->bus)
+               return;
+
+       for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+               struct resource *r = &dev->resource[idx];
+
+               if (!r->flags || r->parent || !r->start)
+                       continue;
+
+               pci_claim_bridge_resource(dev, idx);
+       }
 }
 
 /*
index e9c6a8014bd647eec50a66afb5bc75b076b35e4d..e3d4d4890104cc27e2eb9de2f22cb6f53f939c90 100644 (file)
@@ -200,6 +200,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 75e75d7b1702fb6434c59e9155dbba1d71623b17..244e0dbe45dbeda359e233cde23b4652f0ce13dc 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls            355
+#define NR_syscalls            356
 
 #define __ARCH_WANT_OLD_READDIR
 #define __ARCH_WANT_OLD_STAT
index 2c1bec9a14b67da42a8ed09b644373d0cf35b5ef..61fb6cb9d2ae3c66a1c0c6dec1ac95adb83dd810 100644 (file)
 #define __NR_getrandom         352
 #define __NR_memfd_create      353
 #define __NR_bpf               354
+#define __NR_execveat          355
 
 #endif /* _UAPI_ASM_M68K_UNISTD_H_ */
index 2ca219e184cd16e6ebad1bd9123061695691c843..a0ec4303f2c8e57a04fb353178d43b0be6a461fe 100644 (file)
@@ -375,4 +375,5 @@ ENTRY(sys_call_table)
        .long sys_getrandom
        .long sys_memfd_create
        .long sys_bpf
+       .long sys_execveat              /* 355 */
 
index 2bd7487440c455802dac6470ec05ac138148bfcb..b2f04aee46ecc2f7a5fb1db26d8e4279f6b6ea2e 100644 (file)
@@ -145,6 +145,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto map_err;
                else if (fault & VM_FAULT_SIGBUS)
                        goto bus_err;
                BUG();
index 332680e5ebf23c7909b796c415c2273efd77ba3c..2de5dc695a87fa96d41a83e127166a7126d10df0 100644 (file)
@@ -141,6 +141,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index fa4cf52aa7a6d386711690005a314ece7d67fc53..d46a5ebb7570e07869ea03b9b995374aa3bff82e 100644 (file)
@@ -224,6 +224,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index b30e41c0c0335cf2ab79e716c9c41c0ebced18e8..48528fb81effa07ef5c992c08efba2cad6a75ff0 100644 (file)
@@ -1026,6 +1026,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
                         pr, (pr && pr->name) ? pr->name : "nil");
 
                if (pr && !(pr->flags & IORESOURCE_UNSET)) {
+                       struct pci_dev *dev = bus->self;
+
                        if (request_resource(pr, res) == 0)
                                continue;
                        /*
@@ -1035,6 +1037,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
                         */
                        if (reparent_resources(pr, res) == 0)
                                continue;
+
+                       if (dev && i < PCI_BRIDGE_RESOURCE_NUM &&
+                           pci_claim_bridge_resource(dev,
+                                                i + PCI_BRIDGE_RESOURCES) == 0)
+                               continue;
+
                }
                pr_warn("PCI: Cannot allocate resource region ");
                pr_cont("%d of PCI bridge %d, will remap\n", i, bus->number);
@@ -1227,7 +1235,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
                                 (unsigned long long)r->end,
                                 (unsigned int)r->flags);
 
-                       pci_claim_resource(dev, i);
+                       if (pci_claim_resource(dev, i) == 0)
+                               continue;
+
+                       pci_claim_bridge_resource(dev, i);
                }
        }
 
index becc42bb18495adf98389bd039bc111c1893cedd..70ab5d664332694e92305331f13ed15a35ab1956 100644 (file)
@@ -158,6 +158,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 9fd6834a2172ac3cd77115d604a2f07ac8370bc2..5d6139390bf830adf503d67d004a5322d8eb7ad4 100644 (file)
@@ -1388,7 +1388,7 @@ out:
 void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
-               module_free(NULL, fp->bpf_func);
+               module_memfree(fp->bpf_func);
 
        bpf_prog_unlock_free(fp);
 }
index 3516cbdf1ee93acb82ebef6428f79df9af104514..0c2cc5d39c8e37ce1cfe5be191902bc435c41090 100644 (file)
@@ -262,6 +262,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index febb9cd83177177e4c0edffa6d4c2d34b4a2b2a0..b5b036f64275b0fe0176132b74f4715f185f7503 100644 (file)
@@ -106,7 +106,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
                                if (!r->flags)
                                        continue;
                                if (!r->start ||
-                                   pci_claim_resource(dev, idx) < 0) {
+                                   pci_claim_bridge_resource(dev, idx) < 0) {
                                        printk(KERN_ERR "PCI:"
                                               " Cannot allocate resource"
                                               " region %d of bridge %s\n",
index 6b4339f8c9c2e1e757f13fddccb9053c2c292b0c..471ff398090cd88e89089b5387d1a1f4dc0dcc0a 100644 (file)
@@ -281,42 +281,37 @@ static int __init pci_check_direct(void)
        return -ENODEV;
 }
 
-static int is_valid_resource(struct pci_dev *dev, int idx)
+static void pcibios_fixup_device_resources(struct pci_dev *dev)
 {
-       unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
-       struct resource *devr = &dev->resource[idx], *busr;
-
-       if (dev->bus) {
-               pci_bus_for_each_resource(dev->bus, busr, i) {
-                       if (!busr || (busr->flags ^ devr->flags) & type_mask)
-                               continue;
-
-                       if (devr->start &&
-                           devr->start >= busr->start &&
-                           devr->end <= busr->end)
-                               return 1;
-               }
-       }
+       int idx;
 
-       return 0;
+       if (!dev->bus)
+               return;
+
+       for (idx = 0; idx < PCI_BRIDGE_RESOURCES; idx++) {
+               struct resource *r = &dev->resource[idx];
+
+               if (!r->flags || r->parent || !r->start)
+                       continue;
+
+               pci_claim_resource(dev, idx);
+       }
 }
 
-static void pcibios_fixup_device_resources(struct pci_dev *dev)
+static void pcibios_fixup_bridge_resources(struct pci_dev *dev)
 {
-       int limit, i;
+       int idx;
 
-       if (dev->bus->number != 0)
+       if (!dev->bus)
                return;
 
-       limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ?
-               PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES;
+       for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+               struct resource *r = &dev->resource[idx];
 
-       for (i = 0; i < limit; i++) {
-               if (!dev->resource[i].flags)
+               if (!r->flags || r->parent || !r->start)
                        continue;
 
-               if (is_valid_resource(dev, i))
-                       pci_claim_resource(dev, i);
+               pci_claim_bridge_resource(dev, idx);
        }
 }
 
@@ -330,7 +325,7 @@ void pcibios_fixup_bus(struct pci_bus *bus)
 
        if (bus->self) {
                pci_read_bridge_bases(bus);
-               pcibios_fixup_device_resources(bus->self);
+               pcibios_fixup_bridge_resources(bus->self);
        }
 
        list_for_each_entry(dev, &bus->devices, bus_list)
index 51d5bb90d3e504e6b3480bf4cb51be0598d58a22..a223691dff4fb1699c52b3e025ebb6446394fbb0 100644 (file)
@@ -72,6 +72,7 @@ void __init setup_cpuinfo(void)
        cpuinfo.has_div = fcpu_has(cpu, "altr,has-div");
        cpuinfo.has_mul = fcpu_has(cpu, "altr,has-mul");
        cpuinfo.has_mulx = fcpu_has(cpu, "altr,has-mulx");
+       cpuinfo.mmu = fcpu_has(cpu, "altr,has-mmu");
 
        if (IS_ENABLED(CONFIG_NIOS2_HW_DIV_SUPPORT) && !cpuinfo.has_div)
                err_cpu("DIV");
index 83bca17d1008f844857ca1dca98b00a4158f6e38..0bdfd13ff98bbbbd5af7fc4251abf1c618d63a94 100644 (file)
@@ -365,30 +365,14 @@ ENTRY(ret_from_interrupt)
        GET_THREAD_INFO r1
        ldw     r4, TI_PREEMPT_COUNT(r1)
        bne     r4, r0, restore_all
-
-need_resched:
        ldw     r4, TI_FLAGS(r1)                /* ? Need resched set */
        BTBZ    r10, r4, TIF_NEED_RESCHED, restore_all
        ldw     r4, PT_ESTATUS(sp)      /* ? Interrupts off */
        andi    r10, r4, ESTATUS_EPIE
        beq     r10, r0, restore_all
-       movia   r4, PREEMPT_ACTIVE
-       stw     r4, TI_PREEMPT_COUNT(r1)
-       rdctl   r10, status             /* enable intrs again */
-       ori     r10, r10 ,STATUS_PIE
-       wrctl   status, r10
-       PUSH    r1
-       call    schedule
-       POP     r1
-       mov     r4, r0
-       stw     r4, TI_PREEMPT_COUNT(r1)
-       rdctl   r10, status             /* disable intrs */
-       andi    r10, r10, %lo(~STATUS_PIE)
-       wrctl   status, r10
-       br      need_resched
-#else
-       br      restore_all
+       call    preempt_schedule_irq
 #endif
+       br      restore_all
 
 /***********************************************************************
  * A few syscall wrappers
index cc924a38f22a0fef473a3c6d871789fdacf8f7f9..e2e3f13f98d55a811ef30db3493dbd71a8e86eb0 100644 (file)
@@ -36,7 +36,7 @@ void *module_alloc(unsigned long size)
 }
 
 /* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_memfree(void *module_region)
 {
        kfree(module_region);
 }
index f9d27883a7148729545489c14bb678122da74e88..2d0ea25be1717de06d8cd138032dc5c7c5f3970d 100644 (file)
@@ -200,7 +200,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
 
        /* Set up to return from userspace; jump to fixed address sigreturn
           trampoline on kuser page.  */
-       regs->ra = (unsigned long) (0x1040);
+       regs->ra = (unsigned long) (0x1044);
 
        /* Set up registers for signal handler */
        regs->sp = (unsigned long) frame;
index 15a0bb5fc06d970a6c3dcd92ce31173a8914670b..34429d5a0ccde65e0bd18a88dbc47a2968d6c793 100644 (file)
@@ -135,6 +135,8 @@ survive:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 0703acf7d3276811919fd3d398ada99b1b9c6d50..230ac20ae7944f71636e5083fdaf3f034eb10af2 100644 (file)
@@ -171,6 +171,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index d2d11b7055ba640178817917d04c46364453c069..8121aa6db2ff21ad37510879dd82a3fe7ba7fa29 100644 (file)
 
 #endif /*!CONFIG_PA20*/
 
-/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.  */
+/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
+   We don't explicitly expose that "*a" may be written as reload
+   fails to find a register in class R1_REGS when "a" needs to be
+   reloaded when generating 64-bit PIC code.  Instead, we clobber
+   memory to indicate to the compiler that the assembly code reads
+   or writes to items other than those listed in the input and output
+   operands.  This may pessimize the code somewhat but __ldcw is
+   usually used within code blocks surrounded by memory barriors.  */
 #define __ldcw(a) ({                                           \
        unsigned __ret;                                         \
-       __asm__ __volatile__(__LDCW " 0(%2),%0"                 \
-               : "=r" (__ret), "+m" (*(a)) : "r" (a));         \
+       __asm__ __volatile__(__LDCW " 0(%1),%0"                 \
+               : "=r" (__ret) : "r" (a) : "memory");           \
        __ret;                                                  \
 })
 
index 50dfafc3f2c103aa3567f2fb88aeb94865847517..5822e8e200e6be1ab110b15baf94d4581624099c 100644 (file)
@@ -298,14 +298,10 @@ static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
 }
 #endif
 
-
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_arch_freeing_init(struct module *mod)
 {
        kfree(mod->arch.section);
        mod->arch.section = NULL;
-
-       vfree(module_region);
 }
 
 /* Additional bytes needed in front of individual sections */
index 3ca9c1131cfe0d80b9b12fb5c0e599a3363942c0..e5120e653240c4fa52d4895c7d1d206d3d12e68c 100644 (file)
@@ -256,6 +256,8 @@ good_area:
                 */
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto bad_area;
                BUG();
index d3feba5a275f6465fa46b850ed57cb688bd834ea..c154cebc1041c4ac24d72c5e51b93bfec2f0d9ee 100644 (file)
@@ -154,4 +154,5 @@ module_exit(sha1_powerpc_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
 
+MODULE_ALIAS_CRYPTO("sha1");
 MODULE_ALIAS_CRYPTO("sha1-powerpc");
index 19c36cba37c4acac5e63e7c4d8a093b4dbe65781..a46f5f45570c8904a5a13de12ecb3edfed5c2449 100644 (file)
@@ -86,6 +86,11 @@ extern int overlaps_crashkernel(unsigned long start, unsigned long size);
 extern void reserve_crashkernel(void);
 extern void machine_kexec_mask_interrupts(void);
 
+static inline bool kdump_in_progress(void)
+{
+       return crashing_cpu >= 0;
+}
+
 #else /* !CONFIG_KEXEC */
 static inline void crash_kexec_secondary(struct pt_regs *regs) { }
 
@@ -106,6 +111,11 @@ static inline int crash_shutdown_unregister(crash_shutdown_t handler)
        return 0;
 }
 
+static inline bool kdump_in_progress(void)
+{
+       return false;
+}
+
 #endif /* CONFIG_KEXEC */
 #endif /* ! __ASSEMBLY__ */
 #endif /* __KERNEL__ */
index ce9577d693be1c7849c18ac0259a35525d46c6fe..91062eef582f9c1ed8d824f9e16bcde8a0f8714c 100644 (file)
@@ -366,3 +366,4 @@ SYSCALL_SPU(seccomp)
 SYSCALL_SPU(getrandom)
 SYSCALL_SPU(memfd_create)
 SYSCALL_SPU(bpf)
+COMPAT_SYS(execveat)
index ebc4f165690a9fc0113864b6857708b5df8c317a..0be6c681cab1341061c02031464d5355ff8a4d7d 100644 (file)
@@ -23,9 +23,9 @@
 #define THREAD_SIZE            (1 << THREAD_SHIFT)
 
 #ifdef CONFIG_PPC64
-#define CURRENT_THREAD_INFO(dest, sp)  clrrdi dest, sp, THREAD_SHIFT
+#define CURRENT_THREAD_INFO(dest, sp)  stringify_in_c(clrrdi dest, sp, THREAD_SHIFT)
 #else
-#define CURRENT_THREAD_INFO(dest, sp)  rlwinm dest, sp, 0, 0, 31-THREAD_SHIFT
+#define CURRENT_THREAD_INFO(dest, sp)  stringify_in_c(rlwinm dest, sp, 0, 0, 31-THREAD_SHIFT)
 #endif
 
 #ifndef __ASSEMBLY__
@@ -71,12 +71,13 @@ struct thread_info {
 #define THREAD_SIZE_ORDER      (THREAD_SHIFT - PAGE_SHIFT)
 
 /* how to get the thread information struct from C */
-register unsigned long __current_r1 asm("r1");
 static inline struct thread_info *current_thread_info(void)
 {
-       /* gcc4, at least, is smart enough to turn this into a single
-        * rlwinm for ppc32 and clrrdi for ppc64 */
-       return (struct thread_info *)(__current_r1 & ~(THREAD_SIZE-1));
+       unsigned long val;
+
+       asm (CURRENT_THREAD_INFO(%0,1) : "=r" (val));
+
+       return (struct thread_info *)val;
 }
 
 #endif /* __ASSEMBLY__ */
index e0da021caa004205fc8b645d95b3047c8cd9b73e..36b79c31eedda5cb090e73cafc6a64c937fcc5f7 100644 (file)
@@ -12,7 +12,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define __NR_syscalls          362
+#define __NR_syscalls          363
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index f55351f2e66e962097bc078c25f77a176ca52e2a..ef5b5b1f31231648135ed092af027933c8dc3f06 100644 (file)
 #define __NR_getrandom         359
 #define __NR_memfd_create      360
 #define __NR_bpf               361
+#define __NR_execveat          362
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
index 879b3aacac3282d8b9de5101c9349d2aea9b8edc..f96d1ec241891b9683761d3e04c2daed29d670d1 100644 (file)
@@ -330,7 +330,7 @@ void default_machine_kexec(struct kimage *image)
         * using debugger IPI.
         */
 
-       if (crashing_cpu == -1)
+       if (!kdump_in_progress())
                kexec_prepare_cpus();
 
        pr_debug("kexec: Starting switchover sequence.\n");
index 37d512d35943400737d36be40448c063f9ee76f0..2a525c938158e7937445837ef6448354b5147758 100644 (file)
@@ -1184,6 +1184,8 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
                         pr, (pr && pr->name) ? pr->name : "nil");
 
                if (pr && !(pr->flags & IORESOURCE_UNSET)) {
+                       struct pci_dev *dev = bus->self;
+
                        if (request_resource(pr, res) == 0)
                                continue;
                        /*
@@ -1193,6 +1195,11 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
                         */
                        if (reparent_resources(pr, res) == 0)
                                continue;
+
+                       if (dev && i < PCI_BRIDGE_RESOURCE_NUM &&
+                           pci_claim_bridge_resource(dev,
+                                               i + PCI_BRIDGE_RESOURCES) == 0)
+                               continue;
                }
                pr_warning("PCI: Cannot allocate resource region "
                           "%d of PCI bridge %d, will remap\n", i, bus->number);
@@ -1401,7 +1408,10 @@ void pcibios_claim_one_bus(struct pci_bus *bus)
                                 (unsigned long long)r->end,
                                 (unsigned int)r->flags);
 
-                       pci_claim_resource(dev, i);
+                       if (pci_claim_resource(dev, i) == 0)
+                               continue;
+
+                       pci_claim_bridge_resource(dev, i);
                }
        }
 
index 8ec017cb44461943c90ebdb6cdf6e007936efb39..8b2d2dc8ef106ef780c9a145335e9de17b3879a7 100644 (file)
@@ -700,6 +700,7 @@ void start_secondary(void *unused)
        smp_store_cpu_info(cpu);
        set_dec(tb_ticks_per_jiffy);
        preempt_disable();
+       cpu_callin_map[cpu] = 1;
 
        if (smp_ops->setup_cpu)
                smp_ops->setup_cpu(cpu);
@@ -738,14 +739,6 @@ void start_secondary(void *unused)
        notify_cpu_starting(cpu);
        set_cpu_online(cpu, true);
 
-       /*
-        * CPU must be marked active and online before we signal back to the
-        * master, because the scheduler needs to see the cpu_online and
-        * cpu_active bits set.
-        */
-       smp_wmb();
-       cpu_callin_map[cpu] = 1;
-
        local_irq_enable();
 
        cpu_startup_entry(CPUHP_ONLINE);
index 5a236f082c78386a47b9b415f98f619e8e615688..1b5305d4bdabe95c4f4430b89c0fb56512bb6fdf 100644 (file)
@@ -76,7 +76,7 @@ int copro_handle_mm_fault(struct mm_struct *mm, unsigned long ea,
                if (*flt & VM_FAULT_OOM) {
                        ret = -ENOMEM;
                        goto out_unlock;
-               } else if (*flt & VM_FAULT_SIGBUS) {
+               } else if (*flt & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) {
                        ret = -EFAULT;
                        goto out_unlock;
                }
index eb79907f34fac2df170be8fcb3a14a9cbf400b1e..6154b0a2b06331f0c29efe56b210baa6f90d43c7 100644 (file)
@@ -437,6 +437,8 @@ good_area:
         */
        fault = handle_mm_fault(mm, vma, address, flags);
        if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
+               if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                rc = mm_fault_error(regs, address, fault);
                if (rc >= MM_FAULT_RETURN)
                        goto bail;
index 1ca125b9c226070eefca744857b203648055b131..d1916b577f2c9a71c3fb3a5ee419925f070412d0 100644 (file)
@@ -699,7 +699,7 @@ out:
 void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
-               module_free(NULL, fp->bpf_func);
+               module_memfree(fp->bpf_func);
 
        bpf_prog_unlock_free(fp);
 }
index 54eca8b3b288f8fcca45ef5f44c5211832b3416f..0509bca5e830b656c8a553c047740b68b172f4b1 100644 (file)
@@ -40,7 +40,6 @@ BEGIN_FTR_SECTION;                                            \
        b       1f;                                             \
 END_FTR_SECTION(0, 1);                                         \
        ld      r12,opal_tracepoint_refcount@toc(r2);           \
-       std     r12,32(r1);                                     \
        cmpdi   r12,0;                                          \
        bne-    LABEL;                                          \
 1:
index b700a329c31d448444d0f48e0fdd0b9176f1a825..d2de7d5d7574ca48fb1f31aa5c6892a510107ade 100644 (file)
@@ -304,7 +304,7 @@ int pnv_save_sprs_for_winkle(void)
         * all cpus at boot. Get these reg values of current cpu and use the
         * same accross all cpus.
         */
-       uint64_t lpcr_val = mfspr(SPRN_LPCR);
+       uint64_t lpcr_val = mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1;
        uint64_t hid0_val = mfspr(SPRN_HID0);
        uint64_t hid1_val = mfspr(SPRN_HID1);
        uint64_t hid4_val = mfspr(SPRN_HID4);
index 469751d9200469c5220be3da3ec573207d9c1100..b5682fd6c9846b2cdb259720e35a2326cf7c45a1 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/trace.h>
 #include <asm/firmware.h>
 #include <asm/plpar_wrappers.h>
+#include <asm/kexec.h>
 #include <asm/fadump.h>
 
 #include "pseries.h"
@@ -267,8 +268,13 @@ static void pSeries_lpar_hptab_clear(void)
                 * out to the user, but at least this will stop us from
                 * continuing on further and creating an even more
                 * difficult to debug situation.
+                *
+                * There is a known problem when kdump'ing, if cpus are offline
+                * the above call will fail. Rather than panicking again, keep
+                * going and hope the kdump kernel is also little endian, which
+                * it usually is.
                 */
-               if (rc)
+               if (rc && !kdump_in_progress())
                        panic("Could not enable big endian exceptions");
        }
 #endif
index 5b150f0c5df94a39587ea6b519e12192d28bce3c..13c6e200b24ec5bc2a7927308eaf579f1a904cd5 100644 (file)
@@ -337,6 +337,7 @@ static inline void disable_surveillance(void)
        args.token = rtas_token("set-indicator");
        if (args.token == RTAS_UNKNOWN_SERVICE)
                return;
+       args.token = cpu_to_be32(args.token);
        args.nargs = cpu_to_be32(3);
        args.nret = cpu_to_be32(1);
        args.rets = &args.args[3];
index 32040ace00ea2431a18428dca5c34c0c4ebde10c..afbe07907c10b6304e52b5eb234d33694fd9693a 100644 (file)
@@ -231,7 +231,7 @@ failed:
 struct dbfs_d2fc_hdr {
        u64     len;            /* Length of d2fc buffer without header */
        u16     version;        /* Version of header */
-       char    tod_ext[16];    /* TOD clock for d2fc */
+       char    tod_ext[STORE_CLOCK_EXT_SIZE]; /* TOD clock for d2fc */
        u64     count;          /* Number of VM guests in d2fc buffer */
        char    reserved[30];
 } __attribute__ ((packed));
index 37b9091ab8c010c88a22bb2851f0133b10c6f032..16aa0c779e0762e210fe6652a0a5efda24771381 100644 (file)
@@ -36,7 +36,7 @@ static inline notrace void __arch_local_irq_ssm(unsigned long flags)
 
 static inline notrace unsigned long arch_local_save_flags(void)
 {
-       return __arch_local_irq_stosm(0x00);
+       return __arch_local_irq_stnsm(0xff);
 }
 
 static inline notrace unsigned long arch_local_irq_save(void)
index 8beee1cceba4ed17831736a11c6f5167155335d6..98eb2a5792234d9d12c303bdb1301f869f706b60 100644 (file)
@@ -67,20 +67,22 @@ static inline void local_tick_enable(unsigned long long comp)
        set_clock_comparator(S390_lowcore.clock_comparator);
 }
 
-#define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
+#define CLOCK_TICK_RATE                1193180 /* Underlying HZ */
+#define STORE_CLOCK_EXT_SIZE   16      /* stcke writes 16 bytes */
 
 typedef unsigned long long cycles_t;
 
-static inline void get_tod_clock_ext(char clk[16])
+static inline void get_tod_clock_ext(char *clk)
 {
-       typedef struct { char _[sizeof(clk)]; } addrtype;
+       typedef struct { char _[STORE_CLOCK_EXT_SIZE]; } addrtype;
 
        asm volatile("stcke %0" : "=Q" (*(addrtype *) clk) : : "cc");
 }
 
 static inline unsigned long long get_tod_clock(void)
 {
-       unsigned char clk[16];
+       unsigned char clk[STORE_CLOCK_EXT_SIZE];
+
        get_tod_clock_ext(clk);
        return *((unsigned long long *)&clk[1]);
 }
index 2b446cf0cc65543d38defaf1985d4246f767449b..67878af257a083c531140f74b951019e2a1537e0 100644 (file)
 #define __NR_bpf               351
 #define __NR_s390_pci_mmio_write       352
 #define __NR_s390_pci_mmio_read                353
-#define NR_syscalls 354
+#define __NR_execveat          354
+#define NR_syscalls 355
 
 /* 
  * There are some system calls that are not present on 64 bit, some
index b89b59158b9592317479422b14cfb8e7779fa722..409d152585bea67a6aca845bb0c3e4db130b1505 100644 (file)
@@ -55,14 +55,10 @@ void *module_alloc(unsigned long size)
 }
 #endif
 
-/* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_arch_freeing_init(struct module *mod)
 {
-       if (mod) {
-               vfree(mod->arch.syminfo);
-               mod->arch.syminfo = NULL;
-       }
-       vfree(module_region);
+       vfree(mod->arch.syminfo);
+       mod->arch.syminfo = NULL;
 }
 
 static void check_rela(Elf_Rela *rela, struct module *me)
index a2987243bc76c89bd07a6d4a298825bea9664ab8..939ec474b1dd705e7814f94c94df4faeb8009aa2 100644 (file)
@@ -362,3 +362,4 @@ SYSCALL(sys_memfd_create,sys_memfd_create,compat_sys_memfd_create) /* 350 */
 SYSCALL(sys_bpf,sys_bpf,compat_sys_bpf)
 SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_write,compat_sys_s390_pci_mmio_write)
 SYSCALL(sys_ni_syscall,sys_s390_pci_mmio_read,compat_sys_s390_pci_mmio_read)
+SYSCALL(sys_execveat,sys_execveat,compat_sys_execveat)
index f6b3cd056ec22c1c28b908c4cefc46bc4a4e2099..cc7328080b609a653b72c1ca2c6989f054e3be74 100644 (file)
@@ -48,6 +48,30 @@ bool arch_uprobe_xol_was_trapped(struct task_struct *tsk)
        return false;
 }
 
+static int check_per_event(unsigned short cause, unsigned long control,
+                          struct pt_regs *regs)
+{
+       if (!(regs->psw.mask & PSW_MASK_PER))
+               return 0;
+       /* user space single step */
+       if (control == 0)
+               return 1;
+       /* over indication for storage alteration */
+       if ((control & 0x20200000) && (cause & 0x2000))
+               return 1;
+       if (cause & 0x8000) {
+               /* all branches */
+               if ((control & 0x80800000) == 0x80000000)
+                       return 1;
+               /* branch into selected range */
+               if (((control & 0x80800000) == 0x80800000) &&
+                   regs->psw.addr >= current->thread.per_user.start &&
+                   regs->psw.addr <= current->thread.per_user.end)
+                       return 1;
+       }
+       return 0;
+}
+
 int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 {
        int fixup = probe_get_fixup_type(auprobe->insn);
@@ -71,9 +95,13 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
                if (regs->psw.addr - utask->xol_vaddr == ilen)
                        regs->psw.addr = utask->vaddr + ilen;
        }
-       /* If per tracing was active generate trap */
-       if (regs->psw.mask & PSW_MASK_PER)
-               do_per_trap(regs);
+       if (check_per_event(current->thread.per_event.cause,
+                           current->thread.per_user.control, regs)) {
+               /* fix per address */
+               current->thread.per_event.address = utask->vaddr;
+               /* trigger per event */
+               set_pt_regs_flag(regs, PIF_PER_TRAP);
+       }
        return 0;
 }
 
@@ -106,6 +134,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
        clear_thread_flag(TIF_UPROBE_SINGLESTEP);
        regs->int_code = auprobe->saved_int_code;
        regs->psw.addr = current->utask->vaddr;
+       current->thread.per_event.address = current->utask->vaddr;
 }
 
 unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline,
@@ -146,17 +175,20 @@ static void adjust_psw_addr(psw_t *psw, unsigned long len)
        __rc;                                           \
 })
 
-#define emu_store_ril(ptr, input)                      \
+#define emu_store_ril(regs, ptr, input)                        \
 ({                                                     \
        unsigned int mask = sizeof(*(ptr)) - 1;         \
+       __typeof__(ptr) __ptr = (ptr);                  \
        int __rc = 0;                                   \
                                                        \
        if (!test_facility(34))                         \
                __rc = EMU_ILLEGAL_OP;                  \
-       else if ((u64 __force)ptr & mask)               \
+       else if ((u64 __force)__ptr & mask)             \
                __rc = EMU_SPECIFICATION;               \
-       else if (put_user(*(input), ptr))               \
+       else if (put_user(*(input), __ptr))             \
                __rc = EMU_ADDRESSING;                  \
+       if (__rc == 0)                                  \
+               sim_stor_event(regs, __ptr, mask + 1);  \
        __rc;                                           \
 })
 
@@ -197,6 +229,25 @@ union split_register {
        s16 s16[4];
 };
 
+/*
+ * If user per registers are setup to trace storage alterations and an
+ * emulated store took place on a fitting address a user trap is generated.
+ */
+static void sim_stor_event(struct pt_regs *regs, void *addr, int len)
+{
+       if (!(regs->psw.mask & PSW_MASK_PER))
+               return;
+       if (!(current->thread.per_user.control & PER_EVENT_STORE))
+               return;
+       if ((void *)current->thread.per_user.start > (addr + len))
+               return;
+       if ((void *)current->thread.per_user.end < addr)
+               return;
+       current->thread.per_event.address = regs->psw.addr;
+       current->thread.per_event.cause = PER_EVENT_STORE >> 16;
+       set_pt_regs_flag(regs, PIF_PER_TRAP);
+}
+
 /*
  * pc relative instructions are emulated, since parameters may not be
  * accessible from the xol area due to range limitations.
@@ -249,13 +300,13 @@ static void handle_insn_ril(struct arch_uprobe *auprobe, struct pt_regs *regs)
                        rc = emu_load_ril((u32 __user *)uptr, &rx->u64);
                        break;
                case 0x07: /* sthrl */
-                       rc = emu_store_ril((u16 __user *)uptr, &rx->u16[3]);
+                       rc = emu_store_ril(regs, (u16 __user *)uptr, &rx->u16[3]);
                        break;
                case 0x0b: /* stgrl */
-                       rc = emu_store_ril((u64 __user *)uptr, &rx->u64);
+                       rc = emu_store_ril(regs, (u64 __user *)uptr, &rx->u64);
                        break;
                case 0x0f: /* strl */
-                       rc = emu_store_ril((u32 __user *)uptr, &rx->u32[1]);
+                       rc = emu_store_ril(regs, (u32 __user *)uptr, &rx->u32[1]);
                        break;
                }
                break;
index 7f0089d9a4aa47ef86e7691502281c140ee637c3..e34122e539a16bad4e5727f881f982e4829cd8f0 100644 (file)
@@ -128,8 +128,6 @@ void vtime_account_irq_enter(struct task_struct *tsk)
        struct thread_info *ti = task_thread_info(tsk);
        u64 timer, system;
 
-       WARN_ON_ONCE(!irqs_disabled());
-
        timer = S390_lowcore.last_update_timer;
        S390_lowcore.last_update_timer = get_vtimer();
        S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
index 811937bb90be69a18f57621d1be7e6fbfc12d423..9065d5aa3932dd7f6637069e493f2ad4a3ad72f3 100644 (file)
@@ -374,6 +374,12 @@ static noinline void do_fault_error(struct pt_regs *regs, int fault)
                                do_no_context(regs);
                        else
                                pagefault_out_of_memory();
+               } else if (fault & VM_FAULT_SIGSEGV) {
+                       /* Kernel mode? Handle exceptions or die */
+                       if (!user_mode(regs))
+                               do_no_context(regs);
+                       else
+                               do_sigsegv(regs, SEGV_MAPERR);
                } else if (fault & VM_FAULT_SIGBUS) {
                        /* Kernel mode? Handle exceptions or die */
                        if (!user_mode(regs))
index be99357d238c68e34dee133c52053e23c88a34d4..3cf8cc03fff60d7a59e7b23f4e92d477061a5f42 100644 (file)
@@ -322,11 +322,12 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,
 static unsigned long __gmap_segment_gaddr(unsigned long *entry)
 {
        struct page *page;
-       unsigned long offset;
+       unsigned long offset, mask;
 
        offset = (unsigned long) entry / sizeof(unsigned long);
        offset = (offset & (PTRS_PER_PMD - 1)) * PMD_SIZE;
-       page = pmd_to_page((pmd_t *) entry);
+       mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1);
+       page = virt_to_page((void *)((unsigned long) entry & mask));
        return page->index + offset;
 }
 
index 7e45d13816c183e46962e75c3dc4817d72d5b223..ba44c9f5534633a2da3133714f6b018ba6a69545 100644 (file)
@@ -22,8 +22,8 @@
  * skb_copy_bits takes 4 parameters:
  *   %r2 = skb pointer
  *   %r3 = offset into skb data
- *   %r4 = length to copy
- *   %r5 = pointer to temp buffer
+ *   %r4 = pointer to temp buffer
+ *   %r5 = length to copy
  */
 #define SKBDATA        %r8
 
@@ -44,8 +44,9 @@ ENTRY(sk_load_word)
 
 sk_load_word_slow:
        lgr     %r9,%r2                 # save %r2
-       lhi     %r4,4                   # 4 bytes
-       la      %r5,160(%r15)           # pointer to temp buffer
+       lgr     %r3,%r1                 # offset
+       la      %r4,160(%r15)           # pointer to temp buffer
+       lghi    %r5,4                   # 4 bytes
        brasl   %r14,skb_copy_bits      # get data from skb
        l       %r5,160(%r15)           # load result from temp buffer
        ltgr    %r2,%r2                 # set cc to (%r2 != 0)
@@ -69,8 +70,9 @@ ENTRY(sk_load_half)
 
 sk_load_half_slow:
        lgr     %r9,%r2                 # save %r2
-       lhi     %r4,2                   # 2 bytes
-       la      %r5,162(%r15)           # pointer to temp buffer
+       lgr     %r3,%r1                 # offset
+       la      %r4,162(%r15)           # pointer to temp buffer
+       lghi    %r5,2                   # 2 bytes
        brasl   %r14,skb_copy_bits      # get data from skb
        xc      160(2,%r15),160(%r15)
        l       %r5,160(%r15)           # load result from temp buffer
@@ -95,8 +97,9 @@ ENTRY(sk_load_byte)
 
 sk_load_byte_slow:
        lgr     %r9,%r2                 # save %r2
-       lhi     %r4,1                   # 1 bytes
-       la      %r5,163(%r15)           # pointer to temp buffer
+       lgr     %r3,%r1                 # offset
+       la      %r4,163(%r15)           # pointer to temp buffer
+       lghi    %r5,1                   # 1 byte
        brasl   %r14,skb_copy_bits      # get data from skb
        xc      160(3,%r15),160(%r15)
        l       %r5,160(%r15)           # load result from temp buffer
@@ -104,11 +107,11 @@ sk_load_byte_slow:
        lgr     %r2,%r9                 # restore %r2
        br      %r8
 
-       /* A = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+       /* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */
 ENTRY(sk_load_byte_msh)
        llgfr   %r1,%r3                 # extend offset
        clr     %r11,%r3                # hlen < offset ?
-       jle     sk_load_byte_slow
+       jle     sk_load_byte_msh_slow
        lhi     %r12,0
        ic      %r12,0(%r1,%r10)        # get byte from skb
        nill    %r12,0x0f
@@ -118,8 +121,9 @@ ENTRY(sk_load_byte_msh)
 
 sk_load_byte_msh_slow:
        lgr     %r9,%r2                 # save %r2
-       lhi     %r4,2                   # 2 bytes
-       la      %r5,162(%r15)           # pointer to temp buffer
+       lgr     %r3,%r1                 # offset
+       la      %r4,163(%r15)           # pointer to temp buffer
+       lghi    %r5,1                   # 1 byte
        brasl   %r14,skb_copy_bits      # get data from skb
        xc      160(3,%r15),160(%r15)
        l       %r12,160(%r15)          # load result from temp buffer
index c52ac77408ca5cac7ad50b6a2a8a3113d8af30ca..bbd1981cc15007fcdb779ca201553ed28012f20d 100644 (file)
@@ -431,8 +431,8 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
                EMIT4_DISP(0x88500000, K);
                break;
        case BPF_ALU | BPF_NEG: /* A = -A */
-               /* lnr %r5,%r5 */
-               EMIT2(0x1155);
+               /* lcr %r5,%r5 */
+               EMIT2(0x1355);
                break;
        case BPF_JMP | BPF_JA: /* ip += K */
                offset = addrs[i + K] + jit->start - jit->prg;
@@ -448,15 +448,12 @@ static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
                mask = 0x800000; /* je */
 kbranch:       /* Emit compare if the branch targets are different */
                if (filter->jt != filter->jf) {
-                       if (K <= 16383)
-                               /* chi %r5,<K> */
-                               EMIT4_IMM(0xa75e0000, K);
-                       else if (test_facility(21))
+                       if (test_facility(21))
                                /* clfi %r5,<K> */
                                EMIT6_IMM(0xc25f0000, K);
                        else
-                               /* c %r5,<d(K)>(%r13) */
-                               EMIT4_DISP(0x5950d000, EMIT_CONST(K));
+                               /* cl %r5,<d(K)>(%r13) */
+                               EMIT4_DISP(0x5550d000, EMIT_CONST(K));
                }
 branch:                if (filter->jt == filter->jf) {
                        if (filter->jt == 0)
@@ -502,8 +499,8 @@ branch:             if (filter->jt == filter->jf) {
 xbranch:       /* Emit compare if the branch targets are different */
                if (filter->jt != filter->jf) {
                        jit->seen |= SEEN_XREG;
-                       /* cr %r5,%r12 */
-                       EMIT2(0x195c);
+                       /* clr %r5,%r12 */
+                       EMIT2(0x155c);
                }
                goto branch;
        case BPF_JMP | BPF_JSET | BPF_X: /* ip += (A & X) ? jt : jf */
index 52238983527d605914853fd5415ea39617944ffe..6860beb2a280d0a4a65a67c89ad2201b33513068 100644 (file)
@@ -114,6 +114,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 541dc610150888e706977c7944c42ab1d61d7437..a58fec9b55e016df85cdfb7c214cc385e300479c 100644 (file)
@@ -353,6 +353,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
        } else {
                if (fault & VM_FAULT_SIGBUS)
                        do_sigbus(regs, error_code, address);
+               else if (fault & VM_FAULT_SIGSEGV)
+                       bad_area(regs, error_code, address);
                else
                        BUG();
        }
index b36365f49478c573d715816d53582e2dfb153227..9ce5afe167ff509288b21605a2f9a35f96ff36dc 100644 (file)
@@ -639,7 +639,10 @@ static void pci_claim_bus_resources(struct pci_bus *bus)
                                       (unsigned long long)r->end,
                                       (unsigned int)r->flags);
 
-                       pci_claim_resource(dev, i);
+                       if (pci_claim_resource(dev, i) == 0)
+                               continue;
+
+                       pci_claim_bridge_resource(dev, i);
                }
        }
 
index 908e8c17c902bef419877cd1bedcc896b9627636..70d817154fe8bfd04aeaa71f45f15667f4962c23 100644 (file)
@@ -249,6 +249,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 18fcd71670959291f8ef4933e37d5bc394e98f51..4798232494294a7ece0bef232216dd4a26408d88 100644 (file)
@@ -446,6 +446,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index f33e7c7a3bf74d48232e0c9708877cb63a6a4aaa..7931eeeb649af45af45aaa49a20fa727a6aecd40 100644 (file)
@@ -776,7 +776,7 @@ cond_branch:                        f_offset = addrs[i + filter[i].jf];
                                if (unlikely(proglen + ilen > oldproglen)) {
                                        pr_err("bpb_jit_compile fatal error\n");
                                        kfree(addrs);
-                                       module_free(NULL, image);
+                                       module_memfree(image);
                                        return;
                                }
                                memcpy(image + proglen, temp, ilen);
@@ -822,7 +822,7 @@ out:
 void bpf_jit_free(struct bpf_prog *fp)
 {
        if (fp->jited)
-               module_free(NULL, fp->bpf_func);
+               module_memfree(fp->bpf_func);
 
        bpf_prog_unlock_free(fp);
 }
index 96447c9160a0697f5a756f0a2acc945c4cb3efb6..2305084c9b93b72df9f5fba6f6302037d0fb43a7 100644 (file)
@@ -74,7 +74,7 @@ error:
 
 
 /* Free memory returned from module_alloc */
-void module_free(struct module *mod, void *module_region)
+void module_memfree(void *module_region)
 {
        vfree(module_region);
 
@@ -83,7 +83,7 @@ void module_free(struct module *mod, void *module_region)
                     0, 0, 0, NULL, NULL, 0);
 
        /*
-        * FIXME: If module_region == mod->module_init, trim exception
+        * FIXME: Add module_arch_freeing_init to trim exception
         * table entries.
         */
 }
index 565e25a98334201ee031d09381ea570a2fcbda03..0f61a73534e6d7c41ccf56ee71244f926908f6d0 100644 (file)
@@ -442,6 +442,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 87bc86821bc9b81380f46ac38557ad537fd0a442..d195a87ca542b75e919055b30a72bf60f1ba132c 100644 (file)
@@ -3,6 +3,7 @@ config UML
        default y
        select HAVE_ARCH_AUDITSYSCALL
        select HAVE_UID16
+       select HAVE_FUTEX_CMPXCHG if FUTEX
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
        select GENERIC_IO
index 5678c3571e7cb4d1572d0b16a91b0650f76095c7..209617302df89e02994b7c1e45df4340826bad05 100644 (file)
@@ -80,6 +80,8 @@ good_area:
                if (unlikely(fault & VM_FAULT_ERROR)) {
                        if (fault & VM_FAULT_OOM) {
                                goto out_of_memory;
+                       } else if (fault & VM_FAULT_SIGSEGV) {
+                               goto out;
                        } else if (fault & VM_FAULT_SIGBUS) {
                                err = -EACCES;
                                goto out;
index ba397bde79482043d46e0e90d0bd6d7e71daa110..0dc9d0144a27957d2bd2cdadf3b141a3195ccab0 100644 (file)
@@ -857,7 +857,7 @@ source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
        bool "Local APIC support on uniprocessors"
-       depends on X86_32 && !SMP && !X86_32_NON_STANDARD && !PCI_MSI
+       depends on X86_32 && !SMP && !X86_32_NON_STANDARD
        ---help---
          A local APIC (Advanced Programmable Interrupt Controller) is an
          integrated interrupt controller in the CPU. If you have a single-CPU
@@ -868,6 +868,10 @@ config X86_UP_APIC
          performance counters), and the NMI watchdog which detects hard
          lockups.
 
+config X86_UP_APIC_MSI
+       def_bool y
+       select X86_UP_APIC if X86_32 && !SMP && !X86_32_NON_STANDARD && PCI_MSI
+
 config X86_UP_IOAPIC
        bool "IO-APIC support on uniprocessors"
        depends on X86_UP_APIC
index 5b016e2498f3d3250b4edf12584a524bcb79e968..3db07f30636fe40c4cfea973abb08af8adc3c13c 100644 (file)
@@ -51,6 +51,7 @@ targets += cpustr.h
 $(obj)/cpustr.h: $(obj)/mkcpustr FORCE
        $(call if_changed,cpustr)
 endif
+clean-files += cpustr.h
 
 # ---------------------------------------------------------------------------
 
index d999398928bc81ba0957fa7af17b63016f73e54e..ad754b4411f7e42aeecd8ae41a2f67866f23d24f 100644 (file)
@@ -90,7 +90,7 @@ suffix-$(CONFIG_KERNEL_LZO)   := lzo
 suffix-$(CONFIG_KERNEL_LZ4)    := lz4
 
 RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \
-            perl $(srctree)/arch/x86/tools/calc_run_size.pl)
+            $(CONFIG_SHELL) $(srctree)/arch/x86/tools/calc_run_size.sh)
 quiet_cmd_mkpiggy = MKPIGGY $@
       cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
 
index dcc1c536cc212daffda92b903ea9111e36b2c64a..a950864a64dab3d558197c77bef3c56a07961494 100644 (file)
@@ -373,6 +373,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
                                  unsigned long output_len,
                                  unsigned long run_size)
 {
+       unsigned char *output_orig = output;
+
        real_mode = rmode;
 
        sanitize_boot_params(real_mode);
@@ -421,7 +423,12 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap,
        debug_putstr("\nDecompressing Linux... ");
        decompress(input_data, input_len, NULL, NULL, output, NULL, error);
        parse_elf(output);
-       handle_relocations(output, output_len);
+       /*
+        * 32-bit always performs relocations. 64-bit relocations are only
+        * needed if kASLR has chosen a different load address.
+        */
+       if (!IS_ENABLED(CONFIG_X86_64) || output != output_orig)
+               handle_relocations(output, output_len);
        debug_putstr("done.\nBooting the kernel.\n");
        return output;
 }
index fd0f848938ccd81a165c9dff570e108c84271c4d..5a4a089e8b1fd7166e396b52917424e1d9a421b5 100644 (file)
@@ -26,7 +26,6 @@ obj-$(CONFIG_CRYPTO_GHASH_CLMUL_NI_INTEL) += ghash-clmulni-intel.o
 
 obj-$(CONFIG_CRYPTO_CRC32C_INTEL) += crc32c-intel.o
 obj-$(CONFIG_CRYPTO_SHA1_SSSE3) += sha1-ssse3.o
-obj-$(CONFIG_CRYPTO_SHA1_MB) += sha-mb/
 obj-$(CONFIG_CRYPTO_CRC32_PCLMUL) += crc32-pclmul.o
 obj-$(CONFIG_CRYPTO_SHA256_SSSE3) += sha256-ssse3.o
 obj-$(CONFIG_CRYPTO_SHA512_SSSE3) += sha512-ssse3.o
@@ -46,6 +45,7 @@ endif
 ifeq ($(avx2_supported),yes)
        obj-$(CONFIG_CRYPTO_CAMELLIA_AESNI_AVX2_X86_64) += camellia-aesni-avx2.o
        obj-$(CONFIG_CRYPTO_SERPENT_AVX2_X86_64) += serpent-avx2.o
+       obj-$(CONFIG_CRYPTO_SHA1_MB) += sha-mb/
 endif
 
 aes-i586-y := aes-i586-asm_32.o aes_glue.o
index 2df2a0298f5ad7075bc9b214438516270dc60bb5..a916c4a611652fb97e2e6d295e1a4b333ea532bd 100644 (file)
@@ -208,7 +208,7 @@ ddq_add_8:
 
        .if (klen == KEY_128)
                .if (load_keys)
-                       vmovdqa 3*16(p_keys), xkeyA
+                       vmovdqa 3*16(p_keys), xkey4
                .endif
        .else
                vmovdqa 3*16(p_keys), xkeyA
@@ -224,7 +224,7 @@ ddq_add_8:
        add     $(16*by), p_in
 
        .if (klen == KEY_128)
-               vmovdqa 4*16(p_keys), xkey4
+               vmovdqa 4*16(p_keys), xkeyB
        .else
                .if (load_keys)
                        vmovdqa 4*16(p_keys), xkey4
@@ -234,7 +234,12 @@ ddq_add_8:
        .set i, 0
        .rept by
                club XDATA, i
-               vaesenc xkeyA, var_xdata, var_xdata             /* key 3 */
+               /* key 3 */
+               .if (klen == KEY_128)
+                       vaesenc xkey4, var_xdata, var_xdata
+               .else
+                       vaesenc xkeyA, var_xdata, var_xdata
+               .endif
                .set i, (i +1)
        .endr
 
@@ -243,13 +248,18 @@ ddq_add_8:
        .set i, 0
        .rept by
                club XDATA, i
-               vaesenc xkey4, var_xdata, var_xdata             /* key 4 */
+               /* key 4 */
+               .if (klen == KEY_128)
+                       vaesenc xkeyB, var_xdata, var_xdata
+               .else
+                       vaesenc xkey4, var_xdata, var_xdata
+               .endif
                .set i, (i +1)
        .endr
 
        .if (klen == KEY_128)
                .if (load_keys)
-                       vmovdqa 6*16(p_keys), xkeyB
+                       vmovdqa 6*16(p_keys), xkey8
                .endif
        .else
                vmovdqa 6*16(p_keys), xkeyB
@@ -267,12 +277,17 @@ ddq_add_8:
        .set i, 0
        .rept by
                club XDATA, i
-               vaesenc xkeyB, var_xdata, var_xdata             /* key 6 */
+               /* key 6 */
+               .if (klen == KEY_128)
+                       vaesenc xkey8, var_xdata, var_xdata
+               .else
+                       vaesenc xkeyB, var_xdata, var_xdata
+               .endif
                .set i, (i +1)
        .endr
 
        .if (klen == KEY_128)
-               vmovdqa 8*16(p_keys), xkey8
+               vmovdqa 8*16(p_keys), xkeyB
        .else
                .if (load_keys)
                        vmovdqa 8*16(p_keys), xkey8
@@ -288,7 +303,7 @@ ddq_add_8:
 
        .if (klen == KEY_128)
                .if (load_keys)
-                       vmovdqa 9*16(p_keys), xkeyA
+                       vmovdqa 9*16(p_keys), xkey12
                .endif
        .else
                vmovdqa 9*16(p_keys), xkeyA
@@ -297,7 +312,12 @@ ddq_add_8:
        .set i, 0
        .rept by
                club XDATA, i
-               vaesenc xkey8, var_xdata, var_xdata             /* key 8 */
+               /* key 8 */
+               .if (klen == KEY_128)
+                       vaesenc xkeyB, var_xdata, var_xdata
+               .else
+                       vaesenc xkey8, var_xdata, var_xdata
+               .endif
                .set i, (i +1)
        .endr
 
@@ -306,7 +326,12 @@ ddq_add_8:
        .set i, 0
        .rept by
                club XDATA, i
-               vaesenc xkeyA, var_xdata, var_xdata             /* key 9 */
+               /* key 9 */
+               .if (klen == KEY_128)
+                       vaesenc xkey12, var_xdata, var_xdata
+               .else
+                       vaesenc xkeyA, var_xdata, var_xdata
+               .endif
                .set i, (i +1)
        .endr
 
@@ -412,7 +437,6 @@ ddq_add_8:
 /* main body of aes ctr load */
 
 .macro do_aes_ctrmain key_len
-
        cmp     $16, num_bytes
        jb      .Ldo_return2\key_len
 
index a225a5ca1037ede0a9fa8ebb109a43c22523ffaa..fd9f6b035b163001620d40811b728cc5e213c712 100644 (file)
@@ -931,4 +931,4 @@ module_exit(sha1_mb_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm, multi buffer accelerated");
 
-MODULE_ALIAS("sha1");
+MODULE_ALIAS_CRYPTO("sha1");
index 0ab4f9fd268764114e3f252b07895c4bcaf63f90..3a45668f6dc38312bc9f5761214f076a144d00d4 100644 (file)
@@ -50,6 +50,7 @@ void acpi_pic_sci_set_trigger(unsigned int, u16);
 
 extern int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
                                  int trigger, int polarity);
+extern void (*__acpi_unregister_gsi)(u32 gsi);
 
 static inline void disable_acpi(void)
 {
index 50d033a8947db64f8ad0270fd55f23faed683c46..a94b82e8f156f3888e0ab90ac879e39dd05ccec1 100644 (file)
@@ -251,7 +251,8 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
                gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i];
 }
 
-#define _LDT_empty(info)                               \
+/* This intentionally ignores lm, since 32-bit apps don't have that field. */
+#define LDT_empty(info)                                        \
        ((info)->base_addr              == 0    &&      \
         (info)->limit                  == 0    &&      \
         (info)->contents               == 0    &&      \
@@ -261,11 +262,18 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
         (info)->seg_not_present        == 1    &&      \
         (info)->useable                == 0)
 
-#ifdef CONFIG_X86_64
-#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0))
-#else
-#define LDT_empty(info) (_LDT_empty(info))
-#endif
+/* Lots of programs expect an all-zero user_desc to mean "no segment at all". */
+static inline bool LDT_zero(const struct user_desc *info)
+{
+       return (info->base_addr         == 0 &&
+               info->limit             == 0 &&
+               info->contents          == 0 &&
+               info->read_exec_only    == 0 &&
+               info->seg_32bit         == 0 &&
+               info->limit_in_pages    == 0 &&
+               info->seg_not_present   == 0 &&
+               info->useable           == 0);
+}
 
 static inline void clear_LDT(void)
 {
index 40269a2bf6f90f6761a1a27f91d013bd5ee09017..4b75d591eb5ed1e4757ef8b658d08a2ad02a84cd 100644 (file)
@@ -130,7 +130,25 @@ static inline void arch_bprm_mm_init(struct mm_struct *mm,
 static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
                              unsigned long start, unsigned long end)
 {
-       mpx_notify_unmap(mm, vma, start, end);
+       /*
+        * mpx_notify_unmap() goes and reads a rarely-hot
+        * cacheline in the mm_struct.  That can be expensive
+        * enough to be seen in profiles.
+        *
+        * The mpx_notify_unmap() call and its contents have been
+        * observed to affect munmap() performance on hardware
+        * where MPX is not present.
+        *
+        * The unlikely() optimizes for the fast case: no MPX
+        * in the CPU, or no MPX use in the process.  Even if
+        * we get this wrong (in the unlikely event that MPX
+        * is widely enabled on some system) the overhead of
+        * MPX itself (reading bounds tables) is expected to
+        * overwhelm the overhead of getting this unlikely()
+        * consistently wrong.
+        */
+       if (unlikely(cpu_feature_enabled(X86_FEATURE_MPX)))
+               mpx_notify_unmap(mm, vma, start, end);
 }
 
 #endif /* _ASM_X86_MMU_CONTEXT_H */
index e7e9682a33e90f350e0ce5f99c61480755614221..f556c4843aa18af74359dfeb2a41d39d9a2c3bb9 100644 (file)
@@ -80,9 +80,11 @@ static inline unsigned int __getcpu(void)
 
        /*
         * Load per CPU data from GDT.  LSL is faster than RDTSCP and
-        * works on all CPUs.
+        * works on all CPUs.  This is volatile so that it orders
+        * correctly wrt barrier() and to keep gcc from cleverly
+        * hoisting it out of the calling function.
         */
-       asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
+       asm volatile ("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
 
        return p;
 }
index 4433a4be8171b095ff56bb6699f71d67857cc6fb..b9e30daa0881b3213bb9b6be8bf2bb1803cfba7b 100644 (file)
@@ -611,20 +611,20 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
 
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
 {
-       int irq;
-
-       if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) {
-               *irqp = gsi;
-       } else {
-               mutex_lock(&acpi_ioapic_lock);
-               irq = mp_map_gsi_to_irq(gsi,
-                                       IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
-               mutex_unlock(&acpi_ioapic_lock);
-               if (irq < 0)
-                       return -1;
-               *irqp = irq;
+       int rc, irq, trigger, polarity;
+
+       rc = acpi_get_override_irq(gsi, &trigger, &polarity);
+       if (rc == 0) {
+               trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
+               polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
+               irq = acpi_register_gsi(NULL, gsi, trigger, polarity);
+               if (irq >= 0) {
+                       *irqp = irq;
+                       return 0;
+               }
        }
-       return 0;
+
+       return -1;
 }
 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
 
@@ -750,13 +750,13 @@ static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
 }
 
 /* wrapper to silence section mismatch warning */
-int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu)
+int __ref acpi_map_cpu(acpi_handle handle, int physid, int *pcpu)
 {
        return _acpi_map_lsapic(handle, physid, pcpu);
 }
-EXPORT_SYMBOL(acpi_map_lsapic);
+EXPORT_SYMBOL(acpi_map_cpu);
 
-int acpi_unmap_lsapic(int cpu)
+int acpi_unmap_cpu(int cpu)
 {
 #ifdef CONFIG_ACPI_NUMA
        set_apicid_to_node(per_cpu(x86_cpu_to_apicid, cpu), NUMA_NO_NODE);
@@ -768,8 +768,7 @@ int acpi_unmap_lsapic(int cpu)
 
        return (0);
 }
-
-EXPORT_SYMBOL(acpi_unmap_lsapic);
+EXPORT_SYMBOL(acpi_unmap_cpu);
 #endif                         /* CONFIG_ACPI_HOTPLUG_CPU */
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
index e27b49d7c922a3caaa6c45446e8bc383a86d27bc..80091ae54c2b0995ea56629a3f7e6969a484fb9b 100644 (file)
@@ -66,3 +66,4 @@ targets += capflags.c
 $(obj)/capflags.c: $(cpufeature) $(src)/mkcapflags.sh FORCE
        $(call if_changed,mkcapflags)
 endif
+clean-files += capflags.c
index e2b22df964cd88fc49b4cce67023b1e85122ed66..36d99a337b49f56398ca29d900638ddcedee277b 100644 (file)
@@ -28,7 +28,7 @@ function dump_array()
                # If the /* comment */ starts with a quote string, grab that.
                VALUE="$(echo "$i" | sed -n 's@.*/\* *\("[^"]*"\).*\*/@\1@p')"
                [ -z "$VALUE" ] && VALUE="\"$NAME\""
-               [ "$VALUE" == '""' ] && continue
+               [ "$VALUE" = '""' ] && continue
 
                # Name is uppercase, VALUE is all lowercase
                VALUE="$(echo "$VALUE" | tr A-Z a-z)"
index a450373e8e91698dd235725e8d8f9f35b3cec7cc..939155ffdecec60628a06b2937604dd2f2f98813 100644 (file)
@@ -107,6 +107,7 @@ static struct clocksource hyperv_cs = {
        .rating         = 400, /* use this when running on Hyperv*/
        .read           = read_hv_clock,
        .mask           = CLOCKSOURCE_MASK(64),
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
 static void __init ms_hyperv_init_platform(void)
index 944bf019b74f425e06cc465358d25b85741a5b47..498b6d967138b1fff29659e81813c77e70ff1f58 100644 (file)
@@ -2431,6 +2431,7 @@ __init int intel_pmu_init(void)
                break;
 
        case 55: /* 22nm Atom "Silvermont"                */
+       case 76: /* 14nm Atom "Airmont"                   */
        case 77: /* 22nm Atom "Silvermont Avoton/Rangely" */
                memcpy(hw_cache_event_ids, slm_hw_cache_event_ids,
                        sizeof(hw_cache_event_ids));
index 3c895d480cd75b056ab24e686e765b70db1729f5..07398339836426eae32b55fb08fa108593cd7389 100644 (file)
@@ -568,8 +568,8 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
 };
 
 struct event_constraint intel_slm_pebs_event_constraints[] = {
-       /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
-       INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+       /* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
+       INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x1),
        /* Allow all events as PEBS with no flags */
        INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
        EVENT_CONSTRAINT_END
index 673f930c700f3ae745d8a408111f072dcce00dd1..c4bb8b8e5017403b25847a97ccce42c96bba3837 100644 (file)
@@ -103,6 +103,13 @@ static struct kobj_attribute format_attr_##_var =          \
 
 #define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */
 
+#define RAPL_EVENT_ATTR_STR(_name, v, str)                             \
+static struct perf_pmu_events_attr event_attr_##v = {                  \
+       .attr           = __ATTR(_name, 0444, rapl_sysfs_show, NULL),   \
+       .id             = 0,                                            \
+       .event_str      = str,                                          \
+};
+
 struct rapl_pmu {
        spinlock_t       lock;
        int              hw_unit;  /* 1/2^hw_unit Joule */
@@ -135,7 +142,7 @@ static inline u64 rapl_scale(u64 v)
         * or use ldexp(count, -32).
         * Watts = Joules/Time delta
         */
-       return v << (32 - __this_cpu_read(rapl_pmu->hw_unit));
+       return v << (32 - __this_cpu_read(rapl_pmu)->hw_unit);
 }
 
 static u64 rapl_event_update(struct perf_event *event)
@@ -379,23 +386,36 @@ static struct attribute_group rapl_pmu_attr_group = {
        .attrs = rapl_pmu_attrs,
 };
 
-EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
-EVENT_ATTR_STR(energy-pkg  ,   rapl_pkg, "event=0x02");
-EVENT_ATTR_STR(energy-ram  ,   rapl_ram, "event=0x03");
-EVENT_ATTR_STR(energy-gpu  ,   rapl_gpu, "event=0x04");
+static ssize_t rapl_sysfs_show(struct device *dev,
+                              struct device_attribute *attr,
+                              char *page)
+{
+       struct perf_pmu_events_attr *pmu_attr = \
+               container_of(attr, struct perf_pmu_events_attr, attr);
+
+       if (pmu_attr->event_str)
+               return sprintf(page, "%s", pmu_attr->event_str);
+
+       return 0;
+}
+
+RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
+RAPL_EVENT_ATTR_STR(energy-pkg  ,   rapl_pkg, "event=0x02");
+RAPL_EVENT_ATTR_STR(energy-ram  ,   rapl_ram, "event=0x03");
+RAPL_EVENT_ATTR_STR(energy-gpu  ,   rapl_gpu, "event=0x04");
 
-EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules");
-EVENT_ATTR_STR(energy-pkg.unit  ,   rapl_pkg_unit, "Joules");
-EVENT_ATTR_STR(energy-ram.unit  ,   rapl_ram_unit, "Joules");
-EVENT_ATTR_STR(energy-gpu.unit  ,   rapl_gpu_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-pkg.unit  ,   rapl_pkg_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-ram.unit  ,   rapl_ram_unit, "Joules");
+RAPL_EVENT_ATTR_STR(energy-gpu.unit  ,   rapl_gpu_unit, "Joules");
 
 /*
  * we compute in 0.23 nJ increments regardless of MSR
  */
-EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10");
-EVENT_ATTR_STR(energy-pkg.scale,     rapl_pkg_scale, "2.3283064365386962890625e-10");
-EVENT_ATTR_STR(energy-ram.scale,     rapl_ram_scale, "2.3283064365386962890625e-10");
-EVENT_ATTR_STR(energy-gpu.scale,     rapl_gpu_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-pkg.scale,     rapl_pkg_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-ram.scale,     rapl_ram_scale, "2.3283064365386962890625e-10");
+RAPL_EVENT_ATTR_STR(energy-gpu.scale,     rapl_gpu_scale, "2.3283064365386962890625e-10");
 
 static struct attribute *rapl_events_srv_attr[] = {
        EVENT_PTR(rapl_cores),
index 10b8d3eaaf15d760468a6ad88105ab7e06cd540b..c635b8b49e931e7926efc3dc96475a8c577958e0 100644 (file)
@@ -840,7 +840,6 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
        box->phys_id = phys_id;
        box->pci_dev = pdev;
        box->pmu = pmu;
-       uncore_box_init(box);
        pci_set_drvdata(pdev, box);
 
        raw_spin_lock(&uncore_box_lock);
@@ -1004,10 +1003,8 @@ static int uncore_cpu_starting(int cpu)
                        pmu = &type->pmus[j];
                        box = *per_cpu_ptr(pmu->box, cpu);
                        /* called by uncore_cpu_init? */
-                       if (box && box->phys_id >= 0) {
-                               uncore_box_init(box);
+                       if (box && box->phys_id >= 0)
                                continue;
-                       }
 
                        for_each_online_cpu(k) {
                                exist = *per_cpu_ptr(pmu->box, k);
@@ -1023,10 +1020,8 @@ static int uncore_cpu_starting(int cpu)
                                }
                        }
 
-                       if (box) {
+                       if (box)
                                box->phys_id = phys_id;
-                               uncore_box_init(box);
-                       }
                }
        }
        return 0;
index 18eb78bbdd1003a5f7d1d8b302b608405214741f..6c8c1e7e69d85d3ad217eada0f0e55573c3daaf0 100644 (file)
@@ -17,7 +17,7 @@
 #define UNCORE_PCI_DEV_TYPE(data)      ((data >> 8) & 0xff)
 #define UNCORE_PCI_DEV_IDX(data)       (data & 0xff)
 #define UNCORE_EXTRA_PCI_DEV           0xff
-#define UNCORE_EXTRA_PCI_DEV_MAX       2
+#define UNCORE_EXTRA_PCI_DEV_MAX       3
 
 /* support up to 8 sockets */
 #define UNCORE_SOCKET_MAX              8
@@ -257,6 +257,14 @@ static inline int uncore_num_counters(struct intel_uncore_box *box)
        return box->pmu->type->num_counters;
 }
 
+static inline void uncore_box_init(struct intel_uncore_box *box)
+{
+       if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) {
+               if (box->pmu->type->ops->init_box)
+                       box->pmu->type->ops->init_box(box);
+       }
+}
+
 static inline void uncore_disable_box(struct intel_uncore_box *box)
 {
        if (box->pmu->type->ops->disable_box)
@@ -265,6 +273,8 @@ static inline void uncore_disable_box(struct intel_uncore_box *box)
 
 static inline void uncore_enable_box(struct intel_uncore_box *box)
 {
+       uncore_box_init(box);
+
        if (box->pmu->type->ops->enable_box)
                box->pmu->type->ops->enable_box(box);
 }
@@ -287,14 +297,6 @@ static inline u64 uncore_read_counter(struct intel_uncore_box *box,
        return box->pmu->type->ops->read_counter(box, event);
 }
 
-static inline void uncore_box_init(struct intel_uncore_box *box)
-{
-       if (!test_and_set_bit(UNCORE_BOX_FLAG_INITIATED, &box->flags)) {
-               if (box->pmu->type->ops->init_box)
-                       box->pmu->type->ops->init_box(box);
-       }
-}
-
 static inline bool uncore_box_is_fake(struct intel_uncore_box *box)
 {
        return (box->phys_id < 0);
index 745b158e9a65768134caaba91d2f55f43200a481..21af6149edf2e79dd462a7e8f4994c8fd201fa0f 100644 (file)
@@ -891,6 +891,7 @@ void snbep_uncore_cpu_init(void)
 enum {
        SNBEP_PCI_QPI_PORT0_FILTER,
        SNBEP_PCI_QPI_PORT1_FILTER,
+       HSWEP_PCI_PCU_3,
 };
 
 static int snbep_qpi_hw_config(struct intel_uncore_box *box, struct perf_event *event)
@@ -2026,6 +2027,17 @@ void hswep_uncore_cpu_init(void)
 {
        if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
                hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
+
+       /* Detect 6-8 core systems with only two SBOXes */
+       if (uncore_extra_pci_dev[0][HSWEP_PCI_PCU_3]) {
+               u32 capid4;
+
+               pci_read_config_dword(uncore_extra_pci_dev[0][HSWEP_PCI_PCU_3],
+                                     0x94, &capid4);
+               if (((capid4 >> 6) & 0x3) == 0)
+                       hswep_uncore_sbox.num_boxes = 2;
+       }
+
        uncore_msr_uncores = hswep_msr_uncores;
 }
 
@@ -2287,6 +2299,11 @@ static DEFINE_PCI_DEVICE_TABLE(hswep_uncore_pci_ids) = {
                .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
                                                   SNBEP_PCI_QPI_PORT1_FILTER),
        },
+       { /* PCU.3 (for Capability registers) */
+               PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2fc0),
+               .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV,
+                                                  HSWEP_PCI_PCU_3),
+       },
        { /* end: all zeroes */ }
 };
 
index 2142376dc8c6ce0a2ea8c5da5e42016545005d8f..8b7b0a51e742cd26defe12b535f37a865ee3c172 100644 (file)
@@ -674,7 +674,7 @@ static inline void *alloc_tramp(unsigned long size)
 }
 static inline void tramp_free(void *tramp)
 {
-       module_free(NULL, tramp);
+       module_memfree(tramp);
 }
 #else
 /* Trampolines can only be created if modules are supported */
index 6307a0f0cf17abc93aad4490c8bcdaccfdb29541..705ef8d48e2dc464936672fb54eea908f8f03b4e 100644 (file)
@@ -127,7 +127,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
        seq_puts(p, "  Machine check polls\n");
 #endif
 #if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
-       seq_printf(p, "%*s: ", prec, "THR");
+       seq_printf(p, "%*s: ", prec, "HYP");
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
        seq_puts(p, "  Hypervisor callback interrupts\n");
index f7e3cd50ece02a7b0408683d113bbafca8d49479..98f654d466e585167153e58811902675bfeb5baa 100644 (file)
@@ -1020,6 +1020,15 @@ int setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
        regs->flags &= ~X86_EFLAGS_IF;
        trace_hardirqs_off();
        regs->ip = (unsigned long)(jp->entry);
+
+       /*
+        * jprobes use jprobe_return() which skips the normal return
+        * path of the function, and this messes up the accounting of the
+        * function graph tracer to get messed up.
+        *
+        * Pause function graph tracing while performing the jprobe function.
+        */
+       pause_graph_tracing();
        return 1;
 }
 NOKPROBE_SYMBOL(setjmp_pre_handler);
@@ -1048,24 +1057,25 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
        struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
        u8 *addr = (u8 *) (regs->ip - 1);
        struct jprobe *jp = container_of(p, struct jprobe, kp);
+       void *saved_sp = kcb->jprobe_saved_sp;
 
        if ((addr > (u8 *) jprobe_return) &&
            (addr < (u8 *) jprobe_return_end)) {
-               if (stack_addr(regs) != kcb->jprobe_saved_sp) {
+               if (stack_addr(regs) != saved_sp) {
                        struct pt_regs *saved_regs = &kcb->jprobe_saved_regs;
                        printk(KERN_ERR
                               "current sp %p does not match saved sp %p\n",
-                              stack_addr(regs), kcb->jprobe_saved_sp);
+                              stack_addr(regs), saved_sp);
                        printk(KERN_ERR "Saved registers for jprobe %p\n", jp);
                        show_regs(saved_regs);
                        printk(KERN_ERR "Current registers\n");
                        show_regs(regs);
                        BUG();
                }
+               /* It's OK to start function graph tracing again */
+               unpause_graph_tracing();
                *regs = kcb->jprobe_saved_regs;
-               memcpy((kprobe_opcode_t *)(kcb->jprobe_saved_sp),
-                      kcb->jprobes_stack,
-                      MIN_STACK_SIZE(kcb->jprobe_saved_sp));
+               memcpy(saved_sp, kcb->jprobes_stack, MIN_STACK_SIZE(saved_sp));
                preempt_enable_no_resched();
                return 1;
        }
index e309cc5c276eaf7b2a9fa01020f14007b166875f..781861cc5ee8d7b9bbd27e9b13c380da59bb06c0 100644 (file)
@@ -78,6 +78,14 @@ u64 perf_reg_abi(struct task_struct *task)
 {
        return PERF_SAMPLE_REGS_ABI_32;
 }
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs,
+                       struct pt_regs *regs_user_copy)
+{
+       regs_user->regs = task_pt_regs(current);
+       regs_user->abi = perf_reg_abi(current);
+}
 #else /* CONFIG_X86_64 */
 #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
                       (1ULL << PERF_REG_X86_ES) | \
@@ -102,4 +110,86 @@ u64 perf_reg_abi(struct task_struct *task)
        else
                return PERF_SAMPLE_REGS_ABI_64;
 }
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs,
+                       struct pt_regs *regs_user_copy)
+{
+       struct pt_regs *user_regs = task_pt_regs(current);
+
+       /*
+        * If we're in an NMI that interrupted task_pt_regs setup, then
+        * we can't sample user regs at all.  This check isn't really
+        * sufficient, though, as we could be in an NMI inside an interrupt
+        * that happened during task_pt_regs setup.
+        */
+       if (regs->sp > (unsigned long)&user_regs->r11 &&
+           regs->sp <= (unsigned long)(user_regs + 1)) {
+               regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
+               regs_user->regs = NULL;
+               return;
+       }
+
+       /*
+        * RIP, flags, and the argument registers are usually saved.
+        * orig_ax is probably okay, too.
+        */
+       regs_user_copy->ip = user_regs->ip;
+       regs_user_copy->cx = user_regs->cx;
+       regs_user_copy->dx = user_regs->dx;
+       regs_user_copy->si = user_regs->si;
+       regs_user_copy->di = user_regs->di;
+       regs_user_copy->r8 = user_regs->r8;
+       regs_user_copy->r9 = user_regs->r9;
+       regs_user_copy->r10 = user_regs->r10;
+       regs_user_copy->r11 = user_regs->r11;
+       regs_user_copy->orig_ax = user_regs->orig_ax;
+       regs_user_copy->flags = user_regs->flags;
+
+       /*
+        * Don't even try to report the "rest" regs.
+        */
+       regs_user_copy->bx = -1;
+       regs_user_copy->bp = -1;
+       regs_user_copy->r12 = -1;
+       regs_user_copy->r13 = -1;
+       regs_user_copy->r14 = -1;
+       regs_user_copy->r15 = -1;
+
+       /*
+        * For this to be at all useful, we need a reasonable guess for
+        * sp and the ABI.  Be careful: we're in NMI context, and we're
+        * considering current to be the current task, so we should
+        * be careful not to look at any other percpu variables that might
+        * change during context switches.
+        */
+       if (IS_ENABLED(CONFIG_IA32_EMULATION) &&
+           task_thread_info(current)->status & TS_COMPAT) {
+               /* Easy case: we're in a compat syscall. */
+               regs_user->abi = PERF_SAMPLE_REGS_ABI_32;
+               regs_user_copy->sp = user_regs->sp;
+               regs_user_copy->cs = user_regs->cs;
+               regs_user_copy->ss = user_regs->ss;
+       } else if (user_regs->orig_ax != -1) {
+               /*
+                * We're probably in a 64-bit syscall.
+                * Warning: this code is severely racy.  At least it's better
+                * than just blindly copying user_regs.
+                */
+               regs_user->abi = PERF_SAMPLE_REGS_ABI_64;
+               regs_user_copy->sp = this_cpu_read(old_rsp);
+               regs_user_copy->cs = __USER_CS;
+               regs_user_copy->ss = __USER_DS;
+               regs_user_copy->cx = -1;  /* usually contains garbage */
+       } else {
+               /* We're probably in an interrupt or exception. */
+               regs_user->abi = user_64bit_mode(user_regs) ?
+                       PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
+               regs_user_copy->sp = user_regs->sp;
+               regs_user_copy->cs = user_regs->cs;
+               regs_user_copy->ss = user_regs->ss;
+       }
+
+       regs_user->regs = regs_user_copy;
+}
 #endif /* CONFIG_X86_32 */
index 4e942f31b1a7c9401a65fb37af093caab5ad0c2e..7fc5e843f247b358288b23e459eebfefcf6631f0 100644 (file)
@@ -29,7 +29,28 @@ static int get_free_idx(void)
 
 static bool tls_desc_okay(const struct user_desc *info)
 {
-       if (LDT_empty(info))
+       /*
+        * For historical reasons (i.e. no one ever documented how any
+        * of the segmentation APIs work), user programs can and do
+        * assume that a struct user_desc that's all zeros except for
+        * entry_number means "no segment at all".  This never actually
+        * worked.  In fact, up to Linux 3.19, a struct user_desc like
+        * this would create a 16-bit read-write segment with base and
+        * limit both equal to zero.
+        *
+        * That was close enough to "no segment at all" until we
+        * hardened this function to disallow 16-bit TLS segments.  Fix
+        * it up by interpreting these zeroed segments the way that they
+        * were almost certainly intended to be interpreted.
+        *
+        * The correct way to ask for "no segment at all" is to specify
+        * a user_desc that satisfies LDT_empty.  To keep everything
+        * working, we accept both.
+        *
+        * Note that there's a similar kludge in modify_ldt -- look at
+        * the distinction between modes 1 and 0x11.
+        */
+       if (LDT_empty(info) || LDT_zero(info))
                return true;
 
        /*
@@ -71,7 +92,7 @@ static void set_tls_desc(struct task_struct *p, int idx,
        cpu = get_cpu();
 
        while (n-- > 0) {
-               if (LDT_empty(info))
+               if (LDT_empty(info) || LDT_zero(info))
                        desc->a = desc->b = 0;
                else
                        fill_ldt(desc, info);
index b7e50bba3bbbb98066fac741d826e5f6f4d7e946..505449700e0cf4e66ea6284135482ac172fe756a 100644 (file)
@@ -617,7 +617,7 @@ static unsigned long quick_pit_calibrate(void)
                        goto success;
                }
        }
-       pr_err("Fast TSC calibration failed\n");
+       pr_info("Fast TSC calibration failed\n");
        return 0;
 
 success:
index 169b09d76ddd83d3033d93d2b7eace6fada2331e..de12c1d379f16899645d96a2c3fd75663919c86d 100644 (file)
@@ -2348,7 +2348,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
         * Not recognized on AMD in compat mode (but is recognized in legacy
         * mode).
         */
-       if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA)
+       if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA)
            && !vendor_intel(ctxt))
                return emulate_ud(ctxt);
 
@@ -2359,25 +2359,13 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
        setup_syscalls_segments(ctxt, &cs, &ss);
 
        ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data);
-       switch (ctxt->mode) {
-       case X86EMUL_MODE_PROT32:
-               if ((msr_data & 0xfffc) == 0x0)
-                       return emulate_gp(ctxt, 0);
-               break;
-       case X86EMUL_MODE_PROT64:
-               if (msr_data == 0x0)
-                       return emulate_gp(ctxt, 0);
-               break;
-       default:
-               break;
-       }
+       if ((msr_data & 0xfffc) == 0x0)
+               return emulate_gp(ctxt, 0);
 
        ctxt->eflags &= ~(EFLG_VM | EFLG_IF);
-       cs_sel = (u16)msr_data;
-       cs_sel &= ~SELECTOR_RPL_MASK;
+       cs_sel = (u16)msr_data & ~SELECTOR_RPL_MASK;
        ss_sel = cs_sel + 8;
-       ss_sel &= ~SELECTOR_RPL_MASK;
-       if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) {
+       if (efer & EFER_LMA) {
                cs.d = 0;
                cs.l = 1;
        }
@@ -2386,10 +2374,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
        ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
 
        ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data);
-       ctxt->_eip = msr_data;
+       ctxt->_eip = (efer & EFER_LMA) ? msr_data : (u32)msr_data;
 
        ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
-       *reg_write(ctxt, VCPU_REGS_RSP) = msr_data;
+       *reg_write(ctxt, VCPU_REGS_RSP) = (efer & EFER_LMA) ? msr_data :
+                                                             (u32)msr_data;
 
        return X86EMUL_CONTINUE;
 }
@@ -3791,8 +3780,8 @@ static const struct opcode group5[] = {
 };
 
 static const struct opcode group6[] = {
-       DI(Prot       sldt),
-       DI(Prot       str),
+       DI(Prot | DstMem,       sldt),
+       DI(Prot | DstMem,       str),
        II(Prot | Priv | SrcMem16, em_lldt, lldt),
        II(Prot | Priv | SrcMem16, em_ltr, ltr),
        N, N, N, N,
index 4f0c0b954686cbf5e980f761b5b9bd4f7bc2df9a..d52dcf0776ea930df81ded94ed22af0b9d11e48b 100644 (file)
@@ -192,6 +192,9 @@ static void recalculate_apic_map(struct kvm *kvm)
                u16 cid, lid;
                u32 ldr, aid;
 
+               if (!kvm_apic_present(vcpu))
+                       continue;
+
                aid = kvm_apic_id(apic);
                ldr = kvm_apic_get_reg(apic, APIC_LDR);
                cid = apic_cluster_id(new, ldr);
index 10fbed126b1121ae5fde2f7ccfbf04133b5f8771..f83fc6c5e0bad6712e9f172acaba931c47cd32cd 100644 (file)
@@ -4448,7 +4448,7 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm)
         * zap all shadow pages.
         */
        if (unlikely(kvm_current_mmio_generation(kvm) == 0)) {
-               printk_ratelimited(KERN_INFO "kvm: zapping shadow pages for mmio generation wraparound\n");
+               printk_ratelimited(KERN_DEBUG "kvm: zapping shadow pages for mmio generation wraparound\n");
                kvm_mmu_invalidate_zap_all_pages(kvm);
        }
 }
index feb852b04598b63d187b0870db26d008c81a13d8..d4c58d884838d1539cb52e13df3c6893459a98af 100644 (file)
@@ -5840,53 +5840,10 @@ static __init int hardware_setup(void)
        memset(vmx_msr_bitmap_legacy, 0xff, PAGE_SIZE);
        memset(vmx_msr_bitmap_longmode, 0xff, PAGE_SIZE);
 
-       vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
-       vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
-       vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
-       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
-       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
-       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
-       vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
-
-       memcpy(vmx_msr_bitmap_legacy_x2apic,
-                       vmx_msr_bitmap_legacy, PAGE_SIZE);
-       memcpy(vmx_msr_bitmap_longmode_x2apic,
-                       vmx_msr_bitmap_longmode, PAGE_SIZE);
-
-       if (enable_apicv) {
-               for (msr = 0x800; msr <= 0x8ff; msr++)
-                       vmx_disable_intercept_msr_read_x2apic(msr);
-
-               /* According SDM, in x2apic mode, the whole id reg is used.
-                * But in KVM, it only use the highest eight bits. Need to
-                * intercept it */
-               vmx_enable_intercept_msr_read_x2apic(0x802);
-               /* TMCCT */
-               vmx_enable_intercept_msr_read_x2apic(0x839);
-               /* TPR */
-               vmx_disable_intercept_msr_write_x2apic(0x808);
-               /* EOI */
-               vmx_disable_intercept_msr_write_x2apic(0x80b);
-               /* SELF-IPI */
-               vmx_disable_intercept_msr_write_x2apic(0x83f);
-       }
-
-       if (enable_ept) {
-               kvm_mmu_set_mask_ptes(0ull,
-                       (enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
-                       (enable_ept_ad_bits) ? VMX_EPT_DIRTY_BIT : 0ull,
-                       0ull, VMX_EPT_EXECUTABLE_MASK);
-               ept_set_mmio_spte_mask();
-               kvm_enable_tdp();
-       } else
-               kvm_disable_tdp();
-
-       update_ple_window_actual_max();
-
        if (setup_vmcs_config(&vmcs_config) < 0) {
                r = -EIO;
                goto out7;
-    }
+       }
 
        if (boot_cpu_has(X86_FEATURE_NX))
                kvm_enable_efer_bits(EFER_NX);
@@ -5945,6 +5902,49 @@ static __init int hardware_setup(void)
        if (nested)
                nested_vmx_setup_ctls_msrs();
 
+       vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
+       vmx_disable_intercept_for_msr(MSR_GS_BASE, false);
+       vmx_disable_intercept_for_msr(MSR_KERNEL_GS_BASE, true);
+       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_CS, false);
+       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_ESP, false);
+       vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
+       vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
+
+       memcpy(vmx_msr_bitmap_legacy_x2apic,
+                       vmx_msr_bitmap_legacy, PAGE_SIZE);
+       memcpy(vmx_msr_bitmap_longmode_x2apic,
+                       vmx_msr_bitmap_longmode, PAGE_SIZE);
+
+       if (enable_apicv) {
+               for (msr = 0x800; msr <= 0x8ff; msr++)
+                       vmx_disable_intercept_msr_read_x2apic(msr);
+
+               /* According SDM, in x2apic mode, the whole id reg is used.
+                * But in KVM, it only use the highest eight bits. Need to
+                * intercept it */
+               vmx_enable_intercept_msr_read_x2apic(0x802);
+               /* TMCCT */
+               vmx_enable_intercept_msr_read_x2apic(0x839);
+               /* TPR */
+               vmx_disable_intercept_msr_write_x2apic(0x808);
+               /* EOI */
+               vmx_disable_intercept_msr_write_x2apic(0x80b);
+               /* SELF-IPI */
+               vmx_disable_intercept_msr_write_x2apic(0x83f);
+       }
+
+       if (enable_ept) {
+               kvm_mmu_set_mask_ptes(0ull,
+                       (enable_ept_ad_bits) ? VMX_EPT_ACCESS_BIT : 0ull,
+                       (enable_ept_ad_bits) ? VMX_EPT_DIRTY_BIT : 0ull,
+                       0ull, VMX_EPT_EXECUTABLE_MASK);
+               ept_set_mmio_spte_mask();
+               kvm_enable_tdp();
+       } else
+               kvm_disable_tdp();
+
+       update_ple_window_actual_max();
+
        return alloc_kvm_area();
 
 out7:
index 2480978b31cc29e5d34cd54bbd05394eeee4b484..1313ae6b478b6c439741ee032a8c33b86868ee2c 100644 (file)
@@ -28,7 +28,7 @@
 
 /* Verify next sizeof(t) bytes can be on the same instruction */
 #define validate_next(t, insn, n)      \
-       ((insn)->next_byte + sizeof(t) + n < (insn)->end_kaddr)
+       ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr)
 
 #define __get_next(t, insn)    \
        ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
index 38dcec403b46ae5b33c5967e6740faa8378e1380..e3ff27a5b6348ffb2dcff6f592abafe48b6b6396 100644 (file)
@@ -898,6 +898,8 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
                if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
                             VM_FAULT_HWPOISON_LARGE))
                        do_sigbus(regs, error_code, address, fault);
+               else if (fault & VM_FAULT_SIGSEGV)
+                       bad_area_nosemaphore(regs, error_code, address);
                else
                        BUG();
        }
index a97ee0801475a2e25df60f336c552408fe1d2b63..079c3b6a3ff181277a7cb4270895f27d9a1d6f8b 100644 (file)
@@ -43,7 +43,7 @@ uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM] = {
        [_PAGE_CACHE_MODE_WT]           = _PAGE_PCD,
        [_PAGE_CACHE_MODE_WP]           = _PAGE_PCD,
 };
-EXPORT_SYMBOL_GPL(__cachemode2pte_tbl);
+EXPORT_SYMBOL(__cachemode2pte_tbl);
 uint8_t __pte2cachemode_tbl[8] = {
        [__pte2cm_idx(0)] = _PAGE_CACHE_MODE_WB,
        [__pte2cm_idx(_PAGE_PWT)] = _PAGE_CACHE_MODE_WC,
@@ -54,7 +54,7 @@ uint8_t __pte2cachemode_tbl[8] = {
        [__pte2cm_idx(_PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC_MINUS,
        [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
 };
-EXPORT_SYMBOL_GPL(__pte2cachemode_tbl);
+EXPORT_SYMBOL(__pte2cachemode_tbl);
 
 static unsigned long __initdata pgt_buf_start;
 static unsigned long __initdata pgt_buf_end;
@@ -438,20 +438,20 @@ static unsigned long __init init_range_memory_mapping(
 static unsigned long __init get_new_step_size(unsigned long step_size)
 {
        /*
-        * Explain why we shift by 5 and why we don't have to worry about
-        * 'step_size << 5' overflowing:
-        *
-        * initial mapped size is PMD_SIZE (2M).
+        * Initial mapped size is PMD_SIZE (2M).
         * We can not set step_size to be PUD_SIZE (1G) yet.
         * In worse case, when we cross the 1G boundary, and
         * PG_LEVEL_2M is not set, we will need 1+1+512 pages (2M + 8k)
-        * to map 1G range with PTE. Use 5 as shift for now.
+        * to map 1G range with PTE. Hence we use one less than the
+        * difference of page table level shifts.
         *
-        * Don't need to worry about overflow, on 32bit, when step_size
-        * is 0, round_down() returns 0 for start, and that turns it
-        * into 0x100000000ULL.
+        * Don't need to worry about overflow in the top-down case, on 32bit,
+        * when step_size is 0, round_down() returns 0 for start, and that
+        * turns it into 0x100000000ULL.
+        * In the bottom-up case, round_up(x, 0) returns 0 though too, which
+        * needs to be taken into consideration by the code below.
         */
-       return step_size << 5;
+       return step_size << (PMD_SHIFT - PAGE_SHIFT - 1);
 }
 
 /**
@@ -471,7 +471,6 @@ static void __init memory_map_top_down(unsigned long map_start,
        unsigned long step_size;
        unsigned long addr;
        unsigned long mapped_ram_size = 0;
-       unsigned long new_mapped_ram_size;
 
        /* xen has big range in reserved near end of ram, skip it at first.*/
        addr = memblock_find_in_range(map_start, map_end, PMD_SIZE, PMD_SIZE);
@@ -496,14 +495,12 @@ static void __init memory_map_top_down(unsigned long map_start,
                                start = map_start;
                } else
                        start = map_start;
-               new_mapped_ram_size = init_range_memory_mapping(start,
+               mapped_ram_size += init_range_memory_mapping(start,
                                                        last_start);
                last_start = start;
                min_pfn_mapped = last_start >> PAGE_SHIFT;
-               /* only increase step_size after big range get mapped */
-               if (new_mapped_ram_size > mapped_ram_size)
+               if (mapped_ram_size >= step_size)
                        step_size = get_new_step_size(step_size);
-               mapped_ram_size += new_mapped_ram_size;
        }
 
        if (real_end < map_end)
@@ -524,7 +521,7 @@ static void __init memory_map_top_down(unsigned long map_start,
 static void __init memory_map_bottom_up(unsigned long map_start,
                                        unsigned long map_end)
 {
-       unsigned long next, new_mapped_ram_size, start;
+       unsigned long next, start;
        unsigned long mapped_ram_size = 0;
        /* step_size need to be small so pgt_buf from BRK could cover it */
        unsigned long step_size = PMD_SIZE;
@@ -539,19 +536,19 @@ static void __init memory_map_bottom_up(unsigned long map_start,
         * for page table.
         */
        while (start < map_end) {
-               if (map_end - start > step_size) {
+               if (step_size && map_end - start > step_size) {
                        next = round_up(start + 1, step_size);
                        if (next > map_end)
                                next = map_end;
-               } else
+               } else {
                        next = map_end;
+               }
 
-               new_mapped_ram_size = init_range_memory_mapping(start, next);
+               mapped_ram_size += init_range_memory_mapping(start, next);
                start = next;
 
-               if (new_mapped_ram_size > mapped_ram_size)
+               if (mapped_ram_size >= step_size)
                        step_size = get_new_step_size(step_size);
-               mapped_ram_size += new_mapped_ram_size;
        }
 }
 
index 67ebf57512229a4a29bceda04324c177a587232f..c439ec47821601c5b594bc1eec5abc529c5fd012 100644 (file)
@@ -348,6 +348,12 @@ static __user void *task_get_bounds_dir(struct task_struct *tsk)
        if (!cpu_feature_enabled(X86_FEATURE_MPX))
                return MPX_INVALID_BOUNDS_DIR;
 
+       /*
+        * 32-bit binaries on 64-bit kernels are currently
+        * unsupported.
+        */
+       if (IS_ENABLED(CONFIG_X86_64) && test_thread_flag(TIF_IA32))
+               return MPX_INVALID_BOUNDS_DIR;
        /*
         * The bounds directory pointer is stored in a register
         * only accessible if we first do an xsave.
index edf299c8ff6c774dea8116092a41b15102d9cf1c..7ac68698406c3b35e5ce0b0e98c73c5441e869a3 100644 (file)
@@ -234,8 +234,13 @@ void pat_init(void)
              PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC);
 
        /* Boot CPU check */
-       if (!boot_pat_state)
+       if (!boot_pat_state) {
                rdmsrl(MSR_IA32_CR_PAT, boot_pat_state);
+               if (!boot_pat_state) {
+                       pat_disable("PAT read returns always zero, disabled.");
+                       return;
+               }
+       }
 
        wrmsrl(MSR_IA32_CR_PAT, pat);
 
index 9b18ef315a559bca66ba227da77ac2d329475f19..349c0d32cc0b140222141cfec5fa29a8c6ddbace 100644 (file)
@@ -216,7 +216,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
                        continue;
                if (r->parent)  /* Already allocated */
                        continue;
-               if (!r->start || pci_claim_resource(dev, idx) < 0) {
+               if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) {
                        /*
                         * Something is wrong with the region.
                         * Invalidate the resource to prevent
index c489ef2c1a3915a0b22952520d89c82958a718c9..9098d880c476cf842598d32805ed25ac37fc9ae1 100644 (file)
@@ -458,6 +458,7 @@ int __init pci_xen_hvm_init(void)
         * just how GSIs get registered.
         */
        __acpi_register_gsi = acpi_register_gsi_xen_hvm;
+       __acpi_unregister_gsi = NULL;
 #endif
 
 #ifdef CONFIG_PCI_MSI
@@ -471,52 +472,6 @@ int __init pci_xen_hvm_init(void)
 }
 
 #ifdef CONFIG_XEN_DOM0
-static __init void xen_setup_acpi_sci(void)
-{
-       int rc;
-       int trigger, polarity;
-       int gsi = acpi_sci_override_gsi;
-       int irq = -1;
-       int gsi_override = -1;
-
-       if (!gsi)
-               return;
-
-       rc = acpi_get_override_irq(gsi, &trigger, &polarity);
-       if (rc) {
-               printk(KERN_WARNING "xen: acpi_get_override_irq failed for acpi"
-                               " sci, rc=%d\n", rc);
-               return;
-       }
-       trigger = trigger ? ACPI_LEVEL_SENSITIVE : ACPI_EDGE_SENSITIVE;
-       polarity = polarity ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
-
-       printk(KERN_INFO "xen: sci override: global_irq=%d trigger=%d "
-                       "polarity=%d\n", gsi, trigger, polarity);
-
-       /* Before we bind the GSI to a Linux IRQ, check whether
-        * we need to override it with bus_irq (IRQ) value. Usually for
-        * IRQs below IRQ_LEGACY_IRQ this holds IRQ == GSI, as so:
-        *  ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level)
-        * but there are oddballs where the IRQ != GSI:
-        *  ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 20 low level)
-        * which ends up being: gsi_to_irq[9] == 20
-        * (which is what acpi_gsi_to_irq ends up calling when starting the
-        * the ACPI interpreter and keels over since IRQ 9 has not been
-        * setup as we had setup IRQ 20 for it).
-        */
-       if (acpi_gsi_to_irq(gsi, &irq) == 0) {
-               /* Use the provided value if it's valid. */
-               if (irq >= 0)
-                       gsi_override = irq;
-       }
-
-       gsi = xen_register_gsi(gsi, gsi_override, trigger, polarity);
-       printk(KERN_INFO "xen: acpi sci %d\n", gsi);
-
-       return;
-}
-
 int __init pci_xen_initial_domain(void)
 {
        int irq;
@@ -527,8 +482,8 @@ int __init pci_xen_initial_domain(void)
        x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
        pci_msi_ignore_mask = 1;
 #endif
-       xen_setup_acpi_sci();
        __acpi_register_gsi = acpi_register_gsi_xen;
+       __acpi_unregister_gsi = NULL;
        /* Pre-allocate legacy irqs */
        for (irq = 0; irq < nr_legacy_irqs(); irq++) {
                int trigger, polarity;
diff --git a/arch/x86/tools/calc_run_size.pl b/arch/x86/tools/calc_run_size.pl
deleted file mode 100644 (file)
index 23210ba..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/perl
-#
-# Calculate the amount of space needed to run the kernel, including room for
-# the .bss and .brk sections.
-#
-# Usage:
-# objdump -h a.out | perl calc_run_size.pl
-use strict;
-
-my $mem_size = 0;
-my $file_offset = 0;
-
-my $sections=" *[0-9]+ \.(?:bss|brk) +";
-while (<>) {
-       if (/^$sections([0-9a-f]+) +(?:[0-9a-f]+ +){2}([0-9a-f]+)/) {
-               my $size = hex($1);
-               my $offset = hex($2);
-               $mem_size += $size;
-               if ($file_offset == 0) {
-                       $file_offset = $offset;
-               } elsif ($file_offset != $offset) {
-                       # BFD linker shows the same file offset in ELF.
-                       # Gold linker shows them as consecutive.
-                       next if ($file_offset + $mem_size == $offset + $size);
-
-                       printf STDERR "file_offset: 0x%lx\n", $file_offset;
-                       printf STDERR "mem_size: 0x%lx\n", $mem_size;
-                       printf STDERR "offset: 0x%lx\n", $offset;
-                       printf STDERR "size: 0x%lx\n", $size;
-
-                       die ".bss and .brk are non-contiguous\n";
-               }
-       }
-}
-
-if ($file_offset == 0) {
-       die "Never found .bss or .brk file offset\n";
-}
-printf("%d\n", $mem_size + $file_offset);
diff --git a/arch/x86/tools/calc_run_size.sh b/arch/x86/tools/calc_run_size.sh
new file mode 100644 (file)
index 0000000..1a4c17b
--- /dev/null
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Calculate the amount of space needed to run the kernel, including room for
+# the .bss and .brk sections.
+#
+# Usage:
+# objdump -h a.out | sh calc_run_size.sh
+
+NUM='\([0-9a-fA-F]*[ \t]*\)'
+OUT=$(sed -n 's/^[ \t0-9]*.b[sr][sk][ \t]*'"$NUM$NUM$NUM$NUM"'.*/\1\4/p')
+if [ -z "$OUT" ] ; then
+       echo "Never found .bss or .brk file offset" >&2
+       exit 1
+fi
+
+OUT=$(echo ${OUT# })
+sizeA=$(printf "%d" 0x${OUT%% *})
+OUT=${OUT#* }
+offsetA=$(printf "%d" 0x${OUT%% *})
+OUT=${OUT#* }
+sizeB=$(printf "%d" 0x${OUT%% *})
+OUT=${OUT#* }
+offsetB=$(printf "%d" 0x${OUT%% *})
+
+run_size=$(( $offsetA + $sizeA + $sizeB ))
+
+# BFD linker shows the same file offset in ELF.
+if [ "$offsetA" -ne "$offsetB" ] ; then
+       # Gold linker shows them as consecutive.
+       endB=$(( $offsetB + $sizeB ))
+       if [ "$endB" != "$run_size" ] ; then
+               printf "sizeA: 0x%x\n" $sizeA >&2
+               printf "offsetA: 0x%x\n" $offsetA >&2
+               printf "sizeB: 0x%x\n" $sizeB >&2
+               printf "offsetB: 0x%x\n" $offsetB >&2
+               echo ".bss and .brk are non-contiguous" >&2
+               exit 1
+       fi
+fi
+
+printf "%d\n" $run_size
+exit 0
index 531d4269e2e3c5303e8b40e6753dd20ddab3c405..bd16d6c370ec9aaeb3328779e277de8129ef61f3 100644 (file)
@@ -34,7 +34,7 @@ typedef asmlinkage void (*sys_call_ptr_t)(void);
 
 extern asmlinkage void sys_ni_syscall(void);
 
-const sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
+const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
        /*
         * Smells like a compiler bug -- it doesn't work
         * when the & below is removed.
index 20c3649d06915cce37ea62b5ee8c9a6d704c0a62..5cdfa9db22175ed8dc327465b4cf033a7a65d3bc 100644 (file)
@@ -47,7 +47,7 @@ typedef void (*sys_call_ptr_t)(void);
 
 extern void sys_ni_syscall(void);
 
-const sys_call_ptr_t sys_call_table[] __cacheline_aligned = {
+const sys_call_ptr_t sys_call_table[] ____cacheline_aligned = {
        /*
         * Smells like a compiler bug -- it doesn't work
         * when the & below is removed.
index 009495b9ab4bc52c0927accd29fe0b673cda5f7e..1c9f750c38592c7278c95d7f8dbe6e1a88835c0c 100644 (file)
@@ -41,12 +41,17 @@ void __init init_vdso_image(const struct vdso_image *image)
 
 struct linux_binprm;
 
-/* Put the vdso above the (randomized) stack with another randomized offset.
-   This way there is no hole in the middle of address space.
-   To save memory make sure it is still in the same PTE as the stack top.
-   This doesn't give that many random bits.
-
-   Only used for the 64-bit and x32 vdsos. */
+/*
+ * Put the vdso above the (randomized) stack with another randomized
+ * offset.  This way there is no hole in the middle of address space.
+ * To save memory make sure it is still in the same PTE as the stack
+ * top.  This doesn't give that many random bits.
+ *
+ * Note that this algorithm is imperfect: the distribution of the vdso
+ * start address within a PMD is biased toward the end.
+ *
+ * Only used for the 64-bit and x32 vdsos.
+ */
 static unsigned long vdso_addr(unsigned long start, unsigned len)
 {
 #ifdef CONFIG_X86_32
@@ -54,22 +59,30 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
 #else
        unsigned long addr, end;
        unsigned offset;
-       end = (start + PMD_SIZE - 1) & PMD_MASK;
+
+       /*
+        * Round up the start address.  It can start out unaligned as a result
+        * of stack start randomization.
+        */
+       start = PAGE_ALIGN(start);
+
+       /* Round the lowest possible end address up to a PMD boundary. */
+       end = (start + len + PMD_SIZE - 1) & PMD_MASK;
        if (end >= TASK_SIZE_MAX)
                end = TASK_SIZE_MAX;
        end -= len;
-       /* This loses some more bits than a modulo, but is cheaper */
-       offset = get_random_int() & (PTRS_PER_PTE - 1);
-       addr = start + (offset << PAGE_SHIFT);
-       if (addr >= end)
-               addr = end;
+
+       if (end > start) {
+               offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1);
+               addr = start + (offset << PAGE_SHIFT);
+       } else {
+               addr = start;
+       }
 
        /*
-        * page-align it here so that get_unmapped_area doesn't
-        * align it wrongfully again to the next page. addr can come in 4K
-        * unaligned here as a result of stack start randomization.
+        * Forcibly align the final address in case we have a hardware
+        * issue that requires alignment for performance reasons.
         */
-       addr = PAGE_ALIGN(addr);
        addr = align_vdso_addr(addr);
 
        return addr;
index 6bf3a13e3e0f7af10c8d984f829a512661d12c2e..78a881b7fc415e16f50f16e4381e968370f4fd9f 100644 (file)
@@ -40,6 +40,7 @@
 #include <xen/interface/physdev.h>
 #include <xen/interface/vcpu.h>
 #include <xen/interface/memory.h>
+#include <xen/interface/nmi.h>
 #include <xen/interface/xen-mca.h>
 #include <xen/features.h>
 #include <xen/page.h>
@@ -66,6 +67,7 @@
 #include <asm/reboot.h>
 #include <asm/stackprotector.h>
 #include <asm/hypervisor.h>
+#include <asm/mach_traps.h>
 #include <asm/mwait.h>
 #include <asm/pci_x86.h>
 #include <asm/pat.h>
@@ -1351,6 +1353,21 @@ static const struct machine_ops xen_machine_ops __initconst = {
        .emergency_restart = xen_emergency_restart,
 };
 
+static unsigned char xen_get_nmi_reason(void)
+{
+       unsigned char reason = 0;
+
+       /* Construct a value which looks like it came from port 0x61. */
+       if (test_bit(_XEN_NMIREASON_io_error,
+                    &HYPERVISOR_shared_info->arch.nmi_reason))
+               reason |= NMI_REASON_IOCHK;
+       if (test_bit(_XEN_NMIREASON_pci_serr,
+                    &HYPERVISOR_shared_info->arch.nmi_reason))
+               reason |= NMI_REASON_SERR;
+
+       return reason;
+}
+
 static void __init xen_boot_params_init_edd(void)
 {
 #if IS_ENABLED(CONFIG_EDD)
@@ -1535,9 +1552,12 @@ asmlinkage __visible void __init xen_start_kernel(void)
        pv_info = xen_info;
        pv_init_ops = xen_init_ops;
        pv_apic_ops = xen_apic_ops;
-       if (!xen_pvh_domain())
+       if (!xen_pvh_domain()) {
                pv_cpu_ops = xen_cpu_ops;
 
+               x86_platform.get_nmi_reason = xen_get_nmi_reason;
+       }
+
        if (xen_feature(XENFEAT_auto_translated_physmap))
                x86_init.resources.memory_setup = xen_auto_xlated_memory_setup;
        else
index edbc7a63fd737f0ca13edac752e1f06341f9dd97..70fb5075c901f5b0c370478b156288764f609ad8 100644 (file)
@@ -167,10 +167,13 @@ static void * __ref alloc_p2m_page(void)
        return (void *)__get_free_page(GFP_KERNEL | __GFP_REPEAT);
 }
 
-/* Only to be called in case of a race for a page just allocated! */
-static void free_p2m_page(void *p)
+static void __ref free_p2m_page(void *p)
 {
-       BUG_ON(!slab_is_available());
+       if (unlikely(!slab_is_available())) {
+               free_bootmem((unsigned long)p, PAGE_SIZE);
+               return;
+       }
+
        free_page((unsigned long)p);
 }
 
@@ -375,7 +378,7 @@ static void __init xen_rebuild_p2m_list(unsigned long *p2m)
                        p2m_missing_pte : p2m_identity_pte;
                for (i = 0; i < PMDS_PER_MID_PAGE; i++) {
                        pmdp = populate_extra_pmd(
-                               (unsigned long)(p2m + pfn + i * PTRS_PER_PTE));
+                               (unsigned long)(p2m + pfn) + i * PMD_SIZE);
                        set_pmd(pmdp, __pmd(__pa(ptep) | _KERNPG_TABLE));
                }
        }
@@ -436,10 +439,9 @@ EXPORT_SYMBOL_GPL(get_phys_to_machine);
  * a new pmd is to replace p2m_missing_pte or p2m_identity_pte by a individual
  * pmd. In case of PAE/x86-32 there are multiple pmds to allocate!
  */
-static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *ptep, pte_t *pte_pg)
+static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *pte_pg)
 {
        pte_t *ptechk;
-       pte_t *pteret = ptep;
        pte_t *pte_newpg[PMDS_PER_MID_PAGE];
        pmd_t *pmdp;
        unsigned int level;
@@ -473,8 +475,6 @@ static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *ptep, pte_t *pte_pg)
                if (ptechk == pte_pg) {
                        set_pmd(pmdp,
                                __pmd(__pa(pte_newpg[i]) | _KERNPG_TABLE));
-                       if (vaddr == (addr & ~(PMD_SIZE - 1)))
-                               pteret = pte_offset_kernel(pmdp, addr);
                        pte_newpg[i] = NULL;
                }
 
@@ -488,7 +488,7 @@ static pte_t *alloc_p2m_pmd(unsigned long addr, pte_t *ptep, pte_t *pte_pg)
                vaddr += PMD_SIZE;
        }
 
-       return pteret;
+       return lookup_address(addr, &level);
 }
 
 /*
@@ -517,7 +517,7 @@ static bool alloc_p2m(unsigned long pfn)
 
        if (pte_pg == p2m_missing_pte || pte_pg == p2m_identity_pte) {
                /* PMD level is missing, allocate a new one */
-               ptep = alloc_p2m_pmd(addr, ptep, pte_pg);
+               ptep = alloc_p2m_pmd(addr, pte_pg);
                if (!ptep)
                        return false;
        }
index dfd77dec8e2b7c1ef72d16adb1ecf7f7b80c88de..865e56cea7a0abe4d9b6feb2e1d0da27957d47e8 100644 (file)
@@ -140,7 +140,7 @@ static void __init xen_del_extra_mem(u64 start, u64 size)
 unsigned long __ref xen_chk_extra_mem(unsigned long pfn)
 {
        int i;
-       unsigned long addr = PFN_PHYS(pfn);
+       phys_addr_t addr = PFN_PHYS(pfn);
 
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
                if (addr >= xen_extra_mem[i].start &&
@@ -160,6 +160,8 @@ void __init xen_inv_extra_mem(void)
        int i;
 
        for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) {
+               if (!xen_extra_mem[i].size)
+                       continue;
                pfn_s = PFN_DOWN(xen_extra_mem[i].start);
                pfn_e = PFN_UP(xen_extra_mem[i].start + xen_extra_mem[i].size);
                for (pfn = pfn_s; pfn < pfn_e; pfn++)
@@ -229,15 +231,14 @@ static int __init xen_free_mfn(unsigned long mfn)
  * as a fallback if the remapping fails.
  */
 static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn,
-       unsigned long end_pfn, unsigned long nr_pages, unsigned long *identity,
-       unsigned long *released)
+       unsigned long end_pfn, unsigned long nr_pages, unsigned long *released)
 {
-       unsigned long len = 0;
        unsigned long pfn, end;
        int ret;
 
        WARN_ON(start_pfn > end_pfn);
 
+       /* Release pages first. */
        end = min(end_pfn, nr_pages);
        for (pfn = start_pfn; pfn < end; pfn++) {
                unsigned long mfn = pfn_to_mfn(pfn);
@@ -250,16 +251,14 @@ static void __init xen_set_identity_and_release_chunk(unsigned long start_pfn,
                WARN(ret != 1, "Failed to release pfn %lx err=%d\n", pfn, ret);
 
                if (ret == 1) {
+                       (*released)++;
                        if (!__set_phys_to_machine(pfn, INVALID_P2M_ENTRY))
                                break;
-                       len++;
                } else
                        break;
        }
 
-       /* Need to release pages first */
-       *released += len;
-       *identity += set_phys_range_identity(start_pfn, end_pfn);
+       set_phys_range_identity(start_pfn, end_pfn);
 }
 
 /*
@@ -287,7 +286,7 @@ static void __init xen_update_mem_tables(unsigned long pfn, unsigned long mfn)
        }
 
        /* Update kernel mapping, but not for highmem. */
-       if ((pfn << PAGE_SHIFT) >= __pa(high_memory))
+       if (pfn >= PFN_UP(__pa(high_memory - 1)))
                return;
 
        if (HYPERVISOR_update_va_mapping((unsigned long)__va(pfn << PAGE_SHIFT),
@@ -318,7 +317,6 @@ static void __init xen_do_set_identity_and_remap_chunk(
        unsigned long ident_pfn_iter, remap_pfn_iter;
        unsigned long ident_end_pfn = start_pfn + size;
        unsigned long left = size;
-       unsigned long ident_cnt = 0;
        unsigned int i, chunk;
 
        WARN_ON(size == 0);
@@ -347,8 +345,7 @@ static void __init xen_do_set_identity_and_remap_chunk(
                xen_remap_mfn = mfn;
 
                /* Set identity map */
-               ident_cnt += set_phys_range_identity(ident_pfn_iter,
-                       ident_pfn_iter + chunk);
+               set_phys_range_identity(ident_pfn_iter, ident_pfn_iter + chunk);
 
                left -= chunk;
        }
@@ -371,7 +368,7 @@ static void __init xen_do_set_identity_and_remap_chunk(
 static unsigned long __init xen_set_identity_and_remap_chunk(
         const struct e820entry *list, size_t map_size, unsigned long start_pfn,
        unsigned long end_pfn, unsigned long nr_pages, unsigned long remap_pfn,
-       unsigned long *identity, unsigned long *released)
+       unsigned long *released, unsigned long *remapped)
 {
        unsigned long pfn;
        unsigned long i = 0;
@@ -386,8 +383,7 @@ static unsigned long __init xen_set_identity_and_remap_chunk(
                /* Do not remap pages beyond the current allocation */
                if (cur_pfn >= nr_pages) {
                        /* Identity map remaining pages */
-                       *identity += set_phys_range_identity(cur_pfn,
-                               cur_pfn + size);
+                       set_phys_range_identity(cur_pfn, cur_pfn + size);
                        break;
                }
                if (cur_pfn + size > nr_pages)
@@ -398,7 +394,7 @@ static unsigned long __init xen_set_identity_and_remap_chunk(
                if (!remap_range_size) {
                        pr_warning("Unable to find available pfn range, not remapping identity pages\n");
                        xen_set_identity_and_release_chunk(cur_pfn,
-                               cur_pfn + left, nr_pages, identity, released);
+                               cur_pfn + left, nr_pages, released);
                        break;
                }
                /* Adjust size to fit in current e820 RAM region */
@@ -410,7 +406,7 @@ static unsigned long __init xen_set_identity_and_remap_chunk(
                /* Update variables to reflect new mappings. */
                i += size;
                remap_pfn += size;
-               *identity += size;
+               *remapped += size;
        }
 
        /*
@@ -427,13 +423,13 @@ static unsigned long __init xen_set_identity_and_remap_chunk(
 
 static void __init xen_set_identity_and_remap(
        const struct e820entry *list, size_t map_size, unsigned long nr_pages,
-       unsigned long *released)
+       unsigned long *released, unsigned long *remapped)
 {
        phys_addr_t start = 0;
-       unsigned long identity = 0;
        unsigned long last_pfn = nr_pages;
        const struct e820entry *entry;
        unsigned long num_released = 0;
+       unsigned long num_remapped = 0;
        int i;
 
        /*
@@ -460,14 +456,14 @@ static void __init xen_set_identity_and_remap(
                                last_pfn = xen_set_identity_and_remap_chunk(
                                                list, map_size, start_pfn,
                                                end_pfn, nr_pages, last_pfn,
-                                               &identity, &num_released);
+                                               &num_released, &num_remapped);
                        start = end;
                }
        }
 
        *released = num_released;
+       *remapped = num_remapped;
 
-       pr_info("Set %ld page(s) to 1-1 mapping\n", identity);
        pr_info("Released %ld page(s)\n", num_released);
 }
 
@@ -586,6 +582,7 @@ char * __init xen_memory_setup(void)
        struct xen_memory_map memmap;
        unsigned long max_pages;
        unsigned long extra_pages = 0;
+       unsigned long remapped_pages;
        int i;
        int op;
 
@@ -635,9 +632,10 @@ char * __init xen_memory_setup(void)
         * underlying RAM.
         */
        xen_set_identity_and_remap(map, memmap.nr_entries, max_pfn,
-                                  &xen_released_pages);
+                                  &xen_released_pages, &remapped_pages);
 
        extra_pages += xen_released_pages;
+       extra_pages += remapped_pages;
 
        /*
         * Clamp the amount of extra memory to a EXTRA_MEM_RATIO
index f473d268d387fcdc8f237153b378508ec0c03f56..69087341d9aed7860dfd95549c0a8af5ffbf1ed6 100644 (file)
@@ -391,7 +391,7 @@ static const struct clock_event_device *xen_clockevent =
 
 struct xen_clock_event_device {
        struct clock_event_device evt;
-       char *name;
+       char name[16];
 };
 static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt.irq = -1 };
 
@@ -420,46 +420,38 @@ void xen_teardown_timer(int cpu)
        if (evt->irq >= 0) {
                unbind_from_irqhandler(evt->irq, NULL);
                evt->irq = -1;
-               kfree(per_cpu(xen_clock_events, cpu).name);
-               per_cpu(xen_clock_events, cpu).name = NULL;
        }
 }
 
 void xen_setup_timer(int cpu)
 {
-       char *name;
-       struct clock_event_device *evt;
+       struct xen_clock_event_device *xevt = &per_cpu(xen_clock_events, cpu);
+       struct clock_event_device *evt = &xevt->evt;
        int irq;
 
-       evt = &per_cpu(xen_clock_events, cpu).evt;
        WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
        if (evt->irq >= 0)
                xen_teardown_timer(cpu);
 
        printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
 
-       name = kasprintf(GFP_KERNEL, "timer%d", cpu);
-       if (!name)
-               name = "<timer kasprintf failed>";
+       snprintf(xevt->name, sizeof(xevt->name), "timer%d", cpu);
 
        irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
                                      IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER|
                                      IRQF_FORCE_RESUME|IRQF_EARLY_RESUME,
-                                     name, NULL);
+                                     xevt->name, NULL);
        (void)xen_set_irq_priority(irq, XEN_IRQ_PRIORITY_MAX);
 
        memcpy(evt, xen_clockevent, sizeof(*evt));
 
        evt->cpumask = cpumask_of(cpu);
        evt->irq = irq;
-       per_cpu(xen_clock_events, cpu).name = name;
 }
 
 
 void xen_setup_cpu_clockevents(void)
 {
-       BUG_ON(preemptible());
-
        clockevents_register_device(this_cpu_ptr(&xen_clock_events.evt));
 }
 
index b57c4f91f487efdc6b2f3f44fe43cfb12e9a7e0c..9e3571a6535c3b1bbc8535195ee40405fe9c42c0 100644 (file)
@@ -117,6 +117,8 @@ good_area:
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
+               else if (fault & VM_FAULT_SIGSEGV)
+                       goto bad_area;
                else if (fault & VM_FAULT_SIGBUS)
                        goto do_sigbus;
                BUG();
index 30f6153a40c27c7154dd453301807c7d39d1451c..3ad405571dcc5105a52da4284477a187db936f64 100644 (file)
@@ -473,6 +473,25 @@ void blk_queue_bypass_end(struct request_queue *q)
 }
 EXPORT_SYMBOL_GPL(blk_queue_bypass_end);
 
+void blk_set_queue_dying(struct request_queue *q)
+{
+       queue_flag_set_unlocked(QUEUE_FLAG_DYING, q);
+
+       if (q->mq_ops)
+               blk_mq_wake_waiters(q);
+       else {
+               struct request_list *rl;
+
+               blk_queue_for_each_rl(rl, q) {
+                       if (rl->rq_pool) {
+                               wake_up(&rl->wait[BLK_RW_SYNC]);
+                               wake_up(&rl->wait[BLK_RW_ASYNC]);
+                       }
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(blk_set_queue_dying);
+
 /**
  * blk_cleanup_queue - shutdown a request queue
  * @q: request queue to shutdown
@@ -486,7 +505,7 @@ void blk_cleanup_queue(struct request_queue *q)
 
        /* mark @q DYING, no new request or merges will be allowed afterwards */
        mutex_lock(&q->sysfs_lock);
-       queue_flag_set_unlocked(QUEUE_FLAG_DYING, q);
+       blk_set_queue_dying(q);
        spin_lock_irq(lock);
 
        /*
index 1630a20d5dcfa550ebe9c8815927d51b70bd9d56..6774a0e698675927be5c78dc34b0087d873b5ebe 100644 (file)
 
 static void blk_mq_sysfs_release(struct kobject *kobj)
 {
+       struct request_queue *q;
+
+       q = container_of(kobj, struct request_queue, mq_kobj);
+       free_percpu(q->queue_ctx);
+}
+
+static void blk_mq_ctx_release(struct kobject *kobj)
+{
+       struct blk_mq_ctx *ctx;
+
+       ctx = container_of(kobj, struct blk_mq_ctx, kobj);
+       kobject_put(&ctx->queue->mq_kobj);
+}
+
+static void blk_mq_hctx_release(struct kobject *kobj)
+{
+       struct blk_mq_hw_ctx *hctx;
+
+       hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj);
+       kfree(hctx);
 }
 
 struct blk_mq_ctx_sysfs_entry {
@@ -318,13 +338,13 @@ static struct kobj_type blk_mq_ktype = {
 static struct kobj_type blk_mq_ctx_ktype = {
        .sysfs_ops      = &blk_mq_sysfs_ops,
        .default_attrs  = default_ctx_attrs,
-       .release        = blk_mq_sysfs_release,
+       .release        = blk_mq_ctx_release,
 };
 
 static struct kobj_type blk_mq_hw_ktype = {
        .sysfs_ops      = &blk_mq_hw_sysfs_ops,
        .default_attrs  = default_hw_ctx_attrs,
-       .release        = blk_mq_sysfs_release,
+       .release        = blk_mq_hctx_release,
 };
 
 static void blk_mq_unregister_hctx(struct blk_mq_hw_ctx *hctx)
@@ -355,6 +375,7 @@ static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
                return ret;
 
        hctx_for_each_ctx(hctx, ctx, i) {
+               kobject_get(&q->mq_kobj);
                ret = kobject_add(&ctx->kobj, &hctx->kobj, "cpu%u", ctx->cpu);
                if (ret)
                        break;
index 32e8dbb9ad1c49f0078e57fae100f0e6a7eb8a73..60c9d4a93fe470ced7471cd8653d8a00fc8922d7 100644 (file)
@@ -68,9 +68,9 @@ bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
 }
 
 /*
- * Wakeup all potentially sleeping on normal (non-reserved) tags
+ * Wakeup all potentially sleeping on tags
  */
-static void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags)
+void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool include_reserve)
 {
        struct blk_mq_bitmap_tags *bt;
        int i, wake_index;
@@ -85,6 +85,12 @@ static void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags)
 
                wake_index = bt_index_inc(wake_index);
        }
+
+       if (include_reserve) {
+               bt = &tags->breserved_tags;
+               if (waitqueue_active(&bt->bs[0].wait))
+                       wake_up(&bt->bs[0].wait);
+       }
 }
 
 /*
@@ -100,7 +106,7 @@ void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
 
        atomic_dec(&tags->active_queues);
 
-       blk_mq_tag_wakeup_all(tags);
+       blk_mq_tag_wakeup_all(tags, false);
 }
 
 /*
@@ -584,7 +590,7 @@ int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
         * static and should never need resizing.
         */
        bt_update_count(&tags->bitmap_tags, tdepth);
-       blk_mq_tag_wakeup_all(tags);
+       blk_mq_tag_wakeup_all(tags, false);
        return 0;
 }
 
index 6206ed17ef766714b655a715ffbc05fd34b0463a..a6fa0fc9d41a2e91c8bb4ce29bb2b1a0d952c8ed 100644 (file)
@@ -54,6 +54,7 @@ extern bool blk_mq_has_free_tags(struct blk_mq_tags *tags);
 extern ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page);
 extern void blk_mq_tag_init_last_tag(struct blk_mq_tags *tags, unsigned int *last_tag);
 extern int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int depth);
+extern void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool);
 
 enum {
        BLK_MQ_TAG_CACHE_MIN    = 1,
index da1ab5641227b670faac42a84fde7e223668a4d8..9ee3b87c44984d336dbd4c82572fd3a4c3d35e90 100644 (file)
@@ -107,7 +107,7 @@ static void blk_mq_usage_counter_release(struct percpu_ref *ref)
        wake_up_all(&q->mq_freeze_wq);
 }
 
-static void blk_mq_freeze_queue_start(struct request_queue *q)
+void blk_mq_freeze_queue_start(struct request_queue *q)
 {
        bool freeze;
 
@@ -120,6 +120,7 @@ static void blk_mq_freeze_queue_start(struct request_queue *q)
                blk_mq_run_queues(q, false);
        }
 }
+EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_start);
 
 static void blk_mq_freeze_queue_wait(struct request_queue *q)
 {
@@ -136,7 +137,7 @@ void blk_mq_freeze_queue(struct request_queue *q)
        blk_mq_freeze_queue_wait(q);
 }
 
-static void blk_mq_unfreeze_queue(struct request_queue *q)
+void blk_mq_unfreeze_queue(struct request_queue *q)
 {
        bool wake;
 
@@ -149,6 +150,24 @@ static void blk_mq_unfreeze_queue(struct request_queue *q)
                wake_up_all(&q->mq_freeze_wq);
        }
 }
+EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue);
+
+void blk_mq_wake_waiters(struct request_queue *q)
+{
+       struct blk_mq_hw_ctx *hctx;
+       unsigned int i;
+
+       queue_for_each_hw_ctx(q, hctx, i)
+               if (blk_mq_hw_queue_mapped(hctx))
+                       blk_mq_tag_wakeup_all(hctx->tags, true);
+
+       /*
+        * If we are called because the queue has now been marked as
+        * dying, we need to ensure that processes currently waiting on
+        * the queue are notified as well.
+        */
+       wake_up_all(&q->mq_freeze_wq);
+}
 
 bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx)
 {
@@ -258,8 +277,10 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw, gfp_t gfp,
                ctx = alloc_data.ctx;
        }
        blk_mq_put_ctx(ctx);
-       if (!rq)
+       if (!rq) {
+               blk_mq_queue_exit(q);
                return ERR_PTR(-EWOULDBLOCK);
+       }
        return rq;
 }
 EXPORT_SYMBOL(blk_mq_alloc_request);
@@ -383,6 +404,12 @@ void blk_mq_complete_request(struct request *rq)
 }
 EXPORT_SYMBOL(blk_mq_complete_request);
 
+int blk_mq_request_started(struct request *rq)
+{
+       return test_bit(REQ_ATOM_STARTED, &rq->atomic_flags);
+}
+EXPORT_SYMBOL_GPL(blk_mq_request_started);
+
 void blk_mq_start_request(struct request *rq)
 {
        struct request_queue *q = rq->q;
@@ -500,12 +527,38 @@ void blk_mq_add_to_requeue_list(struct request *rq, bool at_head)
 }
 EXPORT_SYMBOL(blk_mq_add_to_requeue_list);
 
+void blk_mq_cancel_requeue_work(struct request_queue *q)
+{
+       cancel_work_sync(&q->requeue_work);
+}
+EXPORT_SYMBOL_GPL(blk_mq_cancel_requeue_work);
+
 void blk_mq_kick_requeue_list(struct request_queue *q)
 {
        kblockd_schedule_work(&q->requeue_work);
 }
 EXPORT_SYMBOL(blk_mq_kick_requeue_list);
 
+void blk_mq_abort_requeue_list(struct request_queue *q)
+{
+       unsigned long flags;
+       LIST_HEAD(rq_list);
+
+       spin_lock_irqsave(&q->requeue_lock, flags);
+       list_splice_init(&q->requeue_list, &rq_list);
+       spin_unlock_irqrestore(&q->requeue_lock, flags);
+
+       while (!list_empty(&rq_list)) {
+               struct request *rq;
+
+               rq = list_first_entry(&rq_list, struct request, queuelist);
+               list_del_init(&rq->queuelist);
+               rq->errors = -EIO;
+               blk_mq_end_request(rq, rq->errors);
+       }
+}
+EXPORT_SYMBOL(blk_mq_abort_requeue_list);
+
 static inline bool is_flush_request(struct request *rq,
                struct blk_flush_queue *fq, unsigned int tag)
 {
@@ -566,13 +619,24 @@ void blk_mq_rq_timed_out(struct request *req, bool reserved)
                break;
        }
 }
-               
+
 static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx,
                struct request *rq, void *priv, bool reserved)
 {
        struct blk_mq_timeout_data *data = priv;
 
-       if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags))
+       if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) {
+               /*
+                * If a request wasn't started before the queue was
+                * marked dying, kill it here or it'll go unnoticed.
+                */
+               if (unlikely(blk_queue_dying(rq->q))) {
+                       rq->errors = -EIO;
+                       blk_mq_complete_request(rq);
+               }
+               return;
+       }
+       if (rq->cmd_flags & REQ_NO_TIMEOUT)
                return;
 
        if (time_after_eq(jiffies, rq->deadline)) {
@@ -1577,10 +1641,8 @@ static void blk_mq_free_hw_queues(struct request_queue *q,
        struct blk_mq_hw_ctx *hctx;
        unsigned int i;
 
-       queue_for_each_hw_ctx(q, hctx, i) {
+       queue_for_each_hw_ctx(q, hctx, i)
                free_cpumask_var(hctx->cpumask);
-               kfree(hctx);
-       }
 }
 
 static int blk_mq_init_hctx(struct request_queue *q,
@@ -1601,7 +1663,6 @@ static int blk_mq_init_hctx(struct request_queue *q,
        hctx->queue = q;
        hctx->queue_num = hctx_idx;
        hctx->flags = set->flags;
-       hctx->cmd_size = set->cmd_size;
 
        blk_mq_init_cpu_notifier(&hctx->cpu_notifier,
                                        blk_mq_hctx_notify, hctx);
@@ -1939,11 +2000,9 @@ void blk_mq_free_queue(struct request_queue *q)
 
        percpu_ref_exit(&q->mq_usage_counter);
 
-       free_percpu(q->queue_ctx);
        kfree(q->queue_hw_ctx);
        kfree(q->mq_map);
 
-       q->queue_ctx = NULL;
        q->queue_hw_ctx = NULL;
        q->mq_map = NULL;
 
index 206230e64f7915e642ce7306aec8b949deca43b1..4f4f943c22c3d1e907ef2c18224b8635f0057e82 100644 (file)
@@ -32,6 +32,7 @@ void blk_mq_free_queue(struct request_queue *q);
 void blk_mq_clone_flush_request(struct request *flush_rq,
                struct request *orig_rq);
 int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr);
+void blk_mq_wake_waiters(struct request_queue *q);
 
 /*
  * CPU hotplug helpers
index 56c025894cdf2d73f78c5346c9c5987d5deb0e37..246dfb16c3d988c4f84749065a66977b825c98b5 100644 (file)
@@ -190,6 +190,9 @@ void blk_add_timer(struct request *req)
        struct request_queue *q = req->q;
        unsigned long expiry;
 
+       if (req->cmd_flags & REQ_NO_TIMEOUT)
+               return;
+
        /* blk-mq has its own handler, so we don't need ->rq_timed_out_fn */
        if (!q->mq_ops && !q->rq_timed_out_fn)
                return;
index 9b3c54c1cbe826a8cb031a9affb9079f0961d1c4..3dd101144a58def9c38adae3cdf21f810cdbe0aa 100644 (file)
@@ -1475,3 +1475,4 @@ module_exit(aes_fini);
 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_ALIAS_CRYPTO("aes");
+MODULE_ALIAS_CRYPTO("aes-generic");
index 1fa7bc31be63b9fb774782ebe3fbdaed0b16ff72..4665b79c729ac1d59d699907d3e5c75628231cdb 100644 (file)
@@ -455,6 +455,9 @@ void af_alg_complete(struct crypto_async_request *req, int err)
 {
        struct af_alg_completion *completion = req->data;
 
+       if (err == -EINPROGRESS)
+               return;
+
        completion->err = err;
        complete(&completion->completion);
 }
index b4485a108389a2f13b0ca28949e4f6b932818277..6f5bebc9bf01ebea38bca6dd616c6bd2c3ce2111 100644 (file)
@@ -477,3 +477,4 @@ MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)");
 module_init(prng_mod_init);
 module_exit(prng_mod_fini);
 MODULE_ALIAS_CRYPTO("stdrng");
+MODULE_ALIAS_CRYPTO("ansi_cprng");
index 7bd71f02d0dde233939716f3b0059cc758ab788c..87b392a77a9395a9e4164b7e9356e739c9f96455 100644 (file)
@@ -139,3 +139,4 @@ module_exit(blowfish_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Blowfish Cipher Algorithm");
 MODULE_ALIAS_CRYPTO("blowfish");
+MODULE_ALIAS_CRYPTO("blowfish-generic");
index 1b74c5a3e8910741cac8c92e292b041eff40e714..a02286bf319ea3cc0b52fd21079506f0667715b3 100644 (file)
@@ -1099,3 +1099,4 @@ module_exit(camellia_fini);
 MODULE_DESCRIPTION("Camellia Cipher Algorithm");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("camellia");
+MODULE_ALIAS_CRYPTO("camellia-generic");
index 84c86db67ec7a88a85fd92a93ad07af6eb935564..df5c72629383d99b9fa1c030112b8e0bfc3fbd96 100644 (file)
@@ -550,3 +550,4 @@ module_exit(cast5_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cast5 Cipher Algorithm");
 MODULE_ALIAS_CRYPTO("cast5");
+MODULE_ALIAS_CRYPTO("cast5-generic");
index f408f0bd8de2525ac369ae68c4bd5a5187b22e1d..058c8d755d0366532a7e824b7e22681a40624429 100644 (file)
@@ -292,3 +292,4 @@ module_exit(cast6_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cast6 Cipher Algorithm");
 MODULE_ALIAS_CRYPTO("cast6");
+MODULE_ALIAS_CRYPTO("cast6-generic");
index 2a062025749d925f858939933ebe67283f158562..06f1b60f02b223eeea70c000ec4055c470d4eeae 100644 (file)
@@ -171,4 +171,5 @@ MODULE_AUTHOR("Clay Haapala <chaapala@cisco.com>");
 MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("crc32c");
+MODULE_ALIAS_CRYPTO("crc32c-generic");
 MODULE_SOFTDEP("pre: crc32c");
index 08bb4f50452085b65c0ed263a84f5c8298142149..c1229614c7e324e5ee9341d6f2be530afd437487 100644 (file)
@@ -125,3 +125,4 @@ MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
 MODULE_DESCRIPTION("T10 DIF CRC calculation.");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("crct10dif");
+MODULE_ALIAS_CRYPTO("crct10dif-generic");
index 42912948776b1426ec71f2e6fe3d5debd3d67e72..a71720544d118f0134b5301924fe9ab0c572eda7 100644 (file)
@@ -983,8 +983,6 @@ static struct crypto_alg des_algs[2] = { {
        .cia_decrypt            =       des3_ede_decrypt } }
 } };
 
-MODULE_ALIAS_CRYPTO("des3_ede");
-
 static int __init des_generic_mod_init(void)
 {
        return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs));
@@ -1001,4 +999,7 @@ module_exit(des_generic_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
 MODULE_AUTHOR("Dag Arne Osvik <da@osvik.no>");
-MODULE_ALIAS("des");
+MODULE_ALIAS_CRYPTO("des");
+MODULE_ALIAS_CRYPTO("des-generic");
+MODULE_ALIAS_CRYPTO("des3_ede");
+MODULE_ALIAS_CRYPTO("des3_ede-generic");
index 4e97fae9666f6fd549235ea60c93f999ad00699c..bac70995e0640a49fbc56797c4f7b605791ff98b 100644 (file)
@@ -173,3 +173,4 @@ module_exit(ghash_mod_exit);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("GHASH Message Digest Algorithm");
 MODULE_ALIAS_CRYPTO("ghash");
+MODULE_ALIAS_CRYPTO("ghash-generic");
index 67c88b3312107c7c16e9732fa9ffba38172629f4..0224841b6579aa8a915406f7c3a944385c6fcbd6 100644 (file)
@@ -63,3 +63,4 @@ module_exit(krng_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Kernel Random Number Generator");
 MODULE_ALIAS_CRYPTO("stdrng");
+MODULE_ALIAS_CRYPTO("krng");
index 3d0f9df30ac9fe368baa63598db9426c2cd8657a..f550b5d9463074b16670129341de59e069f8509c 100644 (file)
@@ -249,3 +249,4 @@ module_exit(salsa20_generic_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION ("Salsa20 stream cipher algorithm");
 MODULE_ALIAS_CRYPTO("salsa20");
+MODULE_ALIAS_CRYPTO("salsa20-generic");
index a53b5e2af335c95d046b85c0162dd0a5bb25e5e4..94970a794975ac2148fbc0d84bf2e830719070da 100644 (file)
@@ -667,3 +667,4 @@ MODULE_DESCRIPTION("Serpent and tnepres (kerneli compatible serpent reversed) Ci
 MODULE_AUTHOR("Dag Arne Osvik <osvik@ii.uib.no>");
 MODULE_ALIAS_CRYPTO("tnepres");
 MODULE_ALIAS_CRYPTO("serpent");
+MODULE_ALIAS_CRYPTO("serpent-generic");
index 039e58cfa155655f42aec3ddcb8d2761aa22b264..a3e50c37eb6f8f670e4e7da64b62d05ebc2b56d8 100644 (file)
@@ -154,3 +154,4 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm");
 
 MODULE_ALIAS_CRYPTO("sha1");
+MODULE_ALIAS_CRYPTO("sha1-generic");
index 5eb21b1200333e95c73f11d3343183c37331544c..b001ff5c2efcec0d657fd33c2273be4980db690d 100644 (file)
@@ -385,4 +385,6 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm");
 
 MODULE_ALIAS_CRYPTO("sha224");
+MODULE_ALIAS_CRYPTO("sha224-generic");
 MODULE_ALIAS_CRYPTO("sha256");
+MODULE_ALIAS_CRYPTO("sha256-generic");
index 8d0b19ed4f4b3fb90df2266132f5877a488b1e1c..1c3c3767e079af825e3f53b779cca7f8c416b257 100644 (file)
@@ -289,4 +289,6 @@ MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("SHA-512 and SHA-384 Secure Hash Algorithms");
 
 MODULE_ALIAS_CRYPTO("sha384");
+MODULE_ALIAS_CRYPTO("sha384-generic");
 MODULE_ALIAS_CRYPTO("sha512");
+MODULE_ALIAS_CRYPTO("sha512-generic");
index 495be2d0077d4a2828323d2d9ec187964cd74948..b70b441c7d1e7e6135f000fa8fa58a3057671b20 100644 (file)
@@ -270,6 +270,7 @@ static void __exit tea_mod_fini(void)
        crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs));
 }
 
+MODULE_ALIAS_CRYPTO("tea");
 MODULE_ALIAS_CRYPTO("xtea");
 MODULE_ALIAS_CRYPTO("xeta");
 
index 6e5651c66cf8a783b235e1f8551154e8e01641de..321bc6ff2a9d1ff714b3f27e49b68f0d48ce17e0 100644 (file)
@@ -676,6 +676,7 @@ static void __exit tgr192_mod_fini(void)
        crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs));
 }
 
+MODULE_ALIAS_CRYPTO("tgr192");
 MODULE_ALIAS_CRYPTO("tgr160");
 MODULE_ALIAS_CRYPTO("tgr128");
 
index 523ad8c4e35918329cc08ef979d58a678f52dc5d..ebf7a3efb572715750c9529b8f54e9e724b6c5e7 100644 (file)
@@ -212,3 +212,4 @@ module_exit(twofish_mod_fini);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION ("Twofish Cipher Algorithm");
 MODULE_ALIAS_CRYPTO("twofish");
+MODULE_ALIAS_CRYPTO("twofish-generic");
index 0de42eb3d0400b895de0cf8e70e1015dd137ff87..7ee5a043a988350770c3fe712f45b4f3995063c9 100644 (file)
@@ -1167,6 +1167,7 @@ static void __exit wp512_mod_fini(void)
        crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs));
 }
 
+MODULE_ALIAS_CRYPTO("wp512");
 MODULE_ALIAS_CRYPTO("wp384");
 MODULE_ALIAS_CRYPTO("wp256");
 
index 694d5a70d6ce16d195301aa634c5ace2b1a81ec2..c70d6e45dc1029a8be0422bd21ca979b97e0365e 100644 (file)
@@ -134,8 +134,6 @@ source "drivers/staging/Kconfig"
 
 source "drivers/platform/Kconfig"
 
-source "drivers/soc/Kconfig"
-
 source "drivers/clk/Kconfig"
 
 source "drivers/hwspinlock/Kconfig"
index 67d2334dc41ecd571f9eb0dfd907cc87104912a9..527a6da8d539ad2abb84c5397e0087c1914501af 100644 (file)
@@ -50,7 +50,10 @@ obj-$(CONFIG_RESET_CONTROLLER)       += reset/
 obj-y                          += tty/
 obj-y                          += char/
 
-# gpu/ comes after char for AGP vs DRM startup
+# iommu/ comes before gpu as gpu are using iommu controllers
+obj-$(CONFIG_IOMMU_SUPPORT)    += iommu/
+
+# gpu/ comes after char for AGP vs DRM startup and after iommu
 obj-y                          += gpu/
 
 obj-$(CONFIG_CONNECTOR)                += connector/
@@ -141,7 +144,6 @@ obj-y                               += clk/
 
 obj-$(CONFIG_MAILBOX)          += mailbox/
 obj-$(CONFIG_HWSPINLOCK)       += hwspinlock/
-obj-$(CONFIG_IOMMU_SUPPORT)    += iommu/
 obj-$(CONFIG_REMOTEPROC)       += remoteproc/
 obj-$(CONFIG_RPMSG)            += rpmsg/
 
index 1fdf5e07a1c7cb0440594b12f8b78408c1c25bd4..1020b1b53a174e58111056e2c3e88089d0180d83 100644 (file)
@@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
        acpi_status status;
        int ret;
 
-       if (pr->apic_id == -1)
+       if (pr->phys_id == -1)
                return -ENODEV;
 
        status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
@@ -180,13 +180,13 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
        cpu_maps_update_begin();
        cpu_hotplug_begin();
 
-       ret = acpi_map_lsapic(pr->handle, pr->apic_id, &pr->id);
+       ret = acpi_map_cpu(pr->handle, pr->phys_id, &pr->id);
        if (ret)
                goto out;
 
        ret = arch_register_cpu(pr->id);
        if (ret) {
-               acpi_unmap_lsapic(pr->id);
+               acpi_unmap_cpu(pr->id);
                goto out;
        }
 
@@ -215,7 +215,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
        union acpi_object object = { 0 };
        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
        struct acpi_processor *pr = acpi_driver_data(device);
-       int apic_id, cpu_index, device_declaration = 0;
+       int phys_id, cpu_index, device_declaration = 0;
        acpi_status status = AE_OK;
        static int cpu0_initialized;
        unsigned long long value;
@@ -262,15 +262,18 @@ static int acpi_processor_get_info(struct acpi_device *device)
                pr->acpi_id = value;
        }
 
-       apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
-       if (apic_id < 0)
-               acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n");
-       pr->apic_id = apic_id;
+       phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id);
+       if (phys_id < 0)
+               acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n");
+       pr->phys_id = phys_id;
 
-       cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
+       cpu_index = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
        if (!cpu0_initialized && !acpi_has_cpu_in_madt()) {
                cpu0_initialized = 1;
-               /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+               /*
+                * Handle UP system running SMP kernel, with no CPU
+                * entry in MADT
+                */
                if ((cpu_index == -1) && (num_online_cpus() == 1))
                        cpu_index = 0;
        }
@@ -458,7 +461,7 @@ static void acpi_processor_remove(struct acpi_device *device)
 
        /* Remove the CPU. */
        arch_unregister_cpu(pr->id);
-       acpi_unmap_lsapic(pr->id);
+       acpi_unmap_cpu(pr->id);
 
        cpu_hotplug_done();
        cpu_maps_update_done();
index c2daa85fc9f70fa5aca61a6f2a4fbaa6b85df100..c0d44d394ca39c63f87f212f0345d0c05d9acdc4 100644 (file)
@@ -257,7 +257,7 @@ int acpi_bus_init_power(struct acpi_device *device)
 
        device->power.state = ACPI_STATE_UNKNOWN;
        if (!acpi_device_is_present(device))
-               return 0;
+               return -ENXIO;
 
        result = acpi_device_get_power(device, &state);
        if (result)
index a27d31d1ba24afcd176d1151aff62da8350e54b4..9dcf83682e367e889db67cd5ae44670878893459 100644 (file)
 
 #include "internal.h"
 
-#define DO_ENUMERATION 0x01
+#define INT3401_DEVICE 0X01
 static const struct acpi_device_id int340x_thermal_device_ids[] = {
-       {"INT3400", DO_ENUMERATION },
-       {"INT3401"},
+       {"INT3400"},
+       {"INT3401", INT3401_DEVICE},
        {"INT3402"},
        {"INT3403"},
        {"INT3404"},
@@ -34,7 +34,10 @@ static int int340x_thermal_handler_attach(struct acpi_device *adev,
                                        const struct acpi_device_id *id)
 {
 #if defined(CONFIG_INT340X_THERMAL) || defined(CONFIG_INT340X_THERMAL_MODULE)
-       if (id->driver_data == DO_ENUMERATION)
+       acpi_create_platform_device(adev);
+#elif defined(INTEL_SOC_DTS_THERMAL) || defined(INTEL_SOC_DTS_THERMAL_MODULE)
+       /* Intel SoC DTS thermal driver needs INT3401 to set IRQ descriptor */
+       if (id->driver_data == INT3401_DEVICE)
                acpi_create_platform_device(adev);
 #endif
        return 1;
index 5277a0ee57042b26cf78e6186a17899233801273..b1def411c0b89cbf7847b767063c5c2ab528e8a8 100644 (file)
@@ -512,7 +512,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
        dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin));
        if (gsi >= 0) {
                acpi_unregister_gsi(gsi);
-               dev->irq = 0;
                dev->irq_managed = 0;
        }
 }
index 342942f90a1031a3650306144d6858bb58a79b08..02e48394276c785aa84c72fcacf231b4b6cc4587 100644 (file)
@@ -69,7 +69,7 @@ static int map_madt_entry(int type, u32 acpi_id)
        unsigned long madt_end, entry;
        static struct acpi_table_madt *madt;
        static int read_madt;
-       int apic_id = -1;
+       int phys_id = -1;       /* CPU hardware ID */
 
        if (!read_madt) {
                if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
@@ -79,7 +79,7 @@ static int map_madt_entry(int type, u32 acpi_id)
        }
 
        if (!madt)
-               return apic_id;
+               return phys_id;
 
        entry = (unsigned long)madt;
        madt_end = entry + madt->header.length;
@@ -91,18 +91,18 @@ static int map_madt_entry(int type, u32 acpi_id)
                struct acpi_subtable_header *header =
                        (struct acpi_subtable_header *)entry;
                if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
-                       if (!map_lapic_id(header, acpi_id, &apic_id))
+                       if (!map_lapic_id(header, acpi_id, &phys_id))
                                break;
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
-                       if (!map_x2apic_id(header, type, acpi_id, &apic_id))
+                       if (!map_x2apic_id(header, type, acpi_id, &phys_id))
                                break;
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
-                       if (!map_lsapic_id(header, type, acpi_id, &apic_id))
+                       if (!map_lsapic_id(header, type, acpi_id, &phys_id))
                                break;
                }
                entry += header->length;
        }
-       return apic_id;
+       return phys_id;
 }
 
 static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
@@ -110,7 +110,7 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
        struct acpi_subtable_header *header;
-       int apic_id = -1;
+       int phys_id = -1;
 
        if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
                goto exit;
@@ -126,38 +126,38 @@ static int map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
 
        header = (struct acpi_subtable_header *)obj->buffer.pointer;
        if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
-               map_lapic_id(header, acpi_id, &apic_id);
+               map_lapic_id(header, acpi_id, &phys_id);
        else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
-               map_lsapic_id(header, type, acpi_id, &apic_id);
+               map_lsapic_id(header, type, acpi_id, &phys_id);
        else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
-               map_x2apic_id(header, type, acpi_id, &apic_id);
+               map_x2apic_id(header, type, acpi_id, &phys_id);
 
 exit:
        kfree(buffer.pointer);
-       return apic_id;
+       return phys_id;
 }
 
-int acpi_get_apicid(acpi_handle handle, int type, u32 acpi_id)
+int acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
 {
-       int apic_id;
+       int phys_id;
 
-       apic_id = map_mat_entry(handle, type, acpi_id);
-       if (apic_id == -1)
-               apic_id = map_madt_entry(type, acpi_id);
+       phys_id = map_mat_entry(handle, type, acpi_id);
+       if (phys_id == -1)
+               phys_id = map_madt_entry(type, acpi_id);
 
-       return apic_id;
+       return phys_id;
 }
 
-int acpi_map_cpuid(int apic_id, u32 acpi_id)
+int acpi_map_cpuid(int phys_id, u32 acpi_id)
 {
 #ifdef CONFIG_SMP
        int i;
 #endif
 
-       if (apic_id == -1) {
+       if (phys_id == -1) {
                /*
                 * On UP processor, there is no _MAT or MADT table.
-                * So above apic_id is always set to -1.
+                * So above phys_id is always set to -1.
                 *
                 * BIOS may define multiple CPU handles even for UP processor.
                 * For example,
@@ -170,7 +170,7 @@ int acpi_map_cpuid(int apic_id, u32 acpi_id)
                 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
                 * }
                 *
-                * Ignores apic_id and always returns 0 for the processor
+                * Ignores phys_id and always returns 0 for the processor
                 * handle with acpi id 0 if nr_cpu_ids is 1.
                 * This should be the case if SMP tables are not found.
                 * Return -1 for other CPU's handle.
@@ -178,28 +178,28 @@ int acpi_map_cpuid(int apic_id, u32 acpi_id)
                if (nr_cpu_ids <= 1 && acpi_id == 0)
                        return acpi_id;
                else
-                       return apic_id;
+                       return phys_id;
        }
 
 #ifdef CONFIG_SMP
        for_each_possible_cpu(i) {
-               if (cpu_physical_id(i) == apic_id)
+               if (cpu_physical_id(i) == phys_id)
                        return i;
        }
 #else
        /* In UP kernel, only processor 0 is valid */
-       if (apic_id == 0)
-               return apic_id;
+       if (phys_id == 0)
+               return phys_id;
 #endif
        return -1;
 }
 
 int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
 {
-       int apic_id;
+       int phys_id;
 
-       apic_id = acpi_get_apicid(handle, type, acpi_id);
+       phys_id = acpi_get_phys_id(handle, type, acpi_id);
 
-       return acpi_map_cpuid(apic_id, acpi_id);
+       return acpi_map_cpuid(phys_id, acpi_id);
 }
 EXPORT_SYMBOL_GPL(acpi_get_cpuid);
index 4995365046984e55855373484b47936b2569447d..87b704e41877daa488eec962f545f32cf0d079fe 100644 (file)
@@ -985,8 +985,6 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
                state->flags = 0;
                switch (cx->type) {
                        case ACPI_STATE_C1:
-                       if (cx->entry_method != ACPI_CSTATE_FFH)
-                               state->flags |= CPUIDLE_FLAG_TIME_INVALID;
 
                        state->enter = acpi_idle_enter_c1;
                        state->enter_dead = acpi_idle_play_dead;
index 16914cc308822798b091d51a15f337b28486fe51..dc4d8960684a78f12978d56b911ead4f02a2074a 100644 (file)
@@ -1001,7 +1001,7 @@ static void acpi_free_power_resources_lists(struct acpi_device *device)
        if (device->wakeup.flags.valid)
                acpi_power_resources_list_free(&device->wakeup.resources);
 
-       if (!device->flags.power_manageable)
+       if (!device->power.flags.power_resources)
                return;
 
        for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) {
@@ -1744,10 +1744,8 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
                        device->power.flags.power_resources)
                device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
 
-       if (acpi_bus_init_power(device)) {
-               acpi_free_power_resources_lists(device);
+       if (acpi_bus_init_power(device))
                device->flags.power_manageable = 0;
-       }
 }
 
 static void acpi_bus_get_flags(struct acpi_device *device)
@@ -2371,13 +2369,18 @@ static void acpi_bus_attach(struct acpi_device *device)
        /* Skip devices that are not present. */
        if (!acpi_device_is_present(device)) {
                device->flags.visited = false;
+               device->flags.power_manageable = 0;
                return;
        }
        if (device->handler)
                goto ok;
 
        if (!device->flags.initialized) {
-               acpi_bus_update_power(device, NULL);
+               device->flags.power_manageable =
+                       device->power.states[ACPI_STATE_D0].flags.valid;
+               if (acpi_bus_init_power(device))
+                       device->flags.power_manageable = 0;
+
                device->flags.initialized = true;
        }
        device->flags.visited = false;
index 1eaadff2e198037ac9b8567517e8f37e37f09d4a..032db459370f85481ba091dc3761e727284fe0f3 100644 (file)
@@ -505,6 +505,33 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
                DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
                },
        },
+
+       {
+        .callback = video_disable_native_backlight,
+        .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
+               },
+       },
+       {
+        .callback = video_disable_native_backlight,
+        .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"),
+               },
+       },
+
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
+        .callback = video_disable_native_backlight,
+        .ident = "Dell XPS15 L521X",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
+               },
+       },
        {}
 };
 
index a3a13605a9c42d13baed5746f9f1bfb9bc30536c..5f601553b9b043fff9ac80552ab55dbc4173c714 100644 (file)
@@ -835,6 +835,7 @@ config PATA_AT32
 config PATA_AT91
        tristate "PATA support for AT91SAM9260"
        depends on ARM && SOC_AT91SAM9
+       depends on !ARCH_MULTIPLATFORM
        help
          This option enables support for IDE devices on the Atmel AT91SAM9260 SoC.
 
index 49f1e6890587e0b7f8970fe2dbdb7d879da92871..33bb06e006c9d6cbd9689b92a08df1481b12c568 100644 (file)
@@ -325,7 +325,6 @@ static const struct pci_device_id ahci_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
        { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
-       { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
        { PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
index feeb8f1e2fe845e8f63ede5363c34b6dee64803d..cbcd2081035573e9897db0afd475224c176231d3 100644 (file)
@@ -125,10 +125,11 @@ static int xgene_ahci_restart_engine(struct ata_port *ap)
  * xgene_ahci_qc_issue - Issue commands to the device
  * @qc: Command to issue
  *
- * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
- * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
- * state machine goes into the CMFatalErrorUpdate state and locks up. By
- * restarting the dma engine, it removes the controller out of lock up state.
+ * Due to Hardware errata for IDENTIFY DEVICE command and PACKET
+ * command of ATAPI protocol set, the controller cannot clear the BSY bit
+ * after receiving the PIO setup FIS. This results in the DMA state machine
+ * going into the CMFatalErrorUpdate state and locks up. By restarting the
+ * DMA engine, it removes the controller out of lock up state.
  */
 static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
 {
@@ -137,7 +138,8 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
        struct xgene_ahci_context *ctx = hpriv->plat_data;
        int rc = 0;
 
-       if (unlikely(ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA))
+       if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) ||
+           (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET)))
                xgene_ahci_restart_engine(ap);
 
        rc = ahci_qc_issue(qc);
@@ -188,7 +190,7 @@ static unsigned int xgene_ahci_read_id(struct ata_device *dev,
         *
         * Clear reserved bit 8 (DEVSLP bit) as we don't support DEVSLP
         */
-       id[ATA_ID_FEATURE_SUPP] &= ~(1 << 8);
+       id[ATA_ID_FEATURE_SUPP] &= cpu_to_le16(~(1 << 8));
 
        return 0;
 }
index 97683e45ab043be5045ae22945a5520e845cfe4f..61a9c07e0dff5b277dba35cfa135bac449f9ce84 100644 (file)
@@ -2003,7 +2003,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
 
        devslp = readl(port_mmio + PORT_DEVSLP);
        if (!(devslp & PORT_DEVSLP_DSP)) {
-               dev_err(ap->host->dev, "port does not support device sleep\n");
+               dev_info(ap->host->dev, "port does not support device sleep\n");
                return;
        }
 
index 5c84fb5c33720d5b83ba52d407656445a1dbe0ae..d1a05f9bb91f239b6b24f115b6bade4694152698 100644 (file)
@@ -4233,10 +4233,33 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
        /* devices that don't properly handle queued TRIM commands */
-       { "Micron_M500*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT???M500SSD*",      NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Micron_M550*",               NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
-       { "Crucial_CT*M550SSD*",        NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+       { "Micron_M[56]*",              NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Crucial_CT*SSD*",            NULL,   ATA_HORKAGE_NO_NCQ_TRIM, },
+
+       /*
+        * As defined, the DRAT (Deterministic Read After Trim) and RZAT
+        * (Return Zero After Trim) flags in the ATA Command Set are
+        * unreliable in the sense that they only define what happens if
+        * the device successfully executed the DSM TRIM command. TRIM
+        * is only advisory, however, and the device is free to silently
+        * ignore all or parts of the request.
+        *
+        * Whitelist drives that are known to reliably return zeroes
+        * after TRIM.
+        */
+
+       /*
+        * The intel 510 drive has buggy DRAT/RZAT. Explicitly exclude
+        * that model before whitelisting all other intel SSDs.
+        */
+       { "INTEL*SSDSC2MH*",            NULL,   0, },
+
+       { "INTEL*SSD*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "SSD*INTEL*",                 NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Samsung*SSD*",               NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "SAMSUNG*SSD*",               NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "ST[1248][0248]0[FH]*",       NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM, },
 
        /*
         * Some WD SATA-I drives spin up and down erratically when the link
@@ -4748,7 +4771,10 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
                return NULL;
 
        for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
-               tag = tag < max_queue ? tag : 0;
+               if (ap->flags & ATA_FLAG_LOWTAG)
+                       tag = i;
+               else
+                       tag = tag < max_queue ? tag : 0;
 
                /* the last tag is reserved for internal command. */
                if (tag == ATA_TAG_INTERNAL)
index 3dbec8954c867e435689c313d1b1f2f383aaea1e..8d00c2638bed8ea499fb55bcd1b8b660c80be814 100644 (file)
@@ -2389,6 +2389,7 @@ const char *ata_get_cmd_descript(u8 command)
 
        return NULL;
 }
+EXPORT_SYMBOL_GPL(ata_get_cmd_descript);
 
 /**
  *     ata_eh_link_report - report error handling to user
index e364e86e84d75b7d4ec8f18bba0eb4fc2b21a43c..6abd17a85b1369d4515302090c6eb57a2d1d088b 100644 (file)
@@ -2532,13 +2532,15 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
                rbuf[15] = lowest_aligned;
 
                if (ata_id_has_trim(args->id)) {
-                       rbuf[14] |= 0x80; /* TPE */
+                       rbuf[14] |= 0x80; /* LBPME */
 
-                       if (ata_id_has_zero_after_trim(args->id))
-                               rbuf[14] |= 0x40; /* TPRZ */
+                       if (ata_id_has_zero_after_trim(args->id) &&
+                           dev->horkage & ATA_HORKAGE_ZERO_AFTER_TRIM) {
+                               ata_dev_info(dev, "Enabling discard_zeroes_data\n");
+                               rbuf[14] |= 0x40; /* LBPRZ */
+                       }
                }
        }
-
        return 0;
 }
 
index db90aa35cb71e9456d176dcdd1214b760165cc4c..2e86e3b852666e3b57e55aafde26ba1c13f8c695 100644 (file)
@@ -1333,7 +1333,19 @@ void ata_sff_flush_pio_task(struct ata_port *ap)
        DPRINTK("ENTER\n");
 
        cancel_delayed_work_sync(&ap->sff_pio_task);
+
+       /*
+        * We wanna reset the HSM state to IDLE.  If we do so without
+        * grabbing the port lock, critical sections protected by it which
+        * expect the HSM state to stay stable may get surprised.  For
+        * example, we may set IDLE in between the time
+        * __ata_sff_port_intr() checks for HSM_ST_IDLE and before it calls
+        * ata_sff_hsm_move() causing ata_sff_hsm_move() to BUG().
+        */
+       spin_lock_irq(ap->lock);
        ap->hsm_task_state = HSM_ST_IDLE;
+       spin_unlock_irq(ap->lock);
+
        ap->sff_pio_task_link = NULL;
 
        if (ata_msg_ctl(ap))
index c7ddef89e7b02695509a5fa3076d6953435d4b86..8e8248179d20577cf83d0270e324d1a867554554 100644 (file)
@@ -797,7 +797,7 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
        if (err) {
                dev_err(host_pvt.dwc_dev, "%s: dma_request_interrupts returns"
                        " %d\n", __func__, err);
-               goto error_out;
+               return err;
        }
 
        /* Enabe DMA */
@@ -808,11 +808,6 @@ static int dma_dwc_init(struct sata_dwc_device *hsdev, int irq)
                sata_dma_regs);
 
        return 0;
-
-error_out:
-       dma_dwc_exit(hsdev);
-
-       return err;
 }
 
 static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
@@ -1662,7 +1657,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
        char *ver = (char *)&versionr;
        u8 *base = NULL;
        int err = 0;
-       int irq, rc;
+       int irq;
        struct ata_host *host;
        struct ata_port_info pi = sata_dwc_port_info[0];
        const struct ata_port_info *ppi[] = { &pi, NULL };
@@ -1725,7 +1720,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
        if (irq == NO_IRQ) {
                dev_err(&ofdev->dev, "no SATA DMA irq\n");
                err = -ENODEV;
-               goto error_out;
+               goto error_iomap;
        }
 
        /* Get physical SATA DMA register base address */
@@ -1734,14 +1729,16 @@ static int sata_dwc_probe(struct platform_device *ofdev)
                dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
                        " address\n");
                err = -ENODEV;
-               goto error_out;
+               goto error_iomap;
        }
 
        /* Save dev for later use in dev_xxx() routines */
        host_pvt.dwc_dev = &ofdev->dev;
 
        /* Initialize AHB DMAC */
-       dma_dwc_init(hsdev, irq);
+       err = dma_dwc_init(hsdev, irq);
+       if (err)
+               goto error_dma_iomap;
 
        /* Enable SATA Interrupts */
        sata_dwc_enable_interrupts(hsdev);
@@ -1759,9 +1756,8 @@ static int sata_dwc_probe(struct platform_device *ofdev)
         * device discovery process, invoking our port_start() handler &
         * error_handler() to execute a dummy Softreset EH session
         */
-       rc = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
-
-       if (rc != 0)
+       err = ata_host_activate(host, irq, sata_dwc_isr, 0, &sata_dwc_sht);
+       if (err)
                dev_err(&ofdev->dev, "failed to activate host");
 
        dev_set_drvdata(&ofdev->dev, host);
@@ -1770,7 +1766,8 @@ static int sata_dwc_probe(struct platform_device *ofdev)
 error_out:
        /* Free SATA DMA resources */
        dma_dwc_exit(hsdev);
-
+error_dma_iomap:
+       iounmap((void __iomem *)host_pvt.sata_dma_regs);
 error_iomap:
        iounmap(base);
 error_kmalloc:
@@ -1791,6 +1788,7 @@ static int sata_dwc_remove(struct platform_device *ofdev)
        /* Free SATA DMA resources */
        dma_dwc_exit(hsdev);
 
+       iounmap((void __iomem *)host_pvt.sata_dma_regs);
        iounmap(hsdev->reg_base);
        kfree(hsdev);
        kfree(host);
index d81b20ddb52736de9f9b7e15126382ebdeec2e37..ea655949023f4a6304096a33724ed2d2d8ed56c3 100644 (file)
@@ -246,7 +246,7 @@ enum {
        /* host flags */
        SIL24_COMMON_FLAGS      = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
                                  ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
-                                 ATA_FLAG_AN | ATA_FLAG_PMP,
+                                 ATA_FLAG_AN | ATA_FLAG_PMP | ATA_FLAG_LOWTAG,
        SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */
 
        IRQ_STAT_4PORTS         = 0xf,
index 6a103a35ea9b375f9328573c2fdece516690c2f1..0d8780c04a5e4d7c409b2ad1aa2d7e4c0c4f424b 100644 (file)
@@ -2088,7 +2088,7 @@ EXPORT_SYMBOL_GPL(of_genpd_del_provider);
  * Returns a valid pointer to struct generic_pm_domain on success or ERR_PTR()
  * on failure.
  */
-static struct generic_pm_domain *of_genpd_get_from_provider(
+struct generic_pm_domain *of_genpd_get_from_provider(
                                        struct of_phandle_args *genpdspec)
 {
        struct generic_pm_domain *genpd = ERR_PTR(-ENOENT);
@@ -2108,6 +2108,7 @@ static struct generic_pm_domain *of_genpd_get_from_provider(
 
        return genpd;
 }
+EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
 
 /**
  * genpd_dev_pm_detach - Detach a device from its PM domain.
index d24dd614a0bd3208c0d88fd79c35397db5be8a71..106c69359306b595e74075853ae8cc4e1465924f 100644 (file)
@@ -108,6 +108,14 @@ static LIST_HEAD(dev_opp_list);
 /* Lock to allow exclusive modification to the device and opp lists */
 static DEFINE_MUTEX(dev_opp_list_lock);
 
+#define opp_rcu_lockdep_assert()                                       \
+do {                                                                   \
+       rcu_lockdep_assert(rcu_read_lock_held() ||                      \
+                               lockdep_is_held(&dev_opp_list_lock),    \
+                          "Missing rcu_read_lock() or "                \
+                          "dev_opp_list_lock protection");             \
+} while (0)
+
 /**
  * find_device_opp() - find device_opp struct using device pointer
  * @dev:       device pointer used to lookup device OPPs
@@ -208,9 +216,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
  * This function returns the number of available opps if there are any,
  * else returns 0 if none or the corresponding error value.
  *
- * Locking: This function must be called under rcu_read_lock(). This function
- * internally references two RCU protected structures: device_opp and opp which
- * are safe as long as we are under a common RCU locked section.
+ * Locking: This function takes rcu_read_lock().
  */
 int dev_pm_opp_get_opp_count(struct device *dev)
 {
@@ -218,11 +224,14 @@ int dev_pm_opp_get_opp_count(struct device *dev)
        struct dev_pm_opp *temp_opp;
        int count = 0;
 
+       rcu_read_lock();
+
        dev_opp = find_device_opp(dev);
        if (IS_ERR(dev_opp)) {
-               int r = PTR_ERR(dev_opp);
-               dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
-               return r;
+               count = PTR_ERR(dev_opp);
+               dev_err(dev, "%s: device OPP not found (%d)\n",
+                       __func__, count);
+               goto out_unlock;
        }
 
        list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
@@ -230,6 +239,8 @@ int dev_pm_opp_get_opp_count(struct device *dev)
                        count++;
        }
 
+out_unlock:
+       rcu_read_unlock();
        return count;
 }
 EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
@@ -267,6 +278,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
        struct device_opp *dev_opp;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
+       opp_rcu_lockdep_assert();
+
        dev_opp = find_device_opp(dev);
        if (IS_ERR(dev_opp)) {
                int r = PTR_ERR(dev_opp);
@@ -313,6 +326,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
        struct device_opp *dev_opp;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
+       opp_rcu_lockdep_assert();
+
        if (!dev || !freq) {
                dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
                return ERR_PTR(-EINVAL);
@@ -361,6 +376,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
        struct device_opp *dev_opp;
        struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
 
+       opp_rcu_lockdep_assert();
+
        if (!dev || !freq) {
                dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
                return ERR_PTR(-EINVAL);
@@ -783,9 +800,15 @@ void of_free_opp_table(struct device *dev)
 
        /* Check for existing list for 'dev' */
        dev_opp = find_device_opp(dev);
-       if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev),
-                PTR_ERR(dev_opp)))
+       if (IS_ERR(dev_opp)) {
+               int error = PTR_ERR(dev_opp);
+               if (error != -ENODEV)
+                       WARN(1, "%s: dev_opp: %d\n",
+                            IS_ERR_OR_NULL(dev) ?
+                                       "Invalid device" : dev_name(dev),
+                            error);
                return;
+       }
 
        /* Hold our list modification lock here */
        mutex_lock(&dev_opp_list_lock);
index ae9f615382f6173c9ad6377c4bc4275403575fdf..aa2224aa7caa34d5854aebfb7ceaf4cebd29eccc 100644 (file)
@@ -530,7 +530,7 @@ static int null_add_dev(void)
                        goto out_cleanup_queues;
 
                nullb->q = blk_mq_init_queue(&nullb->tag_set);
-               if (!nullb->q) {
+               if (IS_ERR(nullb->q)) {
                        rv = -ENOMEM;
                        goto out_cleanup_tags;
                }
index b1d5d87973157b4c6e4a70b757519c37b3460201..d826bf3e62c8621e8572ca9eabb7951d42c33eb7 100644 (file)
@@ -106,7 +106,7 @@ struct nvme_queue {
        dma_addr_t cq_dma_addr;
        u32 __iomem *q_db;
        u16 q_depth;
-       u16 cq_vector;
+       s16 cq_vector;
        u16 sq_head;
        u16 sq_tail;
        u16 cq_head;
@@ -215,6 +215,7 @@ static void nvme_set_info(struct nvme_cmd_info *cmd, void *ctx,
        cmd->fn = handler;
        cmd->ctx = ctx;
        cmd->aborted = 0;
+       blk_mq_start_request(blk_mq_rq_from_pdu(cmd));
 }
 
 /* Special values must be less than 0x1000 */
@@ -431,8 +432,13 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
        if (unlikely(status)) {
                if (!(status & NVME_SC_DNR || blk_noretry_request(req))
                    && (jiffies - req->start_time) < req->timeout) {
+                       unsigned long flags;
+
                        blk_mq_requeue_request(req);
-                       blk_mq_kick_requeue_list(req->q);
+                       spin_lock_irqsave(req->q->queue_lock, flags);
+                       if (!blk_queue_stopped(req->q))
+                               blk_mq_kick_requeue_list(req->q);
+                       spin_unlock_irqrestore(req->q->queue_lock, flags);
                        return;
                }
                req->errors = nvme_error_status(status);
@@ -664,8 +670,6 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
                }
        }
 
-       blk_mq_start_request(req);
-
        nvme_set_info(cmd, iod, req_completion);
        spin_lock_irq(&nvmeq->q_lock);
        if (req->cmd_flags & REQ_DISCARD)
@@ -835,6 +839,7 @@ static int nvme_submit_async_admin_req(struct nvme_dev *dev)
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       req->cmd_flags |= REQ_NO_TIMEOUT;
        cmd_info = blk_mq_rq_to_pdu(req);
        nvme_set_info(cmd_info, req, async_req_completion);
 
@@ -1016,14 +1021,19 @@ static void nvme_abort_req(struct request *req)
        struct nvme_command cmd;
 
        if (!nvmeq->qid || cmd_rq->aborted) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&dev_list_lock, flags);
                if (work_busy(&dev->reset_work))
-                       return;
+                       goto out;
                list_del_init(&dev->node);
                dev_warn(&dev->pci_dev->dev,
                        "I/O %d QID %d timeout, reset controller\n",
                                                        req->tag, nvmeq->qid);
                dev->reset_workfn = nvme_reset_failed_dev;
                queue_work(nvme_workq, &dev->reset_work);
+ out:
+               spin_unlock_irqrestore(&dev_list_lock, flags);
                return;
        }
 
@@ -1064,15 +1074,22 @@ static void nvme_cancel_queue_ios(struct blk_mq_hw_ctx *hctx,
        void *ctx;
        nvme_completion_fn fn;
        struct nvme_cmd_info *cmd;
-       static struct nvme_completion cqe = {
-               .status = cpu_to_le16(NVME_SC_ABORT_REQ << 1),
-       };
+       struct nvme_completion cqe;
+
+       if (!blk_mq_request_started(req))
+               return;
 
        cmd = blk_mq_rq_to_pdu(req);
 
        if (cmd->ctx == CMD_CTX_CANCELLED)
                return;
 
+       if (blk_queue_dying(req->q))
+               cqe.status = cpu_to_le16((NVME_SC_ABORT_REQ | NVME_SC_DNR) << 1);
+       else
+               cqe.status = cpu_to_le16(NVME_SC_ABORT_REQ << 1);
+
+
        dev_warn(nvmeq->q_dmadev, "Cancelling I/O %d QID %d\n",
                                                req->tag, nvmeq->qid);
        ctx = cancel_cmd_info(cmd, &fn);
@@ -1084,17 +1101,29 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
        struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
        struct nvme_queue *nvmeq = cmd->nvmeq;
 
-       dev_warn(nvmeq->q_dmadev, "Timeout I/O %d QID %d\n", req->tag,
-                                                       nvmeq->qid);
-       if (nvmeq->dev->initialized)
-               nvme_abort_req(req);
-
        /*
         * The aborted req will be completed on receiving the abort req.
         * We enable the timer again. If hit twice, it'll cause a device reset,
         * as the device then is in a faulty state.
         */
-       return BLK_EH_RESET_TIMER;
+       int ret = BLK_EH_RESET_TIMER;
+
+       dev_warn(nvmeq->q_dmadev, "Timeout I/O %d QID %d\n", req->tag,
+                                                       nvmeq->qid);
+
+       spin_lock_irq(&nvmeq->q_lock);
+       if (!nvmeq->dev->initialized) {
+               /*
+                * Force cancelled command frees the request, which requires we
+                * return BLK_EH_NOT_HANDLED.
+                */
+               nvme_cancel_queue_ios(nvmeq->hctx, req, nvmeq, reserved);
+               ret = BLK_EH_NOT_HANDLED;
+       } else
+               nvme_abort_req(req);
+       spin_unlock_irq(&nvmeq->q_lock);
+
+       return ret;
 }
 
 static void nvme_free_queue(struct nvme_queue *nvmeq)
@@ -1131,10 +1160,16 @@ static void nvme_free_queues(struct nvme_dev *dev, int lowest)
  */
 static int nvme_suspend_queue(struct nvme_queue *nvmeq)
 {
-       int vector = nvmeq->dev->entry[nvmeq->cq_vector].vector;
+       int vector;
 
        spin_lock_irq(&nvmeq->q_lock);
+       if (nvmeq->cq_vector == -1) {
+               spin_unlock_irq(&nvmeq->q_lock);
+               return 1;
+       }
+       vector = nvmeq->dev->entry[nvmeq->cq_vector].vector;
        nvmeq->dev->online_queues--;
+       nvmeq->cq_vector = -1;
        spin_unlock_irq(&nvmeq->q_lock);
 
        irq_set_affinity_hint(vector, NULL);
@@ -1169,11 +1204,13 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid)
                adapter_delete_sq(dev, qid);
                adapter_delete_cq(dev, qid);
        }
+       if (!qid && dev->admin_q)
+               blk_mq_freeze_queue_start(dev->admin_q);
        nvme_clear_queue(nvmeq);
 }
 
 static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
-                                                       int depth, int vector)
+                                                       int depth)
 {
        struct device *dmadev = &dev->pci_dev->dev;
        struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq), GFP_KERNEL);
@@ -1199,7 +1236,6 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
        nvmeq->cq_phase = 1;
        nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride];
        nvmeq->q_depth = depth;
-       nvmeq->cq_vector = vector;
        nvmeq->qid = qid;
        dev->queue_count++;
        dev->queues[qid] = nvmeq;
@@ -1244,6 +1280,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
        struct nvme_dev *dev = nvmeq->dev;
        int result;
 
+       nvmeq->cq_vector = qid - 1;
        result = adapter_alloc_cq(dev, qid, nvmeq);
        if (result < 0)
                return result;
@@ -1355,6 +1392,14 @@ static struct blk_mq_ops nvme_mq_ops = {
        .timeout        = nvme_timeout,
 };
 
+static void nvme_dev_remove_admin(struct nvme_dev *dev)
+{
+       if (dev->admin_q && !blk_queue_dying(dev->admin_q)) {
+               blk_cleanup_queue(dev->admin_q);
+               blk_mq_free_tag_set(&dev->admin_tagset);
+       }
+}
+
 static int nvme_alloc_admin_tags(struct nvme_dev *dev)
 {
        if (!dev->admin_q) {
@@ -1370,21 +1415,20 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
                        return -ENOMEM;
 
                dev->admin_q = blk_mq_init_queue(&dev->admin_tagset);
-               if (!dev->admin_q) {
+               if (IS_ERR(dev->admin_q)) {
                        blk_mq_free_tag_set(&dev->admin_tagset);
                        return -ENOMEM;
                }
-       }
+               if (!blk_get_queue(dev->admin_q)) {
+                       nvme_dev_remove_admin(dev);
+                       return -ENODEV;
+               }
+       } else
+               blk_mq_unfreeze_queue(dev->admin_q);
 
        return 0;
 }
 
-static void nvme_free_admin_tags(struct nvme_dev *dev)
-{
-       if (dev->admin_q)
-               blk_mq_free_tag_set(&dev->admin_tagset);
-}
-
 static int nvme_configure_admin_queue(struct nvme_dev *dev)
 {
        int result;
@@ -1416,7 +1460,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
 
        nvmeq = dev->queues[0];
        if (!nvmeq) {
-               nvmeq = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH, 0);
+               nvmeq = nvme_alloc_queue(dev, 0, NVME_AQ_DEPTH);
                if (!nvmeq)
                        return -ENOMEM;
        }
@@ -1439,18 +1483,13 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
        if (result)
                goto free_nvmeq;
 
-       result = nvme_alloc_admin_tags(dev);
-       if (result)
-               goto free_nvmeq;
-
+       nvmeq->cq_vector = 0;
        result = queue_request_irq(dev, nvmeq, nvmeq->irqname);
        if (result)
-               goto free_tags;
+               goto free_nvmeq;
 
        return result;
 
- free_tags:
-       nvme_free_admin_tags(dev);
  free_nvmeq:
        nvme_free_queues(dev, 0);
        return result;
@@ -1944,7 +1983,7 @@ static void nvme_create_io_queues(struct nvme_dev *dev)
        unsigned i;
 
        for (i = dev->queue_count; i <= dev->max_qid; i++)
-               if (!nvme_alloc_queue(dev, i, dev->q_depth, i - 1))
+               if (!nvme_alloc_queue(dev, i, dev->q_depth))
                        break;
 
        for (i = dev->online_queues; i <= dev->queue_count - 1; i++)
@@ -2235,13 +2274,18 @@ static void nvme_wait_dq(struct nvme_delq_ctx *dq, struct nvme_dev *dev)
                        break;
                if (!schedule_timeout(ADMIN_TIMEOUT) ||
                                        fatal_signal_pending(current)) {
+                       /*
+                        * Disable the controller first since we can't trust it
+                        * at this point, but leave the admin queue enabled
+                        * until all queue deletion requests are flushed.
+                        * FIXME: This may take a while if there are more h/w
+                        * queues than admin tags.
+                        */
                        set_current_state(TASK_RUNNING);
-
                        nvme_disable_ctrl(dev, readq(&dev->bar->cap));
-                       nvme_disable_queue(dev, 0);
-
-                       send_sig(SIGKILL, dq->worker->task, 1);
+                       nvme_clear_queue(dev->queues[0]);
                        flush_kthread_worker(dq->worker);
+                       nvme_disable_queue(dev, 0);
                        return;
                }
        }
@@ -2318,7 +2362,6 @@ static void nvme_del_queue_start(struct kthread_work *work)
 {
        struct nvme_queue *nvmeq = container_of(work, struct nvme_queue,
                                                        cmdinfo.work);
-       allow_signal(SIGKILL);
        if (nvme_delete_sq(nvmeq))
                nvme_del_queue_end(nvmeq);
 }
@@ -2376,6 +2419,34 @@ static void nvme_dev_list_remove(struct nvme_dev *dev)
                kthread_stop(tmp);
 }
 
+static void nvme_freeze_queues(struct nvme_dev *dev)
+{
+       struct nvme_ns *ns;
+
+       list_for_each_entry(ns, &dev->namespaces, list) {
+               blk_mq_freeze_queue_start(ns->queue);
+
+               spin_lock(ns->queue->queue_lock);
+               queue_flag_set(QUEUE_FLAG_STOPPED, ns->queue);
+               spin_unlock(ns->queue->queue_lock);
+
+               blk_mq_cancel_requeue_work(ns->queue);
+               blk_mq_stop_hw_queues(ns->queue);
+       }
+}
+
+static void nvme_unfreeze_queues(struct nvme_dev *dev)
+{
+       struct nvme_ns *ns;
+
+       list_for_each_entry(ns, &dev->namespaces, list) {
+               queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue);
+               blk_mq_unfreeze_queue(ns->queue);
+               blk_mq_start_stopped_hw_queues(ns->queue, true);
+               blk_mq_kick_requeue_list(ns->queue);
+       }
+}
+
 static void nvme_dev_shutdown(struct nvme_dev *dev)
 {
        int i;
@@ -2384,8 +2455,10 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
        dev->initialized = 0;
        nvme_dev_list_remove(dev);
 
-       if (dev->bar)
+       if (dev->bar) {
+               nvme_freeze_queues(dev);
                csts = readl(&dev->bar->csts);
+       }
        if (csts & NVME_CSTS_CFS || !(csts & NVME_CSTS_RDY)) {
                for (i = dev->queue_count - 1; i >= 0; i--) {
                        struct nvme_queue *nvmeq = dev->queues[i];
@@ -2400,12 +2473,6 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
        nvme_dev_unmap(dev);
 }
 
-static void nvme_dev_remove_admin(struct nvme_dev *dev)
-{
-       if (dev->admin_q && !blk_queue_dying(dev->admin_q))
-               blk_cleanup_queue(dev->admin_q);
-}
-
 static void nvme_dev_remove(struct nvme_dev *dev)
 {
        struct nvme_ns *ns;
@@ -2413,8 +2480,10 @@ static void nvme_dev_remove(struct nvme_dev *dev)
        list_for_each_entry(ns, &dev->namespaces, list) {
                if (ns->disk->flags & GENHD_FL_UP)
                        del_gendisk(ns->disk);
-               if (!blk_queue_dying(ns->queue))
+               if (!blk_queue_dying(ns->queue)) {
+                       blk_mq_abort_requeue_list(ns->queue);
                        blk_cleanup_queue(ns->queue);
+               }
        }
 }
 
@@ -2495,6 +2564,7 @@ static void nvme_free_dev(struct kref *kref)
        nvme_free_namespaces(dev);
        nvme_release_instance(dev);
        blk_mq_free_tag_set(&dev->tagset);
+       blk_put_queue(dev->admin_q);
        kfree(dev->queues);
        kfree(dev->entry);
        kfree(dev);
@@ -2591,15 +2661,20 @@ static int nvme_dev_start(struct nvme_dev *dev)
        }
 
        nvme_init_queue(dev->queues[0], 0);
+       result = nvme_alloc_admin_tags(dev);
+       if (result)
+               goto disable;
 
        result = nvme_setup_io_queues(dev);
        if (result)
-               goto disable;
+               goto free_tags;
 
        nvme_set_irq_hints(dev);
 
        return result;
 
+ free_tags:
+       nvme_dev_remove_admin(dev);
  disable:
        nvme_disable_queue(dev, 0);
        nvme_dev_list_remove(dev);
@@ -2639,6 +2714,9 @@ static int nvme_dev_resume(struct nvme_dev *dev)
                dev->reset_workfn = nvme_remove_disks;
                queue_work(nvme_workq, &dev->reset_work);
                spin_unlock(&dev_list_lock);
+       } else {
+               nvme_unfreeze_queues(dev);
+               nvme_set_irq_hints(dev);
        }
        dev->initialized = 1;
        return 0;
@@ -2776,11 +2854,10 @@ static void nvme_remove(struct pci_dev *pdev)
        pci_set_drvdata(pdev, NULL);
        flush_work(&dev->reset_work);
        misc_deregister(&dev->miscdev);
-       nvme_dev_remove(dev);
        nvme_dev_shutdown(dev);
+       nvme_dev_remove(dev);
        nvme_dev_remove_admin(dev);
        nvme_free_queues(dev, 0);
-       nvme_free_admin_tags(dev);
        nvme_release_prp_pools(dev);
        kref_put(&dev->kref, nvme_free_dev);
 }
index 3ec85dfce12496dd64a8ad2c37984ad61f489e25..8a86b62466f7ce72b54853b283e03fd495df8083 100644 (file)
@@ -2098,32 +2098,26 @@ static void rbd_dev_parent_put(struct rbd_device *rbd_dev)
  * If an image has a non-zero parent overlap, get a reference to its
  * parent.
  *
- * We must get the reference before checking for the overlap to
- * coordinate properly with zeroing the parent overlap in
- * rbd_dev_v2_parent_info() when an image gets flattened.  We
- * drop it again if there is no overlap.
- *
  * Returns true if the rbd device has a parent with a non-zero
  * overlap and a reference for it was successfully taken, or
  * false otherwise.
  */
 static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
 {
-       int counter;
+       int counter = 0;
 
        if (!rbd_dev->parent_spec)
                return false;
 
-       counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
-       if (counter > 0 && rbd_dev->parent_overlap)
-               return true;
-
-       /* Image was flattened, but parent is not yet torn down */
+       down_read(&rbd_dev->header_rwsem);
+       if (rbd_dev->parent_overlap)
+               counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
+       up_read(&rbd_dev->header_rwsem);
 
        if (counter < 0)
                rbd_warn(rbd_dev, "parent reference overflow");
 
-       return false;
+       return counter > 0;
 }
 
 /*
@@ -4239,7 +4233,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
                 */
                if (rbd_dev->parent_overlap) {
                        rbd_dev->parent_overlap = 0;
-                       smp_mb();
                        rbd_dev_parent_put(rbd_dev);
                        pr_info("%s: clone image has been flattened\n",
                                rbd_dev->disk->disk_name);
@@ -4285,7 +4278,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
         * treat it specially.
         */
        rbd_dev->parent_overlap = overlap;
-       smp_mb();
        if (!overlap) {
 
                /* A null parent_spec indicates it's the initial probe */
@@ -5114,10 +5106,7 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
 {
        struct rbd_image_header *header;
 
-       /* Drop parent reference unless it's already been done (or none) */
-
-       if (rbd_dev->parent_overlap)
-               rbd_dev_parent_put(rbd_dev);
+       rbd_dev_parent_put(rbd_dev);
 
        /* Free dynamic fields from the header, then zero it out */
 
index 7ef7c098708fc4e482181724d574555bbb9db6d7..cdfbd21e35975178fa0c4cece78a354ef1d53007 100644 (file)
@@ -638,7 +638,7 @@ static int virtblk_probe(struct virtio_device *vdev)
                goto out_put_disk;
 
        q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
-       if (!q) {
+       if (IS_ERR(q)) {
                err = -ENOMEM;
                goto out_free_tags;
        }
index 860da40b78effb96b16a779f84f9ea21d05aba95..0ce5e2d65a06b5d4e6ecbdf3390554f08751d9e2 100644 (file)
@@ -1312,6 +1312,9 @@ static int cci_probe(void)
        if (!np)
                return -ENODEV;
 
+       if (!of_device_is_available(np))
+               return -ENODEV;
+
        cci_config = of_match_node(arm_cci_matches, np)->data;
        if (!cci_config)
                return -ENODEV;
index eb7682dc123be4ef22d3b0a05e305b5aa7b11045..81bf297f1034abd697135cea8c5c1db3c932cbff 100644 (file)
@@ -210,12 +210,25 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
 }
 
 /* Checks whether the given window number is available */
+
+/* On Armada XP, 375 and 38x the MBus window 13 has the remap
+ * capability, like windows 0 to 7. However, the mvebu-mbus driver
+ * isn't currently taking into account this special case, which means
+ * that when window 13 is actually used, the remap registers are left
+ * to 0, making the device using this MBus window unavailable. The
+ * quick fix for stable is to not use window 13. A follow up patch
+ * will correctly handle this window.
+*/
 static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
                                     const int win)
 {
        void __iomem *addr = mbus->mbuswins_base +
                mbus->soc->win_cfg_offset(win);
        u32 ctrl = readl(addr + WIN_CTRL_OFF);
+
+       if (win == 13)
+               return false;
+
        return !(ctrl & WIN_CTRL_ENABLE);
 }
 
index 19db036676505519fb19538299afe2f5c84dd42a..dcbbb4ea3cc1d7040a847799fad2415e44a24e08 100644 (file)
@@ -417,6 +417,6 @@ static void __exit agp_ali_cleanup(void)
 module_init(agp_ali_init);
 module_exit(agp_ali_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones");
 MODULE_LICENSE("GPL and additional rights");
 
index 3b47ed0310e1fcbb73eda184cb810c1b3ea2889b..0ef350010766355c933ebe7e48ce41a78656b0ac 100644 (file)
@@ -813,6 +813,6 @@ static void __exit agp_amd64_cleanup(void)
 module_init(agp_amd64_mod_init);
 module_exit(agp_amd64_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>, Andi Kleen");
+MODULE_AUTHOR("Dave Jones, Andi Kleen");
 module_param(agp_try_unsupported, bool, 0);
 MODULE_LICENSE("GPL");
index 18a7a6baa304eadfc3968a640f97ac3da590b106..75a9786a77e6307711a74bcde8f4dd7fee8fcae0 100644 (file)
@@ -579,6 +579,6 @@ static void __exit agp_ati_cleanup(void)
 module_init(agp_ati_init);
 module_exit(agp_ati_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones");
 MODULE_LICENSE("GPL and additional rights");
 
index 317c28ce8328bb310c892c8bab4aca60cbbbc4f5..38ffb281df97c71eee3dc8980a98e19df3ca24d3 100644 (file)
@@ -356,7 +356,7 @@ static __init int agp_setup(char *s)
 __setup("agp=", agp_setup);
 #endif
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones, Jeff Hartmann");
 MODULE_DESCRIPTION("AGP GART driver");
 MODULE_LICENSE("GPL and additional rights");
 MODULE_ALIAS_MISCDEV(AGPGART_MINOR);
index f9b9ca5d31b7946c3b1407ef692db1c2c149c628..0a21daed5b6251edd8136bc014d073ab734a2a0a 100644 (file)
@@ -920,5 +920,5 @@ static void __exit agp_intel_cleanup(void)
 module_init(agp_intel_init);
 module_exit(agp_intel_cleanup);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones, Various @Intel");
 MODULE_LICENSE("GPL and additional rights");
index f3334829e55a3e6ac393a348c6da0e7aef159709..92aa43fa8d70205e621cc3f3fe03e8bbcd94a42f 100644 (file)
@@ -1438,5 +1438,5 @@ void intel_gmch_remove(void)
 }
 EXPORT_SYMBOL(intel_gmch_remove);
 
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones, Various @Intel");
 MODULE_LICENSE("GPL and additional rights");
index a1861b75eb31a9fe433e32105ef623092741052e..6c8d39cb566e32ea4ac14c818f3bd16962823097 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Nvidia AGPGART routines.
  * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up
- * to work in 2.5 by Dave Jones <davej@redhat.com>
+ * to work in 2.5 by Dave Jones.
  */
 
 #include <linux/module.h>
index 228f20cddc056244711805b20c44d168a4d94493..a4961d35e94046de34896c492e032b9c5e72c1ae 100644 (file)
@@ -595,4 +595,4 @@ module_init(agp_via_init);
 module_exit(agp_via_cleanup);
 
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
+MODULE_AUTHOR("Dave Jones");
index 5fa83f751378fb56ecc7da11a16d2c8386fb6862..6b65fa4e0c5586895df2b26ee499c9e5ad4d8b2c 100644 (file)
@@ -199,18 +199,6 @@ struct bmc_device {
        int                    guid_set;
        char                   name[16];
        struct kref            usecount;
-
-       /* bmc device attributes */
-       struct device_attribute device_id_attr;
-       struct device_attribute provides_dev_sdrs_attr;
-       struct device_attribute revision_attr;
-       struct device_attribute firmware_rev_attr;
-       struct device_attribute version_attr;
-       struct device_attribute add_dev_support_attr;
-       struct device_attribute manufacturer_id_attr;
-       struct device_attribute product_id_attr;
-       struct device_attribute guid_attr;
-       struct device_attribute aux_firmware_rev_attr;
 };
 #define to_bmc_device(x) container_of((x), struct bmc_device, pdev.dev)
 
@@ -2252,7 +2240,7 @@ static ssize_t device_id_show(struct device *dev,
 
        return snprintf(buf, 10, "%u\n", bmc->id.device_id);
 }
-DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL);
+static DEVICE_ATTR(device_id, S_IRUGO, device_id_show, NULL);
 
 static ssize_t provides_device_sdrs_show(struct device *dev,
                                         struct device_attribute *attr,
@@ -2263,7 +2251,8 @@ static ssize_t provides_device_sdrs_show(struct device *dev,
        return snprintf(buf, 10, "%u\n",
                        (bmc->id.device_revision & 0x80) >> 7);
 }
-DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show, NULL);
+static DEVICE_ATTR(provides_device_sdrs, S_IRUGO, provides_device_sdrs_show,
+                  NULL);
 
 static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
                             char *buf)
@@ -2273,7 +2262,7 @@ static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
        return snprintf(buf, 20, "%u\n",
                        bmc->id.device_revision & 0x0F);
 }
-DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL);
+static DEVICE_ATTR(revision, S_IRUGO, revision_show, NULL);
 
 static ssize_t firmware_revision_show(struct device *dev,
                                      struct device_attribute *attr,
@@ -2284,7 +2273,7 @@ static ssize_t firmware_revision_show(struct device *dev,
        return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
                        bmc->id.firmware_revision_2);
 }
-DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL);
+static DEVICE_ATTR(firmware_revision, S_IRUGO, firmware_revision_show, NULL);
 
 static ssize_t ipmi_version_show(struct device *dev,
                                 struct device_attribute *attr,
@@ -2296,7 +2285,7 @@ static ssize_t ipmi_version_show(struct device *dev,
                        ipmi_version_major(&bmc->id),
                        ipmi_version_minor(&bmc->id));
 }
-DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL);
+static DEVICE_ATTR(ipmi_version, S_IRUGO, ipmi_version_show, NULL);
 
 static ssize_t add_dev_support_show(struct device *dev,
                                    struct device_attribute *attr,
@@ -2307,7 +2296,8 @@ static ssize_t add_dev_support_show(struct device *dev,
        return snprintf(buf, 10, "0x%02x\n",
                        bmc->id.additional_device_support);
 }
-DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show, NULL);
+static DEVICE_ATTR(additional_device_support, S_IRUGO, add_dev_support_show,
+                  NULL);
 
 static ssize_t manufacturer_id_show(struct device *dev,
                                    struct device_attribute *attr,
@@ -2317,7 +2307,7 @@ static ssize_t manufacturer_id_show(struct device *dev,
 
        return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
 }
-DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL);
+static DEVICE_ATTR(manufacturer_id, S_IRUGO, manufacturer_id_show, NULL);
 
 static ssize_t product_id_show(struct device *dev,
                               struct device_attribute *attr,
@@ -2327,7 +2317,7 @@ static ssize_t product_id_show(struct device *dev,
 
        return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
 }
-DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, product_id_show, NULL);
 
 static ssize_t aux_firmware_rev_show(struct device *dev,
                                     struct device_attribute *attr,
@@ -2341,7 +2331,7 @@ static ssize_t aux_firmware_rev_show(struct device *dev,
                        bmc->id.aux_firmware_revision[1],
                        bmc->id.aux_firmware_revision[0]);
 }
-DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL);
+static DEVICE_ATTR(aux_firmware_revision, S_IRUGO, aux_firmware_rev_show, NULL);
 
 static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
                         char *buf)
@@ -2352,7 +2342,7 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
                        (long long) bmc->guid[0],
                        (long long) bmc->guid[8]);
 }
-DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL);
+static DEVICE_ATTR(guid, S_IRUGO, guid_show, NULL);
 
 static struct attribute *bmc_dev_attrs[] = {
        &dev_attr_device_id.attr,
@@ -2392,10 +2382,10 @@ cleanup_bmc_device(struct kref *ref)
 
        if (bmc->id.aux_firmware_revision_set)
                device_remove_file(&bmc->pdev.dev,
-                                  &bmc->aux_firmware_rev_attr);
+                                  &dev_attr_aux_firmware_revision);
        if (bmc->guid_set)
                device_remove_file(&bmc->pdev.dev,
-                                  &bmc->guid_attr);
+                                  &dev_attr_guid);
 
        platform_device_unregister(&bmc->pdev);
 }
@@ -2422,16 +2412,14 @@ static int create_bmc_files(struct bmc_device *bmc)
        int err;
 
        if (bmc->id.aux_firmware_revision_set) {
-               bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision";
                err = device_create_file(&bmc->pdev.dev,
-                                  &bmc->aux_firmware_rev_attr);
+                                        &dev_attr_aux_firmware_revision);
                if (err)
                        goto out;
        }
        if (bmc->guid_set) {
-               bmc->guid_attr.attr.name = "guid";
                err = device_create_file(&bmc->pdev.dev,
-                                  &bmc->guid_attr);
+                                        &dev_attr_guid);
                if (err)
                        goto out_aux_firm;
        }
@@ -2441,7 +2429,7 @@ static int create_bmc_files(struct bmc_device *bmc)
 out_aux_firm:
        if (bmc->id.aux_firmware_revision_set)
                device_remove_file(&bmc->pdev.dev,
-                                  &bmc->aux_firmware_rev_attr);
+                                  &dev_attr_aux_firmware_revision);
 out:
        return err;
 }
index e178ac27e73c6de46ef48c2d94464cd64b4ca011..982b96323f823b8402ede2ceec7c0cb85c042ec4 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/dmi.h>
 #include <linux/kthread.h>
 #include <linux/acpi.h>
+#include <linux/ctype.h>
 
 #define PFX "ipmi_ssif: "
 #define DEVICE_NAME "ipmi_ssif"
@@ -968,7 +969,8 @@ static void sender(void                *send_info,
 
                do_gettimeofday(&t);
                pr_info("**Enqueue %02x %02x: %ld.%6.6ld\n",
-                      msg->data[0], msg->data[1], t.tv_sec, t.tv_usec);
+                      msg->data[0], msg->data[1],
+                      (long) t.tv_sec, (long) t.tv_usec);
        }
 }
 
index 32f7c1b36204018d0ce151601c6ca5ef6f2cf75f..2f13bd5246b5563ec399058029fcd0740c58c3d2 100644 (file)
@@ -70,6 +70,7 @@ struct clk_sam9x5_slow {
 
 #define to_clk_sam9x5_slow(hw) container_of(hw, struct clk_sam9x5_slow, hw)
 
+static struct clk *slow_clk;
 
 static int clk_slow_osc_prepare(struct clk_hw *hw)
 {
@@ -357,6 +358,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr,
        clk = clk_register(NULL, &slowck->hw);
        if (IS_ERR(clk))
                kfree(slowck);
+       else
+               slow_clk = clk;
 
        return clk;
 }
@@ -433,6 +436,8 @@ at91_clk_register_sam9260_slow(struct at91_pmc *pmc,
        clk = clk_register(NULL, &slowck->hw);
        if (IS_ERR(clk))
                kfree(slowck);
+       else
+               slow_clk = clk;
 
        return clk;
 }
@@ -465,3 +470,25 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
 
        of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
+
+/*
+ * FIXME: All slow clk users are not properly claiming it (get + prepare +
+ * enable) before using it.
+ * If all users properly claiming this clock decide that they don't need it
+ * anymore (or are removed), it is disabled while faulty users are still
+ * requiring it, and the system hangs.
+ * Prevent this clock from being disabled until all users are properly
+ * requesting it.
+ * Once this is done we should remove this function and the slow_clk variable.
+ */
+static int __init of_at91_clk_slow_retain(void)
+{
+       if (!slow_clk)
+               return 0;
+
+       __clk_get(slow_clk);
+       clk_prepare_enable(slow_clk);
+
+       return 0;
+}
+arch_initcall(of_at91_clk_slow_retain);
index 21784e4eb3f004af06c1b980938ab4ced9bc2894..440ef81ab15c4ba8d9f70947db7e5a0d144a97a4 100644 (file)
@@ -285,7 +285,6 @@ static const struct berlin2_gate_data bg2q_gates[] __initconst = {
        { "pbridge",    "perif",        15, CLK_IGNORE_UNUSED },
        { "sdio",       "perif",        16, CLK_IGNORE_UNUSED },
        { "nfc",        "perif",        18 },
-       { "smemc",      "perif",        19 },
        { "pcie",       "perif",        22 },
 };
 
index b6e6c85507a5a7706c8c69f2c6611d908ade8611..0a47d6f49cd6f347eca03eadf283722c737c7fb2 100644 (file)
@@ -291,7 +291,7 @@ static const struct of_device_id ppc_clk_ids[] __initconst = {
        {}
 };
 
-static struct platform_driver ppc_corenet_clk_driver __initdata = {
+static struct platform_driver ppc_corenet_clk_driver = {
        .driver = {
                .name = "ppc_corenet_clock",
                .of_match_table = ppc_clk_ids,
index f4963b7d4e17d41b6a6553854c5250a7e90bfdef..d48ac71c6c8b173793a31e95ebaa93749e883a76 100644 (file)
@@ -1366,7 +1366,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
                new_rate = clk->ops->determine_rate(clk->hw, rate,
                                                    &best_parent_rate,
                                                    &parent_hw);
-               parent = parent_hw->clk;
+               parent = parent_hw ? parent_hw->clk : NULL;
        } else if (clk->ops->round_rate) {
                new_rate = clk->ops->round_rate(clk->hw, rate,
                                                &best_parent_rate);
index 75c8c45ef72849358e4b7bf2c3bbff7927761ae0..8539c4fd34cc37bd28810b93d6ffb815b0bd48d6 100644 (file)
@@ -124,10 +124,11 @@ static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk,
 {
        const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data;
        unsigned long alt_prate, alt_div;
+       unsigned long flags;
 
        alt_prate = clk_get_rate(cpuclk->alt_parent);
 
-       spin_lock(cpuclk->lock);
+       spin_lock_irqsave(cpuclk->lock, flags);
 
        /*
         * If the old parent clock speed is less than the clock speed
@@ -164,7 +165,7 @@ static int rockchip_cpuclk_pre_rate_change(struct rockchip_cpuclk *cpuclk,
                        cpuclk->reg_base + reg_data->core_reg);
        }
 
-       spin_unlock(cpuclk->lock);
+       spin_unlock_irqrestore(cpuclk->lock, flags);
        return 0;
 }
 
@@ -173,6 +174,7 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk,
 {
        const struct rockchip_cpuclk_reg_data *reg_data = cpuclk->reg_data;
        const struct rockchip_cpuclk_rate_table *rate;
+       unsigned long flags;
 
        rate = rockchip_get_cpuclk_settings(cpuclk, ndata->new_rate);
        if (!rate) {
@@ -181,7 +183,7 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk,
                return -EINVAL;
        }
 
-       spin_lock(cpuclk->lock);
+       spin_lock_irqsave(cpuclk->lock, flags);
 
        if (ndata->old_rate < ndata->new_rate)
                rockchip_cpuclk_set_dividers(cpuclk, rate);
@@ -201,7 +203,7 @@ static int rockchip_cpuclk_post_rate_change(struct rockchip_cpuclk *cpuclk,
        if (ndata->old_rate > ndata->new_rate)
                rockchip_cpuclk_set_dividers(cpuclk, rate);
 
-       spin_unlock(cpuclk->lock);
+       spin_unlock_irqrestore(cpuclk->lock, flags);
        return 0;
 }
 
index c54078960847c91f6f499ecb8f26924338bb2ab4..7eb684c50d42ce9f0d06ffa4de1ecef4270808b7 100644 (file)
@@ -210,6 +210,17 @@ PNAME(mux_sclk_hsadc_p)            = { "hsadc_src", "hsadc_frac", "ext_hsadc" };
 PNAME(mux_mac_p)               = { "gpll", "dpll" };
 PNAME(mux_sclk_macref_p)       = { "mac_src", "ext_rmii" };
 
+static struct rockchip_pll_clock rk3066_pll_clks[] __initdata = {
+       [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
+                    RK2928_MODE_CON, 0, 5, 0, rk3188_pll_rates),
+       [dpll] = PLL(pll_rk3066, PLL_DPLL, "dpll", mux_pll_p, 0, RK2928_PLL_CON(4),
+                    RK2928_MODE_CON, 4, 4, 0, NULL),
+       [cpll] = PLL(pll_rk3066, PLL_CPLL, "cpll", mux_pll_p, 0, RK2928_PLL_CON(8),
+                    RK2928_MODE_CON, 8, 6, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates),
+       [gpll] = PLL(pll_rk3066, PLL_GPLL, "gpll", mux_pll_p, 0, RK2928_PLL_CON(12),
+                    RK2928_MODE_CON, 12, 7, ROCKCHIP_PLL_SYNC_RATE, rk3188_pll_rates),
+};
+
 static struct rockchip_pll_clock rk3188_pll_clks[] __initdata = {
        [apll] = PLL(pll_rk3066, PLL_APLL, "apll", mux_pll_p, 0, RK2928_PLL_CON(0),
                     RK2928_MODE_CON, 0, 6, 0, rk3188_pll_rates),
@@ -427,11 +438,11 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = {
        /* hclk_peri gates */
        GATE(0, "hclk_peri_axi_matrix", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 0, GFLAGS),
        GATE(0, "hclk_peri_ahb_arbi", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 6, GFLAGS),
-       GATE(0, "hclk_emem_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 7, GFLAGS),
+       GATE(0, "hclk_emem_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 7, GFLAGS),
        GATE(HCLK_EMAC, "hclk_emac", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 0, GFLAGS),
        GATE(HCLK_NANDC0, "hclk_nandc0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 9, GFLAGS),
-       GATE(0, "hclk_usb_peri", "hclk_peri", 0, RK2928_CLKGATE_CON(4), 5, GFLAGS),
-       GATE(HCLK_OTG0, "hclk_usbotg0", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 13, GFLAGS),
+       GATE(0, "hclk_usb_peri", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(4), 5, GFLAGS),
+       GATE(HCLK_OTG0, "hclk_usbotg0", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 13, GFLAGS),
        GATE(HCLK_HSADC, "hclk_hsadc", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 5, GFLAGS),
        GATE(HCLK_PIDF, "hclk_pidfilter", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 6, GFLAGS),
        GATE(HCLK_SDMMC, "hclk_sdmmc", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 10, GFLAGS),
@@ -592,7 +603,8 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = {
        GATE(0, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS),
        GATE(0, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
 
-       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", 0, RK2928_CLKGATE_CON(5), 14, GFLAGS),
+       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED,
+                       RK2928_CLKGATE_CON(5), 14, GFLAGS),
 
        GATE(0, "aclk_cif1", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 7, GFLAGS),
 
@@ -680,7 +692,8 @@ static struct rockchip_clk_branch rk3188_clk_branches[] __initdata = {
        GATE(0, "hclk_imem0", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS),
        GATE(0, "hclk_imem1", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 15, GFLAGS),
 
-       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS),
+       GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED,
+                       RK2928_CLKGATE_CON(7), 3, GFLAGS),
        GATE(HCLK_HSIC, "hclk_hsic", "hclk_peri", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS),
 
        GATE(PCLK_TIMER3, "pclk_timer3", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 9, GFLAGS),
@@ -735,8 +748,8 @@ static void __init rk3188_common_clk_init(struct device_node *np)
 static void __init rk3066a_clk_init(struct device_node *np)
 {
        rk3188_common_clk_init(np);
-       rockchip_clk_register_plls(rk3188_pll_clks,
-                                  ARRAY_SIZE(rk3188_pll_clks),
+       rockchip_clk_register_plls(rk3066_pll_clks,
+                                  ARRAY_SIZE(rk3066_pll_clks),
                                   RK3066_GRF_SOC_STATUS);
        rockchip_clk_register_branches(rk3066a_clk_branches,
                                  ARRAY_SIZE(rk3066a_clk_branches));
index ac6be7c0132d1e27cfad2f95169212b70f3d31d2..11194b8329fe5a639a6241ed0718888f985df854 100644 (file)
@@ -145,20 +145,20 @@ struct rockchip_pll_rate_table rk3288_pll_rates[] = {
        }
 
 static struct rockchip_cpuclk_rate_table rk3288_cpuclk_rates[] __initdata = {
-       RK3288_CPUCLK_RATE(1800000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1704000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1608000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1512000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1416000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1200000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE(1008000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 816000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 696000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 600000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 408000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 312000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 216000000, 2, 4, 2, 4, 4),
-       RK3288_CPUCLK_RATE( 126000000, 2, 4, 2, 4, 4),
+       RK3288_CPUCLK_RATE(1800000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1704000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1608000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1512000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1416000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1200000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE(1008000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 816000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 696000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 600000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 408000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 312000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 216000000, 1, 3, 1, 3, 3),
+       RK3288_CPUCLK_RATE( 126000000, 1, 3, 1, 3, 3),
 };
 
 static const struct rockchip_cpuclk_reg_data rk3288_cpuclk_data = {
index 6a79fc4f900c4b56b4bd351cf050aa5c2b67175e..095c1774592c918d4684995a12f74b1090f17c3f 100644 (file)
@@ -462,7 +462,7 @@ static void __init arch_counter_register(unsigned type)
 
        /* Register the CP15 based counter if we have one */
        if (type & ARCH_CP15_TIMER) {
-               if (arch_timer_use_virtual)
+               if (IS_ENABLED(CONFIG_ARM64) || arch_timer_use_virtual)
                        arch_timer_read_counter = arch_counter_get_cntvct;
                else
                        arch_timer_read_counter = arch_counter_get_cntpct;
index 0595dc6c453e6ee4a97cfb4dd30865f76c351366..f1e33d08dd834a27269062a0b42d8265fb39960c 100644 (file)
@@ -68,9 +68,8 @@ static void kona_timer_disable_and_clear(void __iomem *base)
 }
 
 static void
-kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw)
+kona_timer_get_counter(void __iomem *timer_base, uint32_t *msw, uint32_t *lsw)
 {
-       void __iomem *base = IOMEM(timer_base);
        int loop_limit = 4;
 
        /*
@@ -86,9 +85,9 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw)
         */
 
        while (--loop_limit) {
-               *msw = readl(base + KONA_GPTIMER_STCHI_OFFSET);
-               *lsw = readl(base + KONA_GPTIMER_STCLO_OFFSET);
-               if (*msw == readl(base + KONA_GPTIMER_STCHI_OFFSET))
+               *msw = readl(timer_base + KONA_GPTIMER_STCHI_OFFSET);
+               *lsw = readl(timer_base + KONA_GPTIMER_STCLO_OFFSET);
+               if (*msw == readl(timer_base + KONA_GPTIMER_STCHI_OFFSET))
                        break;
        }
        if (!loop_limit) {
index 9403061a2acc78397dd686208642c71012b328e7..83564c9cfdbe3b18dfb07a3799b73b991ffe00c7 100644 (file)
@@ -97,8 +97,8 @@ static void exynos4_mct_write(unsigned int value, unsigned long offset)
        writel_relaxed(value, reg_base + offset);
 
        if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) {
-               stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET;
-               switch (offset & EXYNOS4_MCT_L_MASK) {
+               stat_addr = (offset & EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET;
+               switch (offset & ~EXYNOS4_MCT_L_MASK) {
                case MCT_L_TCON_OFFSET:
                        mask = 1 << 3;          /* L_TCON write status */
                        break;
index 0f665b8f2461f00ee58bc38918c2b684b04e16d3..f150ca82bfaf106a7ef2c5a40dd12a1e098e39f0 100644 (file)
@@ -428,7 +428,7 @@ static void sh_tmu_register_clockevent(struct sh_tmu_channel *ch,
        ced->features = CLOCK_EVT_FEAT_PERIODIC;
        ced->features |= CLOCK_EVT_FEAT_ONESHOT;
        ced->rating = 200;
-       ced->cpumask = cpumask_of(0);
+       ced->cpumask = cpu_possible_mask;
        ced->set_next_event = sh_tmu_clock_event_next;
        ced->set_mode = sh_tmu_clock_event_mode;
        ced->suspend = sh_tmu_clock_event_suspend;
index f56147a1daed54a2e7fe4be9c983e46db95ecfc6..fde97d6e31d6d9749698aaf91bfae821f1a72f9f 100644 (file)
@@ -211,6 +211,17 @@ static int cpufreq_init(struct cpufreq_policy *policy)
        /* OPPs might be populated at runtime, don't check for error here */
        of_init_opp_table(cpu_dev);
 
+       /*
+        * But we need OPP table to function so if it is not there let's
+        * give platform code chance to provide it for us.
+        */
+       ret = dev_pm_opp_get_opp_count(cpu_dev);
+       if (ret <= 0) {
+               pr_debug("OPP table is not ready, deferring probe\n");
+               ret = -EPROBE_DEFER;
+               goto out_free_opp;
+       }
+
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                ret = -ENOMEM;
index a09a29c312a9cbeef8cb43a2862c07f13c78a24e..46bed4f81cde882e8f1d3b3dbd1b9418b3de2ee5 100644 (file)
@@ -2028,6 +2028,12 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
        /* Don't start any governor operations if we are entering suspend */
        if (cpufreq_suspended)
                return 0;
+       /*
+        * Governor might not be initiated here if ACPI _PPC changed
+        * notification happened, so check it.
+        */
+       if (!policy->governor)
+               return -EINVAL;
 
        if (policy->governor->max_transition_latency &&
            policy->cpuinfo.transition_latency >
index 37263d9a105127079cd71baed298467495000dd6..401c0106ed345eda469a590aa345f88d8ff59eca 100644 (file)
@@ -79,12 +79,7 @@ static int ladder_select_state(struct cpuidle_driver *drv,
 
        last_state = &ldev->states[last_idx];
 
-       if (!(drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_INVALID)) {
-               last_residency = cpuidle_get_last_residency(dev) - \
-                                        drv->states[last_idx].exit_latency;
-       }
-       else
-               last_residency = last_state->threshold.promotion_time + 1;
+       last_residency = cpuidle_get_last_residency(dev) - drv->states[last_idx].exit_latency;
 
        /* consider promotion */
        if (last_idx < drv->state_count - 1 &&
index 659d7b0c9ebfd1e78348d539f497112c36f2cdc5..40580794e23dc00f4d086a696c803ed35b4c0f25 100644 (file)
@@ -396,8 +396,8 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
         * power state and occurrence of the wakeup event.
         *
         * If the entered idle state didn't support residency measurements,
-        * we are basically lost in the dark how much time passed.
-        * As a compromise, assume we slept for the whole expected time.
+        * we use them anyway if they are short, and if long,
+        * truncate to the whole expected time.
         *
         * Any measured amount of time will include the exit latency.
         * Since we are interested in when the wakeup begun, not when it
@@ -405,22 +405,17 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
         * the measured amount of time is less than the exit latency,
         * assume the state was never reached and the exit latency is 0.
         */
-       if (unlikely(target->flags & CPUIDLE_FLAG_TIME_INVALID)) {
-               /* Use timer value as is */
-               measured_us = data->next_timer_us;
 
-       } else {
-               /* Use measured value */
-               measured_us = cpuidle_get_last_residency(dev);
+       /* measured value */
+       measured_us = cpuidle_get_last_residency(dev);
 
-               /* Deduct exit latency */
-               if (measured_us > target->exit_latency)
-                       measured_us -= target->exit_latency;
+       /* Deduct exit latency */
+       if (measured_us > target->exit_latency)
+               measured_us -= target->exit_latency;
 
-               /* Make sure our coefficients do not exceed unity */
-               if (measured_us > data->next_timer_us)
-                       measured_us = data->next_timer_us;
-       }
+       /* Make sure our coefficients do not exceed unity */
+       if (measured_us > data->next_timer_us)
+               measured_us = data->next_timer_us;
 
        /* Update our correction ratio */
        new_factor = data->correction_factor[data->bucket];
index 380478562b7d3187d42a64c221caf5714e6e59ec..5c062548957c3183fba608e13354d204c0a4b40c 100644 (file)
@@ -1505,7 +1505,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        dw->regs = chip->regs;
        chip->dw = dw;
 
-       pm_runtime_enable(chip->dev);
        pm_runtime_get_sync(chip->dev);
 
        dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
@@ -1703,7 +1702,6 @@ int dw_dma_remove(struct dw_dma_chip *chip)
        }
 
        pm_runtime_put_sync_suspend(chip->dev);
-       pm_runtime_disable(chip->dev);
        return 0;
 }
 EXPORT_SYMBOL_GPL(dw_dma_remove);
index a630161473a4fa69c2586a257949d7f0956d4db7..32ea1aca7a0ea27dc28ddd58c20281f482f53c45 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/clk.h>
+#include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
@@ -185,6 +186,8 @@ static int dw_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       pm_runtime_enable(&pdev->dev);
+
        err = dw_dma_probe(chip, pdata);
        if (err)
                goto err_dw_dma_probe;
@@ -205,6 +208,7 @@ static int dw_probe(struct platform_device *pdev)
        return 0;
 
 err_dw_dma_probe:
+       pm_runtime_disable(&pdev->dev);
        clk_disable_unprepare(chip->clk);
        return err;
 }
@@ -217,6 +221,7 @@ static int dw_remove(struct platform_device *pdev)
                of_dma_controller_free(pdev->dev.of_node);
 
        dw_dma_remove(chip);
+       pm_runtime_disable(&pdev->dev);
        clk_disable_unprepare(chip->clk);
 
        return 0;
index 55d4803d71b0db4c3a27b909bfeb20d4d3b668ed..3d9e08f7e823edf13aa719460ecc13f8327c8b31 100644 (file)
@@ -272,7 +272,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
        for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
                if (pending & BIT(gpio)) {
                        virq = irq_find_mapping(cg->chip.irqdomain, gpio);
-                       generic_handle_irq(virq);
+                       handle_nested_irq(virq);
                }
        }
 
index 978b51eae2ec61bbba18db37cf05b8e93db2037e..ce3c1558cb0a6f6cfa5a818736da54ff8fc5ed07 100644 (file)
 
 #define DLN2_GPIO_MAX_PINS 32
 
-struct dln2_irq_work {
-       struct work_struct work;
-       struct dln2_gpio *dln2;
-       int pin;
-       int type;
-};
-
 struct dln2_gpio {
        struct platform_device *pdev;
        struct gpio_chip gpio;
@@ -64,10 +57,12 @@ struct dln2_gpio {
         */
        DECLARE_BITMAP(output_enabled, DLN2_GPIO_MAX_PINS);
 
-       DECLARE_BITMAP(irqs_masked, DLN2_GPIO_MAX_PINS);
-       DECLARE_BITMAP(irqs_enabled, DLN2_GPIO_MAX_PINS);
-       DECLARE_BITMAP(irqs_pending, DLN2_GPIO_MAX_PINS);
-       struct dln2_irq_work *irq_work;
+       /* active IRQs - not synced to hardware */
+       DECLARE_BITMAP(unmasked_irqs, DLN2_GPIO_MAX_PINS);
+       /* active IRQS - synced to hardware */
+       DECLARE_BITMAP(enabled_irqs, DLN2_GPIO_MAX_PINS);
+       int irq_type[DLN2_GPIO_MAX_PINS];
+       struct mutex irq_lock;
 };
 
 struct dln2_gpio_pin {
@@ -141,16 +136,16 @@ static int dln2_gpio_pin_get_out_val(struct dln2_gpio *dln2, unsigned int pin)
        return !!ret;
 }
 
-static void dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
-                                     unsigned int pin, int value)
+static int dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
+                                    unsigned int pin, int value)
 {
        struct dln2_gpio_pin_val req = {
                .pin = cpu_to_le16(pin),
                .value = value,
        };
 
-       dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_OUT_VAL, &req,
-                        sizeof(req));
+       return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_OUT_VAL, &req,
+                               sizeof(req));
 }
 
 #define DLN2_GPIO_DIRECTION_IN         0
@@ -267,6 +262,13 @@ static int dln2_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
                                      int value)
 {
+       struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+       int ret;
+
+       ret = dln2_gpio_pin_set_out_val(dln2, offset, value);
+       if (ret < 0)
+               return ret;
+
        return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_OUT);
 }
 
@@ -297,36 +299,13 @@ static int dln2_gpio_set_event_cfg(struct dln2_gpio *dln2, unsigned pin,
                                &req, sizeof(req));
 }
 
-static void dln2_irq_work(struct work_struct *w)
-{
-       struct dln2_irq_work *iw = container_of(w, struct dln2_irq_work, work);
-       struct dln2_gpio *dln2 = iw->dln2;
-       u8 type = iw->type & DLN2_GPIO_EVENT_MASK;
-
-       if (test_bit(iw->pin, dln2->irqs_enabled))
-               dln2_gpio_set_event_cfg(dln2, iw->pin, type, 0);
-       else
-               dln2_gpio_set_event_cfg(dln2, iw->pin, DLN2_GPIO_EVENT_NONE, 0);
-}
-
-static void dln2_irq_enable(struct irq_data *irqd)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
-       int pin = irqd_to_hwirq(irqd);
-
-       set_bit(pin, dln2->irqs_enabled);
-       schedule_work(&dln2->irq_work[pin].work);
-}
-
-static void dln2_irq_disable(struct irq_data *irqd)
+static void dln2_irq_unmask(struct irq_data *irqd)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
        struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
        int pin = irqd_to_hwirq(irqd);
 
-       clear_bit(pin, dln2->irqs_enabled);
-       schedule_work(&dln2->irq_work[pin].work);
+       set_bit(pin, dln2->unmasked_irqs);
 }
 
 static void dln2_irq_mask(struct irq_data *irqd)
@@ -335,27 +314,7 @@ static void dln2_irq_mask(struct irq_data *irqd)
        struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
        int pin = irqd_to_hwirq(irqd);
 
-       set_bit(pin, dln2->irqs_masked);
-}
-
-static void dln2_irq_unmask(struct irq_data *irqd)
-{
-       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
-       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
-       struct device *dev = dln2->gpio.dev;
-       int pin = irqd_to_hwirq(irqd);
-
-       if (test_and_clear_bit(pin, dln2->irqs_pending)) {
-               int irq;
-
-               irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
-               if (!irq) {
-                       dev_err(dev, "pin %d not mapped to IRQ\n", pin);
-                       return;
-               }
-
-               generic_handle_irq(irq);
-       }
+       clear_bit(pin, dln2->unmasked_irqs);
 }
 
 static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
@@ -366,19 +325,19 @@ static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
 
        switch (type) {
        case IRQ_TYPE_LEVEL_HIGH:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_HIGH;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_LVL_HIGH;
                break;
        case IRQ_TYPE_LEVEL_LOW:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_LOW;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_LVL_LOW;
                break;
        case IRQ_TYPE_EDGE_BOTH:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_CHANGE;
                break;
        case IRQ_TYPE_EDGE_RISING:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_RISING;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_CHANGE_RISING;
                break;
        case IRQ_TYPE_EDGE_FALLING:
-               dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_FALLING;
+               dln2->irq_type[pin] = DLN2_GPIO_EVENT_CHANGE_FALLING;
                break;
        default:
                return -EINVAL;
@@ -387,13 +346,50 @@ static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
        return 0;
 }
 
+static void dln2_irq_bus_lock(struct irq_data *irqd)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+
+       mutex_lock(&dln2->irq_lock);
+}
+
+static void dln2_irq_bus_unlock(struct irq_data *irqd)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+       struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+       int pin = irqd_to_hwirq(irqd);
+       int enabled, unmasked;
+       unsigned type;
+       int ret;
+
+       enabled = test_bit(pin, dln2->enabled_irqs);
+       unmasked = test_bit(pin, dln2->unmasked_irqs);
+
+       if (enabled != unmasked) {
+               if (unmasked) {
+                       type = dln2->irq_type[pin] & DLN2_GPIO_EVENT_MASK;
+                       set_bit(pin, dln2->enabled_irqs);
+               } else {
+                       type = DLN2_GPIO_EVENT_NONE;
+                       clear_bit(pin, dln2->enabled_irqs);
+               }
+
+               ret = dln2_gpio_set_event_cfg(dln2, pin, type, 0);
+               if (ret)
+                       dev_err(dln2->gpio.dev, "failed to set event\n");
+       }
+
+       mutex_unlock(&dln2->irq_lock);
+}
+
 static struct irq_chip dln2_gpio_irqchip = {
        .name = "dln2-irq",
-       .irq_enable = dln2_irq_enable,
-       .irq_disable = dln2_irq_disable,
        .irq_mask = dln2_irq_mask,
        .irq_unmask = dln2_irq_unmask,
        .irq_set_type = dln2_irq_set_type,
+       .irq_bus_lock = dln2_irq_bus_lock,
+       .irq_bus_sync_unlock = dln2_irq_bus_unlock,
 };
 
 static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
@@ -425,14 +421,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
                return;
        }
 
-       if (!test_bit(pin, dln2->irqs_enabled))
-               return;
-       if (test_bit(pin, dln2->irqs_masked)) {
-               set_bit(pin, dln2->irqs_pending);
-               return;
-       }
-
-       switch (dln2->irq_work[pin].type) {
+       switch (dln2->irq_type[pin]) {
        case DLN2_GPIO_EVENT_CHANGE_RISING:
                if (event->value)
                        generic_handle_irq(irq);
@@ -451,7 +440,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
        struct dln2_gpio *dln2;
        struct device *dev = &pdev->dev;
        int pins;
-       int i, ret;
+       int ret;
 
        pins = dln2_gpio_get_pin_count(pdev);
        if (pins < 0) {
@@ -467,15 +456,7 @@ static int dln2_gpio_probe(struct platform_device *pdev)
        if (!dln2)
                return -ENOMEM;
 
-       dln2->irq_work = devm_kcalloc(&pdev->dev, pins,
-                                     sizeof(struct dln2_irq_work), GFP_KERNEL);
-       if (!dln2->irq_work)
-               return -ENOMEM;
-       for (i = 0; i < pins; i++) {
-               INIT_WORK(&dln2->irq_work[i].work, dln2_irq_work);
-               dln2->irq_work[i].pin = i;
-               dln2->irq_work[i].dln2 = dln2;
-       }
+       mutex_init(&dln2->irq_lock);
 
        dln2->pdev = pdev;
 
@@ -529,11 +510,8 @@ out:
 static int dln2_gpio_remove(struct platform_device *pdev)
 {
        struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
-       int i;
 
        dln2_unregister_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV);
-       for (i = 0; i < dln2->gpio.ngpio; i++)
-               flush_work(&dln2->irq_work[i].work);
        gpiochip_remove(&dln2->gpio);
 
        return 0;
index 09daaf2aeb563d982c71807b8155df4b2c50a6c5..3a5a71050559c7c52964a5b55764ef9b16e82361 100644 (file)
@@ -441,7 +441,8 @@ static int grgpio_probe(struct platform_device *ofdev)
        err = gpiochip_add(gc);
        if (err) {
                dev_err(&ofdev->dev, "Could not add gpiochip\n");
-               irq_domain_remove(priv->domain);
+               if (priv->domain)
+                       irq_domain_remove(priv->domain);
                return err;
        }
 
index 604dbe60bdee1abdddb8d706947391987628ab9e..08261f2b3a82afed1ed6c2bdcfcf51804ddbb59d 100644 (file)
@@ -45,8 +45,14 @@ static int of_gpiochip_find_and_xlate(struct gpio_chip *gc, void *data)
                return false;
 
        ret = gc->of_xlate(gc, &gg_data->gpiospec, gg_data->flags);
-       if (ret < 0)
-               return false;
+       if (ret < 0) {
+               /* We've found the gpio chip, but the translation failed.
+                * Return true to stop looking and return the translation
+                * error via out_gpio
+                */
+               gg_data->out_gpio = ERR_PTR(ret);
+               return true;
+        }
 
        gg_data->out_gpio = gpiochip_get_desc(gc, ret);
        return true;
index 2ac1800b58bb7052032ecd23d3acf270a1deb132..f62aa115d79ab4f9fe7e249dbb146dfdde44153e 100644 (file)
@@ -128,7 +128,7 @@ static ssize_t gpio_value_store(struct device *dev,
        return status;
 }
 
-static const DEVICE_ATTR(value, 0644,
+static DEVICE_ATTR(value, 0644,
                gpio_value_show, gpio_value_store);
 
 static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
@@ -353,17 +353,46 @@ static ssize_t gpio_active_low_store(struct device *dev,
        return status ? : size;
 }
 
-static const DEVICE_ATTR(active_low, 0644,
+static DEVICE_ATTR(active_low, 0644,
                gpio_active_low_show, gpio_active_low_store);
 
-static const struct attribute *gpio_attrs[] = {
+static umode_t gpio_is_visible(struct kobject *kobj, struct attribute *attr,
+                              int n)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct gpio_desc *desc = dev_get_drvdata(dev);
+       umode_t mode = attr->mode;
+       bool show_direction = test_bit(FLAG_SYSFS_DIR, &desc->flags);
+
+       if (attr == &dev_attr_direction.attr) {
+               if (!show_direction)
+                       mode = 0;
+       } else if (attr == &dev_attr_edge.attr) {
+               if (gpiod_to_irq(desc) < 0)
+                       mode = 0;
+               if (!show_direction && test_bit(FLAG_IS_OUT, &desc->flags))
+                       mode = 0;
+       }
+
+       return mode;
+}
+
+static struct attribute *gpio_attrs[] = {
+       &dev_attr_direction.attr,
+       &dev_attr_edge.attr,
        &dev_attr_value.attr,
        &dev_attr_active_low.attr,
        NULL,
 };
 
-static const struct attribute_group gpio_attr_group = {
-       .attrs = (struct attribute **) gpio_attrs,
+static const struct attribute_group gpio_group = {
+       .attrs = gpio_attrs,
+       .is_visible = gpio_is_visible,
+};
+
+static const struct attribute_group *gpio_groups[] = {
+       &gpio_group,
+       NULL
 };
 
 /*
@@ -400,16 +429,13 @@ static ssize_t chip_ngpio_show(struct device *dev,
 }
 static DEVICE_ATTR(ngpio, 0444, chip_ngpio_show, NULL);
 
-static const struct attribute *gpiochip_attrs[] = {
+static struct attribute *gpiochip_attrs[] = {
        &dev_attr_base.attr,
        &dev_attr_label.attr,
        &dev_attr_ngpio.attr,
        NULL,
 };
-
-static const struct attribute_group gpiochip_attr_group = {
-       .attrs = (struct attribute **) gpiochip_attrs,
-};
+ATTRIBUTE_GROUPS(gpiochip);
 
 /*
  * /sys/class/gpio/export ... write-only
@@ -556,45 +582,30 @@ int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
                goto fail_unlock;
        }
 
-       if (!desc->chip->direction_input || !desc->chip->direction_output)
-               direction_may_change = false;
+       if (desc->chip->direction_input && desc->chip->direction_output &&
+                       direction_may_change) {
+               set_bit(FLAG_SYSFS_DIR, &desc->flags);
+       }
+
        spin_unlock_irqrestore(&gpio_lock, flags);
 
        offset = gpio_chip_hwgpio(desc);
        if (desc->chip->names && desc->chip->names[offset])
                ioname = desc->chip->names[offset];
 
-       dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-                           desc, ioname ? ioname : "gpio%u",
-                           desc_to_gpio(desc));
+       dev = device_create_with_groups(&gpio_class, desc->chip->dev,
+                                       MKDEV(0, 0), desc, gpio_groups,
+                                       ioname ? ioname : "gpio%u",
+                                       desc_to_gpio(desc));
        if (IS_ERR(dev)) {
                status = PTR_ERR(dev);
                goto fail_unlock;
        }
 
-       status = sysfs_create_group(&dev->kobj, &gpio_attr_group);
-       if (status)
-               goto fail_unregister_device;
-
-       if (direction_may_change) {
-               status = device_create_file(dev, &dev_attr_direction);
-               if (status)
-                       goto fail_unregister_device;
-       }
-
-       if (gpiod_to_irq(desc) >= 0 && (direction_may_change ||
-                                      !test_bit(FLAG_IS_OUT, &desc->flags))) {
-               status = device_create_file(dev, &dev_attr_edge);
-               if (status)
-                       goto fail_unregister_device;
-       }
-
        set_bit(FLAG_EXPORT, &desc->flags);
        mutex_unlock(&sysfs_lock);
        return 0;
 
-fail_unregister_device:
-       device_unregister(dev);
 fail_unlock:
        mutex_unlock(&sysfs_lock);
        gpiod_dbg(desc, "%s: status %d\n", __func__, status);
@@ -718,6 +729,7 @@ void gpiod_unexport(struct gpio_desc *desc)
                dev = class_find_device(&gpio_class, NULL, desc, match_export);
                if (dev) {
                        gpio_setup_irq(desc, dev, 0);
+                       clear_bit(FLAG_SYSFS_DIR, &desc->flags);
                        clear_bit(FLAG_EXPORT, &desc->flags);
                } else
                        status = -ENODEV;
@@ -750,13 +762,13 @@ int gpiochip_export(struct gpio_chip *chip)
 
        /* use chip->base for the ID; it's already known to be unique */
        mutex_lock(&sysfs_lock);
-       dev = device_create(&gpio_class, chip->dev, MKDEV(0, 0), chip,
-                               "gpiochip%d", chip->base);
-       if (!IS_ERR(dev)) {
-               status = sysfs_create_group(&dev->kobj,
-                               &gpiochip_attr_group);
-       } else
+       dev = device_create_with_groups(&gpio_class, chip->dev, MKDEV(0, 0),
+                                       chip, gpiochip_groups,
+                                       "gpiochip%d", chip->base);
+       if (IS_ERR(dev))
                status = PTR_ERR(dev);
+       else
+               status = 0;
        chip->exported = (status == 0);
        mutex_unlock(&sysfs_lock);
 
index 487afe6f22fcd6872b16995cffcb8179c374a276..568aa2b6bdb019e9285372d731d8a9e9bcbed1f7 100644 (file)
@@ -248,29 +248,30 @@ int gpiochip_add(struct gpio_chip *chip)
                base = gpiochip_find_base(chip->ngpio);
                if (base < 0) {
                        status = base;
-                       goto unlock;
+                       spin_unlock_irqrestore(&gpio_lock, flags);
+                       goto err_free_descs;
                }
                chip->base = base;
        }
 
        status = gpiochip_add_to_list(chip);
+       if (status) {
+               spin_unlock_irqrestore(&gpio_lock, flags);
+               goto err_free_descs;
+       }
 
-       if (status == 0) {
-               for (id = 0; id < chip->ngpio; id++) {
-                       struct gpio_desc *desc = &descs[id];
-                       desc->chip = chip;
-
-                       /* REVISIT:  most hardware initializes GPIOs as
-                        * inputs (often with pullups enabled) so power
-                        * usage is minimized.  Linux code should set the
-                        * gpio direction first thing; but until it does,
-                        * and in case chip->get_direction is not set,
-                        * we may expose the wrong direction in sysfs.
-                        */
-                       desc->flags = !chip->direction_input
-                               ? (1 << FLAG_IS_OUT)
-                               : 0;
-               }
+       for (id = 0; id < chip->ngpio; id++) {
+               struct gpio_desc *desc = &descs[id];
+
+               desc->chip = chip;
+
+               /* REVISIT: most hardware initializes GPIOs as inputs (often
+                * with pullups enabled) so power usage is minimized. Linux
+                * code should set the gpio direction first thing; but until
+                * it does, and in case chip->get_direction is not set, we may
+                * expose the wrong direction in sysfs.
+                */
+               desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
        }
 
        chip->desc = descs;
@@ -284,12 +285,9 @@ int gpiochip_add(struct gpio_chip *chip)
        of_gpiochip_add(chip);
        acpi_gpiochip_add(chip);
 
-       if (status)
-               goto fail;
-
        status = gpiochip_export(chip);
        if (status)
-               goto fail;
+               goto err_remove_chip;
 
        pr_debug("%s: registered GPIOs %d to %d on device: %s\n", __func__,
                chip->base, chip->base + chip->ngpio - 1,
@@ -297,11 +295,15 @@ int gpiochip_add(struct gpio_chip *chip)
 
        return 0;
 
-unlock:
+err_remove_chip:
+       acpi_gpiochip_remove(chip);
+       of_gpiochip_remove(chip);
+       spin_lock_irqsave(&gpio_lock, flags);
+       list_del(&chip->list);
        spin_unlock_irqrestore(&gpio_lock, flags);
-fail:
-       kfree(descs);
        chip->desc = NULL;
+err_free_descs:
+       kfree(descs);
 
        /* failures here can mean systems won't boot... */
        pr_err("%s: GPIOs %d..%d (%s) failed to register\n", __func__,
@@ -325,14 +327,15 @@ void gpiochip_remove(struct gpio_chip *chip)
        unsigned long   flags;
        unsigned        id;
 
-       acpi_gpiochip_remove(chip);
-
-       spin_lock_irqsave(&gpio_lock, flags);
+       gpiochip_unexport(chip);
 
        gpiochip_irqchip_remove(chip);
+
+       acpi_gpiochip_remove(chip);
        gpiochip_remove_pin_ranges(chip);
        of_gpiochip_remove(chip);
 
+       spin_lock_irqsave(&gpio_lock, flags);
        for (id = 0; id < chip->ngpio; id++) {
                if (test_bit(FLAG_REQUESTED, &chip->desc[id].flags))
                        dev_crit(chip->dev, "REMOVING GPIOCHIP WITH GPIOS STILL REQUESTED\n");
@@ -342,7 +345,6 @@ void gpiochip_remove(struct gpio_chip *chip)
 
        list_del(&chip->list);
        spin_unlock_irqrestore(&gpio_lock, flags);
-       gpiochip_unexport(chip);
 
        kfree(chip->desc);
        chip->desc = NULL;
index e3a52113a5410531472522ca2e1781e73bd91306..550a5eafbd38ce6f1ed5a1d9a899649df75b2fa0 100644 (file)
@@ -77,6 +77,7 @@ struct gpio_desc {
 #define FLAG_OPEN_DRAIN        7       /* Gpio is open drain type */
 #define FLAG_OPEN_SOURCE 8     /* Gpio is open source type */
 #define FLAG_USED_AS_IRQ 9     /* GPIO is connected to an IRQ */
+#define FLAG_SYSFS_DIR 10      /* show sysfs direction attribute */
 
 #define ID_SHIFT       16      /* add new flags before this one */
 
index 66e40398b3d32220624cb7fad671c86058c84339..e620807418ea7559eddc9d5a994a0c5e1f829a9c 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
 obj-$(CONFIG_DRM_TTM)  += ttm/
 obj-$(CONFIG_DRM_TDFX) += tdfx/
 obj-$(CONFIG_DRM_R128) += r128/
+obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
 obj-$(CONFIG_DRM_RADEON)+= radeon/
 obj-$(CONFIG_DRM_MGA)  += mga/
 obj-$(CONFIG_DRM_I810) += i810/
@@ -67,4 +68,3 @@ obj-$(CONFIG_DRM_IMX) += imx/
 obj-y                  += i2c/
 obj-y                  += panel/
 obj-y                  += bridge/
-obj-$(CONFIG_HSA_AMD) += amd/amdkfd/
index be6246de5091d0a589c25de25d147d8ed786af39..307a309110e60d5f473be86d26c24e3b0cb80a90 100644 (file)
@@ -8,7 +8,6 @@ amdkfd-y        := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \
                kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \
                kfd_process.o kfd_queue.o kfd_mqd_manager.o \
                kfd_kernel_queue.o kfd_packet_manager.o \
-               kfd_process_queue_manager.o kfd_device_queue_manager.o \
-               kfd_interrupt.o
+               kfd_process_queue_manager.o kfd_device_queue_manager.o
 
 obj-$(CONFIG_HSA_AMD)  += amdkfd.o
index 4f7b275f2f7b0fdbb488055057c3291a1aab3a70..fcfdf23e1913ed01663b46bebfda5eec8bc4079d 100644 (file)
@@ -31,7 +31,6 @@
 #include <uapi/linux/kfd_ioctl.h>
 #include <linux/time.h>
 #include <linux/mm.h>
-#include <linux/uaccess.h>
 #include <uapi/asm-generic/mman-common.h>
 #include <asm/processor.h>
 #include "kfd_priv.h"
@@ -121,27 +120,20 @@ static int kfd_open(struct inode *inode, struct file *filep)
        if (IS_ERR(process))
                return PTR_ERR(process);
 
-       process->is_32bit_user_mode = is_32bit_user_mode;
-
        dev_dbg(kfd_device, "process %d opened, compat mode (32 bit) - %d\n",
                process->pasid, process->is_32bit_user_mode);
 
-       kfd_init_apertures(process);
-
        return 0;
 }
 
-static long kfd_ioctl_get_version(struct file *filep, struct kfd_process *p,
-                                       void __user *arg)
+static int kfd_ioctl_get_version(struct file *filep, struct kfd_process *p,
+                                       void *data)
 {
-       struct kfd_ioctl_get_version_args args;
+       struct kfd_ioctl_get_version_args *args = data;
        int err = 0;
 
-       args.major_version = KFD_IOCTL_MAJOR_VERSION;
-       args.minor_version = KFD_IOCTL_MINOR_VERSION;
-
-       if (copy_to_user(arg, &args, sizeof(args)))
-               err = -EFAULT;
+       args->major_version = KFD_IOCTL_MAJOR_VERSION;
+       args->minor_version = KFD_IOCTL_MINOR_VERSION;
 
        return err;
 }
@@ -225,10 +217,10 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
        return 0;
 }
 
-static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
-                                       void __user *arg)
+static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
+                                       void *data)
 {
-       struct kfd_ioctl_create_queue_args args;
+       struct kfd_ioctl_create_queue_args *args = data;
        struct kfd_dev *dev;
        int err = 0;
        unsigned int queue_id;
@@ -237,16 +229,13 @@ static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
 
        memset(&q_properties, 0, sizeof(struct queue_properties));
 
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-
        pr_debug("kfd: creating queue ioctl\n");
 
-       err = set_queue_properties_from_user(&q_properties, &args);
+       err = set_queue_properties_from_user(&q_properties, args);
        if (err)
                return err;
 
-       dev = kfd_device_by_id(args.gpu_id);
+       dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
 
@@ -254,7 +243,7 @@ static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
 
        pdd = kfd_bind_process_to_device(dev, p);
        if (IS_ERR(pdd)) {
-               err = PTR_ERR(pdd);
+               err = -ESRCH;
                goto err_bind_process;
        }
 
@@ -267,33 +256,26 @@ static long kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
        if (err != 0)
                goto err_create_queue;
 
-       args.queue_id = queue_id;
+       args->queue_id = queue_id;
 
        /* Return gpu_id as doorbell offset for mmap usage */
-       args.doorbell_offset = args.gpu_id << PAGE_SHIFT;
-
-       if (copy_to_user(arg, &args, sizeof(args))) {
-               err = -EFAULT;
-               goto err_copy_args_out;
-       }
+       args->doorbell_offset = args->gpu_id << PAGE_SHIFT;
 
        mutex_unlock(&p->mutex);
 
-       pr_debug("kfd: queue id %d was created successfully\n", args.queue_id);
+       pr_debug("kfd: queue id %d was created successfully\n", args->queue_id);
 
        pr_debug("ring buffer address == 0x%016llX\n",
-                       args.ring_base_address);
+                       args->ring_base_address);
 
        pr_debug("read ptr address    == 0x%016llX\n",
-                       args.read_pointer_address);
+                       args->read_pointer_address);
 
        pr_debug("write ptr address   == 0x%016llX\n",
-                       args.write_pointer_address);
+                       args->write_pointer_address);
 
        return 0;
 
-err_copy_args_out:
-       pqm_destroy_queue(&p->pqm, queue_id);
 err_create_queue:
 err_bind_process:
        mutex_unlock(&p->mutex);
@@ -301,99 +283,90 @@ err_bind_process:
 }
 
 static int kfd_ioctl_destroy_queue(struct file *filp, struct kfd_process *p,
-                                       void __user *arg)
+                                       void *data)
 {
        int retval;
-       struct kfd_ioctl_destroy_queue_args args;
-
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
+       struct kfd_ioctl_destroy_queue_args *args = data;
 
        pr_debug("kfd: destroying queue id %d for PASID %d\n",
-                               args.queue_id,
+                               args->queue_id,
                                p->pasid);
 
        mutex_lock(&p->mutex);
 
-       retval = pqm_destroy_queue(&p->pqm, args.queue_id);
+       retval = pqm_destroy_queue(&p->pqm, args->queue_id);
 
        mutex_unlock(&p->mutex);
        return retval;
 }
 
 static int kfd_ioctl_update_queue(struct file *filp, struct kfd_process *p,
-                                       void __user *arg)
+                                       void *data)
 {
        int retval;
-       struct kfd_ioctl_update_queue_args args;
+       struct kfd_ioctl_update_queue_args *args = data;
        struct queue_properties properties;
 
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-
-       if (args.queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
+       if (args->queue_percentage > KFD_MAX_QUEUE_PERCENTAGE) {
                pr_err("kfd: queue percentage must be between 0 to KFD_MAX_QUEUE_PERCENTAGE\n");
                return -EINVAL;
        }
 
-       if (args.queue_priority > KFD_MAX_QUEUE_PRIORITY) {
+       if (args->queue_priority > KFD_MAX_QUEUE_PRIORITY) {
                pr_err("kfd: queue priority must be between 0 to KFD_MAX_QUEUE_PRIORITY\n");
                return -EINVAL;
        }
 
-       if ((args.ring_base_address) &&
+       if ((args->ring_base_address) &&
                (!access_ok(VERIFY_WRITE,
-                       (const void __user *) args.ring_base_address,
+                       (const void __user *) args->ring_base_address,
                        sizeof(uint64_t)))) {
                pr_err("kfd: can't access ring base address\n");
                return -EFAULT;
        }
 
-       if (!is_power_of_2(args.ring_size) && (args.ring_size != 0)) {
+       if (!is_power_of_2(args->ring_size) && (args->ring_size != 0)) {
                pr_err("kfd: ring size must be a power of 2 or 0\n");
                return -EINVAL;
        }
 
-       properties.queue_address = args.ring_base_address;
-       properties.queue_size = args.ring_size;
-       properties.queue_percent = args.queue_percentage;
-       properties.priority = args.queue_priority;
+       properties.queue_address = args->ring_base_address;
+       properties.queue_size = args->ring_size;
+       properties.queue_percent = args->queue_percentage;
+       properties.priority = args->queue_priority;
 
        pr_debug("kfd: updating queue id %d for PASID %d\n",
-                       args.queue_id, p->pasid);
+                       args->queue_id, p->pasid);
 
        mutex_lock(&p->mutex);
 
-       retval = pqm_update_queue(&p->pqm, args.queue_id, &properties);
+       retval = pqm_update_queue(&p->pqm, args->queue_id, &properties);
 
        mutex_unlock(&p->mutex);
 
        return retval;
 }
 
-static long kfd_ioctl_set_memory_policy(struct file *filep,
-                               struct kfd_process *p, void __user *arg)
+static int kfd_ioctl_set_memory_policy(struct file *filep,
+                                       struct kfd_process *p, void *data)
 {
-       struct kfd_ioctl_set_memory_policy_args args;
+       struct kfd_ioctl_set_memory_policy_args *args = data;
        struct kfd_dev *dev;
        int err = 0;
        struct kfd_process_device *pdd;
        enum cache_policy default_policy, alternate_policy;
 
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-
-       if (args.default_policy != KFD_IOC_CACHE_POLICY_COHERENT
-           && args.default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
+       if (args->default_policy != KFD_IOC_CACHE_POLICY_COHERENT
+           && args->default_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
                return -EINVAL;
        }
 
-       if (args.alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
-           && args.alternate_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
+       if (args->alternate_policy != KFD_IOC_CACHE_POLICY_COHERENT
+           && args->alternate_policy != KFD_IOC_CACHE_POLICY_NONCOHERENT) {
                return -EINVAL;
        }
 
-       dev = kfd_device_by_id(args.gpu_id);
+       dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
 
@@ -401,23 +374,23 @@ static long kfd_ioctl_set_memory_policy(struct file *filep,
 
        pdd = kfd_bind_process_to_device(dev, p);
        if (IS_ERR(pdd)) {
-               err = PTR_ERR(pdd);
+               err = -ESRCH;
                goto out;
        }
 
-       default_policy = (args.default_policy == KFD_IOC_CACHE_POLICY_COHERENT)
+       default_policy = (args->default_policy == KFD_IOC_CACHE_POLICY_COHERENT)
                         ? cache_policy_coherent : cache_policy_noncoherent;
 
        alternate_policy =
-               (args.alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
+               (args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
                   ? cache_policy_coherent : cache_policy_noncoherent;
 
        if (!dev->dqm->set_cache_memory_policy(dev->dqm,
                                &pdd->qpd,
                                default_policy,
                                alternate_policy,
-                               (void __user *)args.alternate_aperture_base,
-                               args.alternate_aperture_size))
+                               (void __user *)args->alternate_aperture_base,
+                               args->alternate_aperture_size))
                err = -EINVAL;
 
 out:
@@ -426,53 +399,44 @@ out:
        return err;
 }
 
-static long kfd_ioctl_get_clock_counters(struct file *filep,
-                               struct kfd_process *p, void __user *arg)
+static int kfd_ioctl_get_clock_counters(struct file *filep,
+                               struct kfd_process *p, void *data)
 {
-       struct kfd_ioctl_get_clock_counters_args args;
+       struct kfd_ioctl_get_clock_counters_args *args = data;
        struct kfd_dev *dev;
        struct timespec time;
 
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-
-       dev = kfd_device_by_id(args.gpu_id);
+       dev = kfd_device_by_id(args->gpu_id);
        if (dev == NULL)
                return -EINVAL;
 
        /* Reading GPU clock counter from KGD */
-       args.gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
+       args->gpu_clock_counter = kfd2kgd->get_gpu_clock_counter(dev->kgd);
 
        /* No access to rdtsc. Using raw monotonic time */
        getrawmonotonic(&time);
-       args.cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
+       args->cpu_clock_counter = (uint64_t)timespec_to_ns(&time);
 
        get_monotonic_boottime(&time);
-       args.system_clock_counter = (uint64_t)timespec_to_ns(&time);
+       args->system_clock_counter = (uint64_t)timespec_to_ns(&time);
 
        /* Since the counter is in nano-seconds we use 1GHz frequency */
-       args.system_clock_freq = 1000000000;
-
-       if (copy_to_user(arg, &args, sizeof(args)))
-               return -EFAULT;
+       args->system_clock_freq = 1000000000;
 
        return 0;
 }
 
 
 static int kfd_ioctl_get_process_apertures(struct file *filp,
-                               struct kfd_process *p, void __user *arg)
+                               struct kfd_process *p, void *data)
 {
-       struct kfd_ioctl_get_process_apertures_args args;
+       struct kfd_ioctl_get_process_apertures_args *args = data;
        struct kfd_process_device_apertures *pAperture;
        struct kfd_process_device *pdd;
 
        dev_dbg(kfd_device, "get apertures for PASID %d", p->pasid);
 
-       if (copy_from_user(&args, arg, sizeof(args)))
-               return -EFAULT;
-
-       args.num_of_nodes = 0;
+       args->num_of_nodes = 0;
 
        mutex_lock(&p->mutex);
 
@@ -481,7 +445,8 @@ static int kfd_ioctl_get_process_apertures(struct file *filp,
                /* Run over all pdd of the process */
                pdd = kfd_get_first_process_device_data(p);
                do {
-                       pAperture = &args.process_apertures[args.num_of_nodes];
+                       pAperture =
+                               &args->process_apertures[args->num_of_nodes];
                        pAperture->gpu_id = pdd->dev->id;
                        pAperture->lds_base = pdd->lds_base;
                        pAperture->lds_limit = pdd->lds_limit;
@@ -491,7 +456,7 @@ static int kfd_ioctl_get_process_apertures(struct file *filp,
                        pAperture->scratch_limit = pdd->scratch_limit;
 
                        dev_dbg(kfd_device,
-                               "node id %u\n", args.num_of_nodes);
+                               "node id %u\n", args->num_of_nodes);
                        dev_dbg(kfd_device,
                                "gpu id %u\n", pdd->dev->id);
                        dev_dbg(kfd_device,
@@ -507,80 +472,131 @@ static int kfd_ioctl_get_process_apertures(struct file *filp,
                        dev_dbg(kfd_device,
                                "scratch_limit %llX\n", pdd->scratch_limit);
 
-                       args.num_of_nodes++;
+                       args->num_of_nodes++;
                } while ((pdd = kfd_get_next_process_device_data(p, pdd)) != NULL &&
-                               (args.num_of_nodes < NUM_OF_SUPPORTED_GPUS));
+                               (args->num_of_nodes < NUM_OF_SUPPORTED_GPUS));
        }
 
        mutex_unlock(&p->mutex);
 
-       if (copy_to_user(arg, &args, sizeof(args)))
-               return -EFAULT;
-
        return 0;
 }
 
+#define AMDKFD_IOCTL_DEF(ioctl, _func, _flags) \
+       [_IOC_NR(ioctl)] = {.cmd = ioctl, .func = _func, .flags = _flags, .cmd_drv = 0, .name = #ioctl}
+
+/** Ioctl table */
+static const struct amdkfd_ioctl_desc amdkfd_ioctls[] = {
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_VERSION,
+                       kfd_ioctl_get_version, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_CREATE_QUEUE,
+                       kfd_ioctl_create_queue, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_DESTROY_QUEUE,
+                       kfd_ioctl_destroy_queue, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_SET_MEMORY_POLICY,
+                       kfd_ioctl_set_memory_policy, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_CLOCK_COUNTERS,
+                       kfd_ioctl_get_clock_counters, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_GET_PROCESS_APERTURES,
+                       kfd_ioctl_get_process_apertures, 0),
+
+       AMDKFD_IOCTL_DEF(AMDKFD_IOC_UPDATE_QUEUE,
+                       kfd_ioctl_update_queue, 0),
+};
+
+#define AMDKFD_CORE_IOCTL_COUNT        ARRAY_SIZE(amdkfd_ioctls)
+
 static long kfd_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
 {
        struct kfd_process *process;
-       long err = -EINVAL;
+       amdkfd_ioctl_t *func;
+       const struct amdkfd_ioctl_desc *ioctl = NULL;
+       unsigned int nr = _IOC_NR(cmd);
+       char stack_kdata[128];
+       char *kdata = NULL;
+       unsigned int usize, asize;
+       int retcode = -EINVAL;
+
+       if (nr >= AMDKFD_CORE_IOCTL_COUNT)
+               goto err_i1;
+
+       if ((nr >= AMDKFD_COMMAND_START) && (nr < AMDKFD_COMMAND_END)) {
+               u32 amdkfd_size;
+
+               ioctl = &amdkfd_ioctls[nr];
 
-       dev_dbg(kfd_device,
-               "ioctl cmd 0x%x (#%d), arg 0x%lx\n",
-               cmd, _IOC_NR(cmd), arg);
+               amdkfd_size = _IOC_SIZE(ioctl->cmd);
+               usize = asize = _IOC_SIZE(cmd);
+               if (amdkfd_size > asize)
+                       asize = amdkfd_size;
+
+               cmd = ioctl->cmd;
+       } else
+               goto err_i1;
+
+       dev_dbg(kfd_device, "ioctl cmd 0x%x (#%d), arg 0x%lx\n", cmd, nr, arg);
 
        process = kfd_get_process(current);
-       if (IS_ERR(process))
-               return PTR_ERR(process);
+       if (IS_ERR(process)) {
+               dev_dbg(kfd_device, "no process\n");
+               goto err_i1;
+       }
 
-       switch (cmd) {
-       case KFD_IOC_GET_VERSION:
-               err = kfd_ioctl_get_version(filep, process, (void __user *)arg);
-               break;
-       case KFD_IOC_CREATE_QUEUE:
-               err = kfd_ioctl_create_queue(filep, process,
-                                               (void __user *)arg);
-               break;
-
-       case KFD_IOC_DESTROY_QUEUE:
-               err = kfd_ioctl_destroy_queue(filep, process,
-                                               (void __user *)arg);
-               break;
-
-       case KFD_IOC_SET_MEMORY_POLICY:
-               err = kfd_ioctl_set_memory_policy(filep, process,
-                                               (void __user *)arg);
-               break;
-
-       case KFD_IOC_GET_CLOCK_COUNTERS:
-               err = kfd_ioctl_get_clock_counters(filep, process,
-                                               (void __user *)arg);
-               break;
-
-       case KFD_IOC_GET_PROCESS_APERTURES:
-               err = kfd_ioctl_get_process_apertures(filep, process,
-                                               (void __user *)arg);
-               break;
-
-       case KFD_IOC_UPDATE_QUEUE:
-               err = kfd_ioctl_update_queue(filep, process,
-                                               (void __user *)arg);
-               break;
-
-       default:
-               dev_err(kfd_device,
-                       "unknown ioctl cmd 0x%x, arg 0x%lx)\n",
-                       cmd, arg);
-               err = -EINVAL;
-               break;
+       /* Do not trust userspace, use our own definition */
+       func = ioctl->func;
+
+       if (unlikely(!func)) {
+               dev_dbg(kfd_device, "no function\n");
+               retcode = -EINVAL;
+               goto err_i1;
        }
 
-       if (err < 0)
-               dev_err(kfd_device,
-                       "ioctl error %ld for ioctl cmd 0x%x (#%d)\n",
-                       err, cmd, _IOC_NR(cmd));
+       if (cmd & (IOC_IN | IOC_OUT)) {
+               if (asize <= sizeof(stack_kdata)) {
+                       kdata = stack_kdata;
+               } else {
+                       kdata = kmalloc(asize, GFP_KERNEL);
+                       if (!kdata) {
+                               retcode = -ENOMEM;
+                               goto err_i1;
+                       }
+               }
+               if (asize > usize)
+                       memset(kdata + usize, 0, asize - usize);
+       }
 
-       return err;
+       if (cmd & IOC_IN) {
+               if (copy_from_user(kdata, (void __user *)arg, usize) != 0) {
+                       retcode = -EFAULT;
+                       goto err_i1;
+               }
+       } else if (cmd & IOC_OUT) {
+               memset(kdata, 0, usize);
+       }
+
+       retcode = func(filep, process, kdata);
+
+       if (cmd & IOC_OUT)
+               if (copy_to_user((void __user *)arg, kdata, usize) != 0)
+                       retcode = -EFAULT;
+
+err_i1:
+       if (!ioctl)
+               dev_dbg(kfd_device, "invalid ioctl: pid=%d, cmd=0x%02x, nr=0x%02x\n",
+                         task_pid_nr(current), cmd, nr);
+
+       if (kdata != stack_kdata)
+               kfree(kdata);
+
+       if (retcode)
+               dev_dbg(kfd_device, "ret = %d\n", retcode);
+
+       return retcode;
 }
 
 static int kfd_mmap(struct file *filp, struct vm_area_struct *vma)
index 43884ebd4303fedd47b56431737a0f726852c552..25bc47f3c1cf53d0181d0bc63f3c381f0502f138 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include "kfd_priv.h"
 #include "kfd_device_queue_manager.h"
+#include "kfd_pm4_headers.h"
 
 #define MQD_SIZE_ALIGNED 768
 
@@ -169,9 +170,8 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
        kfd->shared_resources = *gpu_resources;
 
        /* calculate max size of mqds needed for queues */
-       size = max_num_of_processes *
-               max_num_of_queues_per_process *
-               kfd->device_info->mqd_size_aligned;
+       size = max_num_of_queues_per_device *
+                       kfd->device_info->mqd_size_aligned;
 
        /* add another 512KB for all other allocations on gart */
        size += 512 * 1024;
@@ -192,13 +192,6 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
                goto kfd_topology_add_device_error;
        }
 
-       if (kfd_interrupt_init(kfd)) {
-               dev_err(kfd_device,
-                       "Error initializing interrupts for device (%x:%x)\n",
-                       kfd->pdev->vendor, kfd->pdev->device);
-               goto kfd_interrupt_error;
-       }
-
        if (!device_iommu_pasid_init(kfd)) {
                dev_err(kfd_device,
                        "Error initializing iommuv2 for device (%x:%x)\n",
@@ -237,8 +230,6 @@ dqm_start_error:
 device_queue_manager_error:
        amd_iommu_free_device(kfd->pdev);
 device_iommu_pasid_error:
-       kfd_interrupt_exit(kfd);
-kfd_interrupt_error:
        kfd_topology_remove_device(kfd);
 kfd_topology_add_device_error:
        kfd2kgd->fini_sa_manager(kfd->kgd);
@@ -254,7 +245,6 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
        if (kfd->init_complete) {
                device_queue_manager_uninit(kfd->dqm);
                amd_iommu_free_device(kfd->pdev);
-               kfd_interrupt_exit(kfd);
                kfd_topology_remove_device(kfd);
        }
 
@@ -296,13 +286,5 @@ int kgd2kfd_resume(struct kfd_dev *kfd)
 /* This is called directly from KGD at ISR. */
 void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
 {
-       if (kfd->init_complete) {
-               spin_lock(&kfd->interrupt_lock);
-
-               if (kfd->interrupts_active
-                   && enqueue_ih_ring_entry(kfd, ih_ring_entry))
-                       schedule_work(&kfd->interrupt_work);
-
-               spin_unlock(&kfd->interrupt_lock);
-       }
+       /* Process interrupts / schedule work as necessary */
 }
index 924e90c072e513180ec8991b50333f2af663a3f5..0d8694f015c1a58a829da1fef863c99a3fba47f5 100644 (file)
@@ -161,6 +161,9 @@ static void deallocate_vmid(struct device_queue_manager *dqm,
 {
        int bit = qpd->vmid - KFD_VMID_START_OFFSET;
 
+       /* Release the vmid mapping */
+       set_pasid_vmid_mapping(dqm, 0, qpd->vmid);
+
        set_bit(bit, (unsigned long *)&dqm->vmid_bitmap);
        qpd->vmid = 0;
        q->properties.vmid = 0;
@@ -180,6 +183,13 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
 
        mutex_lock(&dqm->lock);
 
+       if (dqm->total_queue_count >= max_num_of_queues_per_device) {
+               pr_warn("amdkfd: Can't create new usermode queue because %d queues were already created\n",
+                               dqm->total_queue_count);
+               mutex_unlock(&dqm->lock);
+               return -EPERM;
+       }
+
        if (list_empty(&qpd->queues_list)) {
                retval = allocate_vmid(dqm, qpd, q);
                if (retval != 0) {
@@ -204,6 +214,14 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
        list_add(&q->list, &qpd->queues_list);
        dqm->queue_count++;
 
+       /*
+        * Unconditionally increment this counter, regardless of the queue's
+        * type or whether the queue is active.
+        */
+       dqm->total_queue_count++;
+       pr_debug("Total of %d queues are accountable so far\n",
+                       dqm->total_queue_count);
+
        mutex_unlock(&dqm->lock);
        return 0;
 }
@@ -272,6 +290,18 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
                return retval;
        }
 
+       pr_debug("kfd: loading mqd to hqd on pipe (%d) queue (%d)\n",
+                       q->pipe,
+                       q->queue);
+
+       retval = mqd->load_mqd(mqd, q->mqd, q->pipe,
+                       q->queue, (uint32_t __user *) q->properties.write_ptr);
+       if (retval != 0) {
+               deallocate_hqd(dqm, q);
+               mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
+               return retval;
+       }
+
        return 0;
 }
 
@@ -311,6 +341,15 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm,
        if (list_empty(&qpd->queues_list))
                deallocate_vmid(dqm, qpd, q);
        dqm->queue_count--;
+
+       /*
+        * Unconditionally decrement this counter, regardless of the queue's
+        * type
+        */
+       dqm->total_queue_count--;
+       pr_debug("Total of %d queues are accountable so far\n",
+                       dqm->total_queue_count);
+
 out:
        mutex_unlock(&dqm->lock);
        return retval;
@@ -320,6 +359,7 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q)
 {
        int retval;
        struct mqd_manager *mqd;
+       bool prev_active = false;
 
        BUG_ON(!dqm || !q || !q->mqd);
 
@@ -330,10 +370,18 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q)
                return -ENOMEM;
        }
 
-       retval = mqd->update_mqd(mqd, q->mqd, &q->properties);
        if (q->properties.is_active == true)
+               prev_active = true;
+
+       /*
+        *
+        * check active state vs. the previous state
+        * and modify counter accordingly
+        */
+       retval = mqd->update_mqd(mqd, q->mqd, &q->properties);
+       if ((q->properties.is_active == true) && (prev_active == false))
                dqm->queue_count++;
-       else
+       else if ((q->properties.is_active == false) && (prev_active == true))
                dqm->queue_count--;
 
        if (sched_policy != KFD_SCHED_POLICY_NO_HWS)
@@ -517,10 +565,14 @@ static int init_pipelines(struct device_queue_manager *dqm,
 
        for (i = 0; i < pipes_num; i++) {
                inx = i + first_pipe;
+               /*
+                * HPD buffer on GTT is allocated by amdkfd, no need to waste
+                * space in GTT for pipelines we don't initialize
+                */
                pipe_hpd_addr = dqm->pipelines_addr + i * CIK_HPD_EOP_BYTES;
                pr_debug("kfd: pipeline address %llX\n", pipe_hpd_addr);
                /* = log2(bytes/4)-1 */
-               kfd2kgd->init_pipeline(dqm->dev->kgd, i,
+               kfd2kgd->init_pipeline(dqm->dev->kgd, inx,
                                CIK_HPD_EOP_BYTES_LOG2 - 3, pipe_hpd_addr);
        }
 
@@ -536,7 +588,7 @@ static int init_scheduler(struct device_queue_manager *dqm)
 
        pr_debug("kfd: In %s\n", __func__);
 
-       retval = init_pipelines(dqm, get_pipes_num(dqm), KFD_DQM_FIRST_PIPE);
+       retval = init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
        if (retval != 0)
                return retval;
 
@@ -728,6 +780,21 @@ static int create_kernel_queue_cpsch(struct device_queue_manager *dqm,
        pr_debug("kfd: In func %s\n", __func__);
 
        mutex_lock(&dqm->lock);
+       if (dqm->total_queue_count >= max_num_of_queues_per_device) {
+               pr_warn("amdkfd: Can't create new kernel queue because %d queues were already created\n",
+                               dqm->total_queue_count);
+               mutex_unlock(&dqm->lock);
+               return -EPERM;
+       }
+
+       /*
+        * Unconditionally increment this counter, regardless of the queue's
+        * type or whether the queue is active.
+        */
+       dqm->total_queue_count++;
+       pr_debug("Total of %d queues are accountable so far\n",
+                       dqm->total_queue_count);
+
        list_add(&kq->list, &qpd->priv_queue_list);
        dqm->queue_count++;
        qpd->is_debug = true;
@@ -751,6 +818,13 @@ static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm,
        dqm->queue_count--;
        qpd->is_debug = false;
        execute_queues_cpsch(dqm, false);
+       /*
+        * Unconditionally decrement this counter, regardless of the queue's
+        * type.
+        */
+       dqm->total_queue_count++;
+       pr_debug("Total of %d queues are accountable so far\n",
+                       dqm->total_queue_count);
        mutex_unlock(&dqm->lock);
 }
 
@@ -769,6 +843,13 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
 
        mutex_lock(&dqm->lock);
 
+       if (dqm->total_queue_count >= max_num_of_queues_per_device) {
+               pr_warn("amdkfd: Can't create new usermode queue because %d queues were already created\n",
+                               dqm->total_queue_count);
+               retval = -EPERM;
+               goto out;
+       }
+
        mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
        if (mqd == NULL) {
                mutex_unlock(&dqm->lock);
@@ -786,6 +867,15 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
                retval = execute_queues_cpsch(dqm, false);
        }
 
+       /*
+        * Unconditionally increment this counter, regardless of the queue's
+        * type or whether the queue is active.
+        */
+       dqm->total_queue_count++;
+
+       pr_debug("Total of %d queues are accountable so far\n",
+                       dqm->total_queue_count);
+
 out:
        mutex_unlock(&dqm->lock);
        return retval;
@@ -906,6 +996,14 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
 
        mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
 
+       /*
+        * Unconditionally decrement this counter, regardless of the queue's
+        * type
+        */
+       dqm->total_queue_count--;
+       pr_debug("Total of %d queues are accountable so far\n",
+                       dqm->total_queue_count);
+
        mutex_unlock(&dqm->lock);
 
        return 0;
index c3f189e8ae35da5527efebe3ae016b47b2b3342c..52035bf0c1cb3ce896901573491a071c17c8bcea 100644 (file)
@@ -130,6 +130,7 @@ struct device_queue_manager {
        struct list_head        queues;
        unsigned int            processes_count;
        unsigned int            queue_count;
+       unsigned int            total_queue_count;
        unsigned int            next_pipe_to_allocate;
        unsigned int            *allocated_queues;
        unsigned int            vmid_bitmap;
index 66df4da01c29a200d64a6a801d8d250231d7d269..e64aa99e5e416349071f3c0906be347ed42e3e53 100644 (file)
@@ -299,13 +299,13 @@ int kfd_init_apertures(struct kfd_process *process)
        struct kfd_dev *dev;
        struct kfd_process_device *pdd;
 
-       mutex_lock(&process->mutex);
-
        /*Iterating over all devices*/
        while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL &&
                id < NUM_OF_SUPPORTED_GPUS) {
 
                pdd = kfd_get_process_device_data(dev, process, 1);
+               if (!pdd)
+                       return -1;
 
                /*
                 * For 64 bit process aperture will be statically reserved in
@@ -348,8 +348,6 @@ int kfd_init_apertures(struct kfd_process *process)
                id++;
        }
 
-       mutex_unlock(&process->mutex);
-
        return 0;
 }
 
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c b/drivers/gpu/drm/amd/amdkfd/kfd_interrupt.c
deleted file mode 100644 (file)
index 5b99909..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2014 Advanced Micro Devices, Inc.
- *
- * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
- */
-
-/*
- * KFD Interrupts.
- *
- * AMD GPUs deliver interrupts by pushing an interrupt description onto the
- * interrupt ring and then sending an interrupt. KGD receives the interrupt
- * in ISR and sends us a pointer to each new entry on the interrupt ring.
- *
- * We generally can't process interrupt-signaled events from ISR, so we call
- * out to each interrupt client module (currently only the scheduler) to ask if
- * each interrupt is interesting. If they return true, then it requires further
- * processing so we copy it to an internal interrupt ring and call each
- * interrupt client again from a work-queue.
- *
- * There's no acknowledgment for the interrupts we use. The hardware simply
- * queues a new interrupt each time without waiting.
- *
- * The fixed-size internal queue means that it's possible for us to lose
- * interrupts because we have no back-pressure to the hardware.
- */
-
-#include <linux/slab.h>
-#include <linux/device.h>
-#include "kfd_priv.h"
-
-#define KFD_INTERRUPT_RING_SIZE 256
-
-static void interrupt_wq(struct work_struct *);
-
-int kfd_interrupt_init(struct kfd_dev *kfd)
-{
-       void *interrupt_ring = kmalloc_array(KFD_INTERRUPT_RING_SIZE,
-                                       kfd->device_info->ih_ring_entry_size,
-                                       GFP_KERNEL);
-       if (!interrupt_ring)
-               return -ENOMEM;
-
-       kfd->interrupt_ring = interrupt_ring;
-       kfd->interrupt_ring_size =
-               KFD_INTERRUPT_RING_SIZE * kfd->device_info->ih_ring_entry_size;
-       atomic_set(&kfd->interrupt_ring_wptr, 0);
-       atomic_set(&kfd->interrupt_ring_rptr, 0);
-
-       spin_lock_init(&kfd->interrupt_lock);
-
-       INIT_WORK(&kfd->interrupt_work, interrupt_wq);
-
-       kfd->interrupts_active = true;
-
-       /*
-        * After this function returns, the interrupt will be enabled. This
-        * barrier ensures that the interrupt running on a different processor
-        * sees all the above writes.
-        */
-       smp_wmb();
-
-       return 0;
-}
-
-void kfd_interrupt_exit(struct kfd_dev *kfd)
-{
-       /*
-        * Stop the interrupt handler from writing to the ring and scheduling
-        * workqueue items. The spinlock ensures that any interrupt running
-        * after we have unlocked sees interrupts_active = false.
-        */
-       unsigned long flags;
-
-       spin_lock_irqsave(&kfd->interrupt_lock, flags);
-       kfd->interrupts_active = false;
-       spin_unlock_irqrestore(&kfd->interrupt_lock, flags);
-
-       /*
-        * Flush_scheduled_work ensures that there are no outstanding
-        * work-queue items that will access interrupt_ring. New work items
-        * can't be created because we stopped interrupt handling above.
-        */
-       flush_scheduled_work();
-
-       kfree(kfd->interrupt_ring);
-}
-
-/*
- * This assumes that it can't be called concurrently with itself
- * but only with dequeue_ih_ring_entry.
- */
-bool enqueue_ih_ring_entry(struct kfd_dev *kfd,        const void *ih_ring_entry)
-{
-       unsigned int rptr = atomic_read(&kfd->interrupt_ring_rptr);
-       unsigned int wptr = atomic_read(&kfd->interrupt_ring_wptr);
-
-       if ((rptr - wptr) % kfd->interrupt_ring_size ==
-                                       kfd->device_info->ih_ring_entry_size) {
-               /* This is very bad, the system is likely to hang. */
-               dev_err_ratelimited(kfd_chardev(),
-                       "Interrupt ring overflow, dropping interrupt.\n");
-               return false;
-       }
-
-       memcpy(kfd->interrupt_ring + wptr, ih_ring_entry,
-                       kfd->device_info->ih_ring_entry_size);
-
-       wptr = (wptr + kfd->device_info->ih_ring_entry_size) %
-                       kfd->interrupt_ring_size;
-       smp_wmb(); /* Ensure memcpy'd data is visible before wptr update. */
-       atomic_set(&kfd->interrupt_ring_wptr, wptr);
-
-       return true;
-}
-
-/*
- * This assumes that it can't be called concurrently with itself
- * but only with enqueue_ih_ring_entry.
- */
-static bool dequeue_ih_ring_entry(struct kfd_dev *kfd, void *ih_ring_entry)
-{
-       /*
-        * Assume that wait queues have an implicit barrier, i.e. anything that
-        * happened in the ISR before it queued work is visible.
-        */
-
-       unsigned int wptr = atomic_read(&kfd->interrupt_ring_wptr);
-       unsigned int rptr = atomic_read(&kfd->interrupt_ring_rptr);
-
-       if (rptr == wptr)
-               return false;
-
-       memcpy(ih_ring_entry, kfd->interrupt_ring + rptr,
-                       kfd->device_info->ih_ring_entry_size);
-
-       rptr = (rptr + kfd->device_info->ih_ring_entry_size) %
-                       kfd->interrupt_ring_size;
-
-       /*
-        * Ensure the rptr write update is not visible until
-        * memcpy has finished reading.
-        */
-       smp_mb();
-       atomic_set(&kfd->interrupt_ring_rptr, rptr);
-
-       return true;
-}
-
-static void interrupt_wq(struct work_struct *work)
-{
-       struct kfd_dev *dev = container_of(work, struct kfd_dev,
-                                               interrupt_work);
-
-       uint32_t ih_ring_entry[DIV_ROUND_UP(
-                               dev->device_info->ih_ring_entry_size,
-                               sizeof(uint32_t))];
-
-       while (dequeue_ih_ring_entry(dev, ih_ring_entry))
-               ;
-}
index 95d5af138e6e7f2bcbd8d76351f7e12827031189..a8be6df8534753fbaed2103a57a3f054838bc29a 100644 (file)
@@ -50,15 +50,10 @@ module_param(sched_policy, int, 0444);
 MODULE_PARM_DESC(sched_policy,
        "Kernel cmdline parameter that defines the amdkfd scheduling policy");
 
-int max_num_of_processes = KFD_MAX_NUM_OF_PROCESSES_DEFAULT;
-module_param(max_num_of_processes, int, 0444);
-MODULE_PARM_DESC(max_num_of_processes,
-       "Kernel cmdline parameter that defines the amdkfd maximum number of supported processes");
-
-int max_num_of_queues_per_process = KFD_MAX_NUM_OF_QUEUES_PER_PROCESS_DEFAULT;
-module_param(max_num_of_queues_per_process, int, 0444);
-MODULE_PARM_DESC(max_num_of_queues_per_process,
-       "Kernel cmdline parameter that defines the amdkfd maximum number of supported queues per process");
+int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT;
+module_param(max_num_of_queues_per_device, int, 0444);
+MODULE_PARM_DESC(max_num_of_queues_per_device,
+       "Maximum number of supported queues per device (1 = Minimum, 4096 = default)");
 
 bool kgd2kfd_init(unsigned interface_version,
                  const struct kfd2kgd_calls *f2g,
@@ -100,16 +95,10 @@ static int __init kfd_module_init(void)
        }
 
        /* Verify module parameters */
-       if ((max_num_of_processes < 0) ||
-               (max_num_of_processes > KFD_MAX_NUM_OF_PROCESSES)) {
-               pr_err("kfd: max_num_of_processes must be between 0 to KFD_MAX_NUM_OF_PROCESSES\n");
-               return -1;
-       }
-
-       if ((max_num_of_queues_per_process < 0) ||
-               (max_num_of_queues_per_process >
-                       KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)) {
-               pr_err("kfd: max_num_of_queues_per_process must be between 0 to KFD_MAX_NUM_OF_QUEUES_PER_PROCESS\n");
+       if ((max_num_of_queues_per_device < 0) ||
+               (max_num_of_queues_per_device >
+                       KFD_MAX_NUM_OF_QUEUES_PER_DEVICE)) {
+               pr_err("kfd: max_num_of_queues_per_device must be between 0 to KFD_MAX_NUM_OF_QUEUES_PER_DEVICE\n");
                return -1;
        }
 
index adc31474e786195bb3308150334c5a7a280f1d81..4c3828cf45bf71fbbae7e26f21f22bcd927fadce 100644 (file)
@@ -184,7 +184,7 @@ static bool is_occupied(struct mqd_manager *mm, void *mqd,
                        uint32_t queue_id)
 {
 
-       return kfd2kgd->hqd_is_occupies(mm->dev->kgd, queue_address,
+       return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
                                        pipe_id, queue_id);
 
 }
index 71699ad97d74487d532cef2a168f8bb4d4fb5366..6cfe7f1f18cff0d805a75097a5a9f86e2a4fcdfd 100644 (file)
@@ -30,9 +30,9 @@ static DEFINE_MUTEX(pasid_mutex);
 
 int kfd_pasid_init(void)
 {
-       pasid_limit = max_num_of_processes;
+       pasid_limit = KFD_MAX_NUM_OF_PROCESSES;
 
-       pasid_bitmap = kzalloc(BITS_TO_LONGS(pasid_limit), GFP_KERNEL);
+       pasid_bitmap = kcalloc(BITS_TO_LONGS(pasid_limit), sizeof(long), GFP_KERNEL);
        if (!pasid_bitmap)
                return -ENOMEM;
 
index f9fb81e3bb09b24edd7f8de6c22cf7e64a92391b..96dc10e8904afc3cd2e5a8069ca8fb0a1eda2e6b 100644 (file)
 #define kfd_alloc_struct(ptr_to_struct)        \
        ((typeof(ptr_to_struct)) kzalloc(sizeof(*ptr_to_struct), GFP_KERNEL))
 
-/* Kernel module parameter to specify maximum number of supported processes */
-extern int max_num_of_processes;
-
-#define KFD_MAX_NUM_OF_PROCESSES_DEFAULT 32
 #define KFD_MAX_NUM_OF_PROCESSES 512
+#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS 1024
 
 /*
- * Kernel module parameter to specify maximum number of supported queues
- * per process
+ * Kernel module parameter to specify maximum number of supported queues per
+ * device
  */
-extern int max_num_of_queues_per_process;
+extern int max_num_of_queues_per_device;
 
-#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS_DEFAULT 128
-#define KFD_MAX_NUM_OF_QUEUES_PER_PROCESS 1024
+#define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT 4096
+#define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE               \
+       (KFD_MAX_NUM_OF_PROCESSES *                     \
+                       KFD_MAX_NUM_OF_QUEUES_PER_PROCESS)
 
 #define KFD_KERNEL_QUEUE_SIZE 2048
 
@@ -135,22 +134,10 @@ struct kfd_dev {
 
        struct kgd2kfd_shared_resources shared_resources;
 
-       void *interrupt_ring;
-       size_t interrupt_ring_size;
-       atomic_t interrupt_ring_rptr;
-       atomic_t interrupt_ring_wptr;
-       struct work_struct interrupt_work;
-       spinlock_t interrupt_lock;
-
        /* QCM Device instance */
        struct device_queue_manager *dqm;
 
        bool init_complete;
-       /*
-        * Interrupts of interest to KFD are copied
-        * from the HW ring into a SW ring.
-        */
-       bool interrupts_active;
 };
 
 /* KGD2KFD callbacks */
@@ -463,6 +450,24 @@ struct kfd_process {
        bool is_32bit_user_mode;
 };
 
+/**
+ * Ioctl function type.
+ *
+ * \param filep pointer to file structure.
+ * \param p amdkfd process pointer.
+ * \param data pointer to arg that was copied from user.
+ */
+typedef int amdkfd_ioctl_t(struct file *filep, struct kfd_process *p,
+                               void *data);
+
+struct amdkfd_ioctl_desc {
+       unsigned int cmd;
+       int flags;
+       amdkfd_ioctl_t *func;
+       unsigned int cmd_drv;
+       const char *name;
+};
+
 void kfd_process_create_wq(void);
 void kfd_process_destroy_wq(void);
 struct kfd_process *kfd_create_process(const struct task_struct *);
@@ -513,10 +518,7 @@ struct kfd_dev *kfd_device_by_pci_dev(const struct pci_dev *pdev);
 struct kfd_dev *kfd_topology_enum_kfd_devices(uint8_t idx);
 
 /* Interrupts */
-int kfd_interrupt_init(struct kfd_dev *dev);
-void kfd_interrupt_exit(struct kfd_dev *dev);
 void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry);
-bool enqueue_ih_ring_entry(struct kfd_dev *kfd,        const void *ih_ring_entry);
 
 /* Power Management */
 void kgd2kfd_suspend(struct kfd_dev *kfd);
index b85eb0b830b41d5d894efebb2a3e6fab83ca7552..3c76ef05cbcf798483b482ac09b7bc62223d92c5 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/slab.h>
 #include <linux/amd-iommu.h>
 #include <linux/notifier.h>
+#include <linux/compat.h>
+
 struct mm_struct;
 
 #include "kfd_priv.h"
@@ -285,8 +287,15 @@ static struct kfd_process *create_process(const struct task_struct *thread)
        if (err != 0)
                goto err_process_pqm_init;
 
+       /* init process apertures*/
+       process->is_32bit_user_mode = is_compat_task();
+       if (kfd_init_apertures(process) != 0)
+               goto err_init_apretures;
+
        return process;
 
+err_init_apretures:
+       pqm_uninit(&process->pqm);
 err_process_pqm_init:
        hash_del_rcu(&process->kfd_processes);
        synchronize_rcu();
index 47526780d736ced5470bfb2822a3892f879b0320..f37cf5efe642ca23b42fc45de8ca0c69617d9937 100644 (file)
@@ -54,11 +54,11 @@ static int find_available_queue_slot(struct process_queue_manager *pqm,
        pr_debug("kfd: in %s\n", __func__);
 
        found = find_first_zero_bit(pqm->queue_slot_bitmap,
-                       max_num_of_queues_per_process);
+                       KFD_MAX_NUM_OF_QUEUES_PER_PROCESS);
 
        pr_debug("kfd: the new slot id %lu\n", found);
 
-       if (found >= max_num_of_queues_per_process) {
+       if (found >= KFD_MAX_NUM_OF_QUEUES_PER_PROCESS) {
                pr_info("amdkfd: Can not open more queues for process with pasid %d\n",
                                pqm->process->pasid);
                return -ENOMEM;
@@ -76,7 +76,7 @@ int pqm_init(struct process_queue_manager *pqm, struct kfd_process *p)
 
        INIT_LIST_HEAD(&pqm->queues);
        pqm->queue_slot_bitmap =
-                       kzalloc(DIV_ROUND_UP(max_num_of_queues_per_process,
+                       kzalloc(DIV_ROUND_UP(KFD_MAX_NUM_OF_QUEUES_PER_PROCESS,
                                        BITS_PER_BYTE), GFP_KERNEL);
        if (pqm->queue_slot_bitmap == NULL)
                return -ENOMEM;
@@ -203,6 +203,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
                pqn->kq = NULL;
                retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd,
                                                &q->properties.vmid);
+               pr_debug("DQM returned %d for create_queue\n", retval);
                print_queue(q);
                break;
        case KFD_QUEUE_TYPE_DIQ:
@@ -222,7 +223,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
        }
 
        if (retval != 0) {
-               pr_err("kfd: error dqm create queue\n");
+               pr_debug("Error dqm create queue\n");
                goto err_create_queue;
        }
 
@@ -241,7 +242,10 @@ int pqm_create_queue(struct process_queue_manager *pqm,
 err_create_queue:
        kfree(pqn);
 err_allocate_pqn:
+       /* check if queues list is empty unregister process from device */
        clear_bit(*qid, pqm->queue_slot_bitmap);
+       if (list_empty(&pqm->queues))
+               dev->dqm->unregister_process(dev->dqm, &pdd->qpd);
        return retval;
 }
 
index 5733e2859e8aabbc361ce821f5e337c0008dd6a3..cca1708fd811be8253ab0d2989d74e405f3dab04 100644 (file)
@@ -700,8 +700,6 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                                dev->node_props.simd_per_cu);
                sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
                                dev->node_props.max_slots_scratch_cu);
-               sysfs_show_32bit_prop(buffer, "engine_id",
-                               dev->node_props.engine_id);
                sysfs_show_32bit_prop(buffer, "vendor_id",
                                dev->node_props.vendor_id);
                sysfs_show_32bit_prop(buffer, "device_id",
@@ -715,6 +713,12 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
                                                dev->gpu->kgd));
                        sysfs_show_64bit_prop(buffer, "local_mem_size",
                                        kfd2kgd->get_vmem_size(dev->gpu->kgd));
+
+                       sysfs_show_32bit_prop(buffer, "fw_version",
+                                       kfd2kgd->get_fw_version(
+                                                       dev->gpu->kgd,
+                                                       KGD_ENGINE_MEC1));
+
                }
 
                ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
@@ -917,7 +921,7 @@ static int kfd_build_sysfs_node_tree(void)
        uint32_t i = 0;
 
        list_for_each_entry(dev, &topology_device_list, list) {
-               ret = kfd_build_sysfs_node_entry(dev, 0);
+               ret = kfd_build_sysfs_node_entry(dev, i);
                if (ret < 0)
                        return ret;
                i++;
index 9c729dd8dd50a077d35f77ed3646438fb80d5c86..96a512208fade6825da6aa8e2645f2a088d485d2 100644 (file)
@@ -45,6 +45,17 @@ enum kgd_memory_pool {
        KGD_POOL_FRAMEBUFFER = 3,
 };
 
+enum kgd_engine_type {
+       KGD_ENGINE_PFP = 1,
+       KGD_ENGINE_ME,
+       KGD_ENGINE_CE,
+       KGD_ENGINE_MEC1,
+       KGD_ENGINE_MEC2,
+       KGD_ENGINE_RLC,
+       KGD_ENGINE_SDMA,
+       KGD_ENGINE_MAX
+};
+
 struct kgd2kfd_shared_resources {
        /* Bit n == 1 means VMID n is available for KFD. */
        unsigned int compute_vmid_bitmap;
@@ -137,6 +148,8 @@ struct kgd2kfd_calls {
  *
  * @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
  *
+ * @get_fw_version: Returns FW versions from the header
+ *
  * This structure contains function pointers to services that the kgd driver
  * provides to amdkfd driver.
  *
@@ -170,12 +183,14 @@ struct kfd2kgd_calls {
        int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr);
 
-       bool (*hqd_is_occupies)(struct kgd_dev *kgd, uint64_t queue_address,
+       bool (*hqd_is_occupied)(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id);
 
        int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
                                unsigned int timeout, uint32_t pipe_id,
                                uint32_t queue_id);
+       uint16_t (*get_fw_version)(struct kgd_dev *kgd,
+                               enum kgd_engine_type type);
 };
 
 bool kgd2kfd_init(unsigned interface_version,
index 4a78a773151ce71f464d36cc4d1d6d887eea1619..bbdbe4721573a92667fe3989bbc1e0be8123bc2b 100644 (file)
@@ -61,7 +61,7 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state,
        struct drm_crtc_state *crtc_state;
 
        if (plane->state->crtc) {
-               crtc_state = state->crtc_states[drm_crtc_index(plane->crtc)];
+               crtc_state = state->crtc_states[drm_crtc_index(plane->state->crtc)];
 
                if (WARN_ON(!crtc_state))
                        return;
index 52ce26d6b4fb8aeda59bb6358f62a659bc0464b7..dc386ebe5193891e6780c7eba47951f3f3fd3e42 100644 (file)
@@ -145,6 +145,31 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
 }
 EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
 
+static void remove_from_modeset(struct drm_mode_set *set,
+               struct drm_connector *connector)
+{
+       int i, j;
+
+       for (i = 0; i < set->num_connectors; i++) {
+               if (set->connectors[i] == connector)
+                       break;
+       }
+
+       if (i == set->num_connectors)
+               return;
+
+       for (j = i + 1; j < set->num_connectors; j++) {
+               set->connectors[j - 1] = set->connectors[j];
+       }
+       set->num_connectors--;
+
+       /* because i915 is pissy about this..
+        * TODO maybe need to makes sure we set it back to !=NULL somewhere?
+        */
+       if (set->num_connectors == 0)
+               set->fb = NULL;
+}
+
 int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
                                       struct drm_connector *connector)
 {
@@ -167,6 +192,11 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
        }
        fb_helper->connector_count--;
        kfree(fb_helper_connector);
+
+       /* also cleanup dangling references to the connector: */
+       for (i = 0; i < fb_helper->crtc_count; i++)
+               remove_from_modeset(&fb_helper->crtc_info[i].mode_set, connector);
+
        return 0;
 }
 EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
@@ -741,7 +771,9 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
        int i, j, rc = 0;
        int start;
 
-       drm_modeset_lock_all(dev);
+       if (__drm_modeset_lock_all(dev, !!oops_in_progress)) {
+               return -EBUSY;
+       }
        if (!drm_fb_helper_is_bound(fb_helper)) {
                drm_modeset_unlock_all(dev);
                return -EBUSY;
@@ -915,7 +947,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
        int ret = 0;
        int i;
 
-       drm_modeset_lock_all(dev);
+       if (__drm_modeset_lock_all(dev, !!oops_in_progress)) {
+               return -EBUSY;
+       }
        if (!drm_fb_helper_is_bound(fb_helper)) {
                drm_modeset_unlock_all(dev);
                return -EBUSY;
index f5a5f18efa5bf230d810d8c031bb30cfddd0390a..4d79dad9d44fad0ac48b2b81177ffda8430b390b 100644 (file)
@@ -830,6 +830,8 @@ drm_get_last_vbltimestamp(struct drm_device *dev, int crtc,
  * vblank events since the system was booted, including lost events due to
  * modesetting activity.
  *
+ * This is the legacy version of drm_crtc_vblank_count().
+ *
  * Returns:
  * The software vblank counter.
  */
@@ -843,6 +845,25 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
+/**
+ * drm_crtc_vblank_count - retrieve "cooked" vblank counter value
+ * @crtc: which counter to retrieve
+ *
+ * Fetches the "cooked" vblank count value that represents the number of
+ * vblank events since the system was booted, including lost events due to
+ * modesetting activity.
+ *
+ * This is the native KMS version of drm_vblank_count().
+ *
+ * Returns:
+ * The software vblank counter.
+ */
+u32 drm_crtc_vblank_count(struct drm_crtc *crtc)
+{
+       return drm_vblank_count(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_vblank_count);
+
 /**
  * drm_vblank_count_and_time - retrieve "cooked" vblank counter value
  * and the system timestamp corresponding to that vblank counter value.
@@ -904,6 +925,8 @@ static void send_vblank_event(struct drm_device *dev,
  *
  * Updates sequence # and timestamp on event, and sends it to userspace.
  * Caller must hold event lock.
+ *
+ * This is the legacy version of drm_crtc_send_vblank_event().
  */
 void drm_send_vblank_event(struct drm_device *dev, int crtc,
                struct drm_pending_vblank_event *e)
@@ -922,6 +945,23 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
 }
 EXPORT_SYMBOL(drm_send_vblank_event);
 
+/**
+ * drm_crtc_send_vblank_event - helper to send vblank event after pageflip
+ * @crtc: the source CRTC of the vblank event
+ * @e: the event to send
+ *
+ * Updates sequence # and timestamp on event, and sends it to userspace.
+ * Caller must hold event lock.
+ *
+ * This is the native KMS version of drm_send_vblank_event().
+ */
+void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
+                               struct drm_pending_vblank_event *e)
+{
+       drm_send_vblank_event(crtc->dev, drm_crtc_index(crtc), e);
+}
+EXPORT_SYMBOL(drm_crtc_send_vblank_event);
+
 /**
  * drm_vblank_enable - enable the vblank interrupt on a CRTC
  * @dev: DRM device
@@ -1594,6 +1634,8 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
  *
  * Drivers should call this routine in their vblank interrupt handlers to
  * update the vblank counter and send any signals that may be pending.
+ *
+ * This is the legacy version of drm_crtc_handle_vblank().
  */
 bool drm_handle_vblank(struct drm_device *dev, int crtc)
 {
@@ -1670,3 +1712,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
        return true;
 }
 EXPORT_SYMBOL(drm_handle_vblank);
+
+/**
+ * drm_crtc_handle_vblank - handle a vblank event
+ * @crtc: where this event occurred
+ *
+ * Drivers should call this routine in their vblank interrupt handlers to
+ * update the vblank counter and send any signals that may be pending.
+ *
+ * This is the native KMS version of drm_handle_vblank().
+ *
+ * Returns:
+ * True if the event was successfully handled, false on failure.
+ */
+bool drm_crtc_handle_vblank(struct drm_crtc *crtc)
+{
+       return drm_handle_vblank(crtc->dev, drm_crtc_index(crtc));
+}
+EXPORT_SYMBOL(drm_crtc_handle_vblank);
index 121470a83d1a497a61a19fe5cd09f769140efac9..1bcbe07cecfc9541a2eba9415c227ae17a9c0449 100644 (file)
@@ -645,18 +645,6 @@ static int exynos_drm_init(void)
        if (!is_exynos)
                return -ENODEV;
 
-       /*
-        * Register device object only in case of Exynos SoC.
-        *
-        * Below codes resolves temporarily infinite loop issue incurred
-        * by Exynos drm driver when using multi-platform kernel.
-        * So these codes will be replaced with more generic way later.
-        */
-       if (!of_machine_is_compatible("samsung,exynos3") &&
-                       !of_machine_is_compatible("samsung,exynos4") &&
-                       !of_machine_is_compatible("samsung,exynos5"))
-               return -ENODEV;
-
        exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
                                                                NULL, 0);
        if (IS_ERR(exynos_drm_pdev))
index 5765a161abdd4b35c958086ad9fdf996b146dbc1..98051e8e855a1f07e8d5ef1e21995eb9783c1a1b 100644 (file)
@@ -1669,7 +1669,6 @@ static void hdmi_mode_apply(struct hdmi_context *hdata)
 
 static void hdmiphy_conf_reset(struct hdmi_context *hdata)
 {
-       u8 buffer[2];
        u32 reg;
 
        clk_disable_unprepare(hdata->res.sclk_hdmi);
@@ -1677,11 +1676,8 @@ static void hdmiphy_conf_reset(struct hdmi_context *hdata)
        clk_prepare_enable(hdata->res.sclk_hdmi);
 
        /* operation mode */
-       buffer[0] = 0x1f;
-       buffer[1] = 0x00;
-
-       if (hdata->hdmiphy_port)
-               i2c_master_send(hdata->hdmiphy_port, buffer, 2);
+       hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
+                               HDMI_PHY_ENABLE_MODE_SET);
 
        if (hdata->type == HDMI_TYPE13)
                reg = HDMI_V13_PHY_RSTOUT;
index 820b76234ef4c5c6da02ebe50327066c5fe38d1a..064ed6597defefad5a2efa3bba63ba55f5551c13 100644 (file)
@@ -1026,6 +1026,7 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
        struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+       int err;
 
        mutex_lock(&mixer_ctx->mixer_mutex);
        if (!mixer_ctx->powered) {
@@ -1034,7 +1035,11 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
        }
        mutex_unlock(&mixer_ctx->mixer_mutex);
 
-       drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
+       err = drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
+       if (err < 0) {
+               DRM_DEBUG_KMS("failed to acquire vblank counter\n");
+               return;
+       }
 
        atomic_set(&mixer_ctx->wait_vsync_event, 1);
 
@@ -1262,8 +1267,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
                return ret;
        }
 
-       pm_runtime_enable(dev);
-
        return 0;
 }
 
@@ -1272,8 +1275,6 @@ static void mixer_unbind(struct device *dev, struct device *master, void *data)
        struct mixer_context *ctx = dev_get_drvdata(dev);
 
        mixer_mgr_remove(&ctx->manager);
-
-       pm_runtime_disable(dev);
 }
 
 static const struct component_ops mixer_component_ops = {
index d4762799351d9d5e67efbce0987e10c0e974939c..a9041d1a8ff002f332705db5d80082761788ad19 100644 (file)
@@ -32,6 +32,8 @@
 struct tda998x_priv {
        struct i2c_client *cec;
        struct i2c_client *hdmi;
+       struct mutex mutex;
+       struct delayed_work dwork;
        uint16_t rev;
        uint8_t current_page;
        int dpms;
@@ -402,9 +404,10 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt)
        uint8_t addr = REG2ADDR(reg);
        int ret;
 
+       mutex_lock(&priv->mutex);
        ret = set_page(priv, reg);
        if (ret < 0)
-               return ret;
+               goto out;
 
        ret = i2c_master_send(client, &addr, sizeof(addr));
        if (ret < 0)
@@ -414,10 +417,12 @@ reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt)
        if (ret < 0)
                goto fail;
 
-       return ret;
+       goto out;
 
 fail:
        dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg);
+out:
+       mutex_unlock(&priv->mutex);
        return ret;
 }
 
@@ -431,13 +436,16 @@ reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt)
        buf[0] = REG2ADDR(reg);
        memcpy(&buf[1], p, cnt);
 
+       mutex_lock(&priv->mutex);
        ret = set_page(priv, reg);
        if (ret < 0)
-               return;
+               goto out;
 
        ret = i2c_master_send(client, buf, cnt + 1);
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
+out:
+       mutex_unlock(&priv->mutex);
 }
 
 static int
@@ -459,13 +467,16 @@ reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
        uint8_t buf[] = {REG2ADDR(reg), val};
        int ret;
 
+       mutex_lock(&priv->mutex);
        ret = set_page(priv, reg);
        if (ret < 0)
-               return;
+               goto out;
 
        ret = i2c_master_send(client, buf, sizeof(buf));
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
+out:
+       mutex_unlock(&priv->mutex);
 }
 
 static void
@@ -475,13 +486,16 @@ reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val)
        uint8_t buf[] = {REG2ADDR(reg), val >> 8, val};
        int ret;
 
+       mutex_lock(&priv->mutex);
        ret = set_page(priv, reg);
        if (ret < 0)
-               return;
+               goto out;
 
        ret = i2c_master_send(client, buf, sizeof(buf));
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
+out:
+       mutex_unlock(&priv->mutex);
 }
 
 static void
@@ -536,6 +550,17 @@ tda998x_reset(struct tda998x_priv *priv)
        reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
 }
 
+/* handle HDMI connect/disconnect */
+static void tda998x_hpd(struct work_struct *work)
+{
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct tda998x_priv *priv =
+                       container_of(dwork, struct tda998x_priv, dwork);
+
+       if (priv->encoder && priv->encoder->dev)
+               drm_kms_helper_hotplug_event(priv->encoder->dev);
+}
+
 /*
  * only 2 interrupts may occur: screen plug/unplug and EDID read
  */
@@ -559,8 +584,7 @@ static irqreturn_t tda998x_irq_thread(int irq, void *data)
                priv->wq_edid_wait = 0;
                wake_up(&priv->wq_edid);
        } else if (cec != 0) {                  /* HPD change */
-               if (priv->encoder && priv->encoder->dev)
-                       drm_helper_hpd_irq_event(priv->encoder->dev);
+               schedule_delayed_work(&priv->dwork, HZ/10);
        }
        return IRQ_HANDLED;
 }
@@ -1170,8 +1194,10 @@ static void tda998x_destroy(struct tda998x_priv *priv)
        /* disable all IRQs and free the IRQ handler */
        cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
        reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
-       if (priv->hdmi->irq)
+       if (priv->hdmi->irq) {
                free_irq(priv->hdmi->irq, priv);
+               cancel_delayed_work_sync(&priv->dwork);
+       }
 
        i2c_unregister_device(priv->cec);
 }
@@ -1255,6 +1281,7 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
        struct device_node *np = client->dev.of_node;
        u32 video;
        int rev_lo, rev_hi, ret;
+       unsigned short cec_addr;
 
        priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3);
        priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1);
@@ -1262,12 +1289,16 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
 
        priv->current_page = 0xff;
        priv->hdmi = client;
-       priv->cec = i2c_new_dummy(client->adapter, 0x34);
+       /* CEC I2C address bound to TDA998x I2C addr by configuration pins */
+       cec_addr = 0x34 + (client->addr & 0x03);
+       priv->cec = i2c_new_dummy(client->adapter, cec_addr);
        if (!priv->cec)
                return -ENODEV;
 
        priv->dpms = DRM_MODE_DPMS_OFF;
 
+       mutex_init(&priv->mutex);       /* protect the page access */
+
        /* wake up the device: */
        cec_write(priv, REG_CEC_ENAMODS,
                        CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI);
@@ -1323,8 +1354,9 @@ static int tda998x_create(struct i2c_client *client, struct tda998x_priv *priv)
        if (client->irq) {
                int irqf_trigger;
 
-               /* init read EDID waitqueue */
+               /* init read EDID waitqueue and HDP work */
                init_waitqueue_head(&priv->wq_edid);
+               INIT_DELAYED_WORK(&priv->dwork, tda998x_hpd);
 
                /* clear pending interrupts */
                reg_read(priv, REG_INT_FLAGS_0);
index f990ab4c3efbfbe1f91f15cc89eda8b5eb0fa64d..7643300828c3aef79d32260af5f2c8e4c7ff5b2c 100644 (file)
@@ -462,19 +462,13 @@ void intel_detect_pch(struct drm_device *dev)
                        } else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_LPT;
                                DRM_DEBUG_KMS("Found LynxPoint PCH\n");
-                               WARN_ON(!IS_HASWELL(dev));
-                               WARN_ON(IS_HSW_ULT(dev));
-                       } else if (IS_BROADWELL(dev)) {
-                               dev_priv->pch_type = PCH_LPT;
-                               dev_priv->pch_id =
-                                       INTEL_PCH_LPT_LP_DEVICE_ID_TYPE;
-                               DRM_DEBUG_KMS("This is Broadwell, assuming "
-                                             "LynxPoint LP PCH\n");
+                               WARN_ON(!IS_HASWELL(dev) && !IS_BROADWELL(dev));
+                               WARN_ON(IS_HSW_ULT(dev) || IS_BDW_ULT(dev));
                        } else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_LPT;
                                DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
-                               WARN_ON(!IS_HASWELL(dev));
-                               WARN_ON(!IS_HSW_ULT(dev));
+                               WARN_ON(!IS_HASWELL(dev) && !IS_BROADWELL(dev));
+                               WARN_ON(!IS_HSW_ULT(dev) && !IS_BDW_ULT(dev));
                        } else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) {
                                dev_priv->pch_type = PCH_SPT;
                                DRM_DEBUG_KMS("Found SunrisePoint PCH\n");
@@ -811,6 +805,8 @@ int i915_reset(struct drm_device *dev)
        if (!i915.reset)
                return 0;
 
+       intel_reset_gt_powersave(dev);
+
        mutex_lock(&dev->struct_mutex);
 
        i915_gem_reset(dev);
@@ -880,7 +876,7 @@ int i915_reset(struct drm_device *dev)
                 * of re-init after reset.
                 */
                if (INTEL_INFO(dev)->gen > 5)
-                       intel_reset_gt_powersave(dev);
+                       intel_enable_gt_powersave(dev);
        } else {
                mutex_unlock(&dev->struct_mutex);
        }
@@ -1584,7 +1580,7 @@ static struct drm_driver driver = {
        .gem_prime_import = i915_gem_prime_import,
 
        .dumb_create = i915_gem_dumb_create,
-       .dumb_map_offset = i915_gem_dumb_map_offset,
+       .dumb_map_offset = i915_gem_mmap_gtt,
        .dumb_destroy = drm_gem_dumb_destroy,
        .ioctls = i915_ioctls,
        .fops = &i915_driver_fops,
index 63bcda5541ecad36179cf72491293694154b1a3e..9d7a7155bf02a6f9fb44d504e69e635fefcc9c2e 100644 (file)
@@ -1756,8 +1756,6 @@ struct drm_i915_private {
         */
        struct workqueue_struct *dp_wq;
 
-       uint32_t bios_vgacntr;
-
        /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
        struct {
                int (*do_execbuf)(struct drm_device *dev, struct drm_file *file,
@@ -2161,8 +2159,7 @@ struct drm_i915_cmd_table {
 #define IS_HSW_EARLY_SDV(dev)  (IS_HASWELL(dev) && \
                                 (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
 #define IS_BDW_ULT(dev)                (IS_BROADWELL(dev) && \
-                                ((INTEL_DEVID(dev) & 0xf) == 0x2  || \
-                                (INTEL_DEVID(dev) & 0xf) == 0x6 || \
+                                ((INTEL_DEVID(dev) & 0xf) == 0x6 ||    \
                                 (INTEL_DEVID(dev) & 0xf) == 0xe))
 #define IS_BDW_GT3(dev)                (IS_BROADWELL(dev) && \
                                 (INTEL_DEVID(dev) & 0x00F0) == 0x0020)
@@ -2501,9 +2498,8 @@ void i915_vma_move_to_active(struct i915_vma *vma,
 int i915_gem_dumb_create(struct drm_file *file_priv,
                         struct drm_device *dev,
                         struct drm_mode_create_dumb *args);
-int i915_gem_dumb_map_offset(struct drm_file *file_priv,
-                            struct drm_device *dev, uint32_t handle,
-                            uint64_t *offset);
+int i915_gem_mmap_gtt(struct drm_file *file_priv, struct drm_device *dev,
+                     uint32_t handle, uint64_t *offset);
 /**
  * Returns true if seq1 is later than seq2.
  */
index 4a9faea626dbf64eec08bf257b6d8a68fe7a7513..5f614828d365555f70005aff470117ab15b3ae12 100644 (file)
@@ -401,7 +401,6 @@ static int
 i915_gem_create(struct drm_file *file,
                struct drm_device *dev,
                uint64_t size,
-               bool dumb,
                uint32_t *handle_p)
 {
        struct drm_i915_gem_object *obj;
@@ -417,7 +416,6 @@ i915_gem_create(struct drm_file *file,
        if (obj == NULL)
                return -ENOMEM;
 
-       obj->base.dumb = dumb;
        ret = drm_gem_handle_create(file, &obj->base, &handle);
        /* drop reference from allocate - handle holds it now */
        drm_gem_object_unreference_unlocked(&obj->base);
@@ -437,7 +435,7 @@ i915_gem_dumb_create(struct drm_file *file,
        args->pitch = ALIGN(args->width * DIV_ROUND_UP(args->bpp, 8), 64);
        args->size = args->pitch * args->height;
        return i915_gem_create(file, dev,
-                              args->size, true, &args->handle);
+                              args->size, &args->handle);
 }
 
 /**
@@ -450,7 +448,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_create *args = data;
 
        return i915_gem_create(file, dev,
-                              args->size, false, &args->handle);
+                              args->size, &args->handle);
 }
 
 static inline int
@@ -1050,6 +1048,7 @@ int
 i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                      struct drm_file *file)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_pwrite *args = data;
        struct drm_i915_gem_object *obj;
        int ret;
@@ -1069,9 +1068,11 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                        return -EFAULT;
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
-               return ret;
+               goto put_rpm;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
        if (&obj->base == NULL) {
@@ -1123,6 +1124,9 @@ out:
        drm_gem_object_unreference(&obj->base);
 unlock:
        mutex_unlock(&dev->struct_mutex);
+put_rpm:
+       intel_runtime_pm_put(dev_priv);
+
        return ret;
 }
 
@@ -1840,10 +1844,10 @@ static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
        drm_gem_free_mmap_offset(&obj->base);
 }
 
-static int
+int
 i915_gem_mmap_gtt(struct drm_file *file,
                  struct drm_device *dev,
-                 uint32_t handle, bool dumb,
+                 uint32_t handle,
                  uint64_t *offset)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1860,13 +1864,6 @@ i915_gem_mmap_gtt(struct drm_file *file,
                goto unlock;
        }
 
-       /*
-        * We don't allow dumb mmaps on objects created using another
-        * interface.
-        */
-       WARN_ONCE(dumb && !(obj->base.dumb || obj->base.import_attach),
-                 "Illegal dumb map of accelerated buffer.\n");
-
        if (obj->base.size > dev_priv->gtt.mappable_end) {
                ret = -E2BIG;
                goto out;
@@ -1891,15 +1888,6 @@ unlock:
        return ret;
 }
 
-int
-i915_gem_dumb_map_offset(struct drm_file *file,
-                        struct drm_device *dev,
-                        uint32_t handle,
-                        uint64_t *offset)
-{
-       return i915_gem_mmap_gtt(file, dev, handle, true, offset);
-}
-
 /**
  * i915_gem_mmap_gtt_ioctl - prepare an object for GTT mmap'ing
  * @dev: DRM device
@@ -1921,7 +1909,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 {
        struct drm_i915_gem_mmap_gtt *args = data;
 
-       return i915_gem_mmap_gtt(file, dev, args->handle, false, &args->offset);
+       return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
 }
 
 static inline int
@@ -3160,6 +3148,13 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
                u32 size = i915_gem_obj_ggtt_size(obj);
                uint64_t val;
 
+               /* Adjust fence size to match tiled area */
+               if (obj->tiling_mode != I915_TILING_NONE) {
+                       uint32_t row_size = obj->stride *
+                               (obj->tiling_mode == I915_TILING_Y ? 32 : 8);
+                       size = (size / row_size) * row_size;
+               }
+
                val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
                                 0xfffff000) << 32;
                val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000;
@@ -4896,25 +4891,18 @@ i915_gem_init_hw(struct drm_device *dev)
        for (i = 0; i < NUM_L3_SLICES(dev); i++)
                i915_gem_l3_remap(&dev_priv->ring[RCS], i);
 
-       /*
-        * XXX: Contexts should only be initialized once. Doing a switch to the
-        * default context switch however is something we'd like to do after
-        * reset or thaw (the latter may not actually be necessary for HW, but
-        * goes with our code better). Context switching requires rings (for
-        * the do_switch), but before enabling PPGTT. So don't move this.
-        */
-       ret = i915_gem_context_enable(dev_priv);
+       ret = i915_ppgtt_init_hw(dev);
        if (ret && ret != -EIO) {
-               DRM_ERROR("Context enable failed %d\n", ret);
+               DRM_ERROR("PPGTT enable failed %d\n", ret);
                i915_gem_cleanup_ringbuffer(dev);
-
-               return ret;
        }
 
-       ret = i915_ppgtt_init_hw(dev);
+       ret = i915_gem_context_enable(dev_priv);
        if (ret && ret != -EIO) {
-               DRM_ERROR("PPGTT enable failed %d\n", ret);
+               DRM_ERROR("Context enable failed %d\n", ret);
                i915_gem_cleanup_ringbuffer(dev);
+
+               return ret;
        }
 
        return ret;
@@ -5167,7 +5155,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
        if (!mutex_is_locked(mutex))
                return false;
 
-#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
+#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
        return mutex->owner == task;
 #else
        /* Since UP may be pre-empted, we cannot assume that we own the lock */
index d17ff435f2767fa31c51ed08ef5e3130aa4dddbd..d011ec82ef1ebfbb37b3c903f9d77b7e503a30f0 100644 (file)
@@ -473,7 +473,12 @@ mi_set_context(struct intel_engine_cs *ring,
               u32 hw_flags)
 {
        u32 flags = hw_flags | MI_MM_SPACE_GTT;
-       int ret;
+       const int num_rings =
+               /* Use an extended w/a on ivb+ if signalling from other rings */
+               i915_semaphore_is_enabled(ring->dev) ?
+               hweight32(INTEL_INFO(ring->dev)->ring_mask) - 1 :
+               0;
+       int len, i, ret;
 
        /* w/a: If Flush TLB Invalidation Mode is enabled, driver must do a TLB
         * invalidation prior to MI_SET_CONTEXT. On GEN6 we don't set the value
@@ -490,15 +495,31 @@ mi_set_context(struct intel_engine_cs *ring,
        if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8)
                flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN);
 
-       ret = intel_ring_begin(ring, 6);
+
+       len = 4;
+       if (INTEL_INFO(ring->dev)->gen >= 7)
+               len += 2 + (num_rings ? 4*num_rings + 2 : 0);
+
+       ret = intel_ring_begin(ring, len);
        if (ret)
                return ret;
 
        /* WaProgramMiArbOnOffAroundMiSetContext:ivb,vlv,hsw,bdw,chv */
-       if (INTEL_INFO(ring->dev)->gen >= 7)
+       if (INTEL_INFO(ring->dev)->gen >= 7) {
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
-       else
-               intel_ring_emit(ring, MI_NOOP);
+               if (num_rings) {
+                       struct intel_engine_cs *signaller;
+
+                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
+                       for_each_ring(signaller, to_i915(ring->dev), i) {
+                               if (signaller == ring)
+                                       continue;
+
+                               intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+                               intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+                       }
+               }
+       }
 
        intel_ring_emit(ring, MI_NOOP);
        intel_ring_emit(ring, MI_SET_CONTEXT);
@@ -510,10 +531,21 @@ mi_set_context(struct intel_engine_cs *ring,
         */
        intel_ring_emit(ring, MI_NOOP);
 
-       if (INTEL_INFO(ring->dev)->gen >= 7)
+       if (INTEL_INFO(ring->dev)->gen >= 7) {
+               if (num_rings) {
+                       struct intel_engine_cs *signaller;
+
+                       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(num_rings));
+                       for_each_ring(signaller, to_i915(ring->dev), i) {
+                               if (signaller == ring)
+                                       continue;
+
+                               intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base));
+                               intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE));
+                       }
+               }
                intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
-       else
-               intel_ring_emit(ring, MI_NOOP);
+       }
 
        intel_ring_advance(ring);
 
index f06027ba3ee5512a7718deb22112f9fe6e16458b..11738316394af9b16669155dbbec74fde0f22223 100644 (file)
@@ -121,9 +121,6 @@ eb_lookup_vmas(struct eb_vmas *eb,
                        goto err;
                }
 
-               WARN_ONCE(obj->base.dumb,
-                         "GPU use of dumb buffer is illegal.\n");
-
                drm_gem_object_reference(&obj->base);
                list_add_tail(&obj->obj_exec_link, &objects);
        }
index 981834b0f9b6309b4f09911c4406a58fadbe0287..b051a238baf9338cb3e47a57ae31d6f1b540d006 100644 (file)
@@ -281,13 +281,34 @@ void gen6_enable_rps_interrupts(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        spin_lock_irq(&dev_priv->irq_lock);
+
        WARN_ON(dev_priv->rps.pm_iir);
        WARN_ON(I915_READ(gen6_pm_iir(dev_priv)) & dev_priv->pm_rps_events);
        dev_priv->rps.interrupts_enabled = true;
+       I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) |
+                               dev_priv->pm_rps_events);
        gen6_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+
        spin_unlock_irq(&dev_priv->irq_lock);
 }
 
+u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask)
+{
+       /*
+        * SNB,IVB can while VLV,CHV may hard hang on looping batchbuffer
+        * if GEN6_PM_UP_EI_EXPIRED is masked.
+        *
+        * TODO: verify if this can be reproduced on VLV,CHV.
+        */
+       if (INTEL_INFO(dev_priv)->gen <= 7 && !IS_HASWELL(dev_priv))
+               mask &= ~GEN6_PM_RP_UP_EI_EXPIRED;
+
+       if (INTEL_INFO(dev_priv)->gen >= 8)
+               mask &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+
+       return mask;
+}
+
 void gen6_disable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -300,8 +321,7 @@ void gen6_disable_rps_interrupts(struct drm_device *dev)
 
        spin_lock_irq(&dev_priv->irq_lock);
 
-       I915_WRITE(GEN6_PMINTRMSK, INTEL_INFO(dev_priv)->gen >= 8 ?
-                  ~GEN8_PMINTR_REDIRECT_TO_NON_DISP : ~0);
+       I915_WRITE(GEN6_PMINTRMSK, gen6_sanitize_rps_pm_mask(dev_priv, ~0));
 
        __gen6_disable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        I915_WRITE(gen6_pm_ier(dev_priv), I915_READ(gen6_pm_ier(dev_priv)) &
@@ -3307,8 +3327,10 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
        GEN5_IRQ_INIT(GT, dev_priv->gt_irq_mask, gt_irqs);
 
        if (INTEL_INFO(dev)->gen >= 6) {
-               pm_irqs |= dev_priv->pm_rps_events;
-
+               /*
+                * RPS interrupts will get enabled/disabled on demand when RPS
+                * itself is enabled/disabled.
+                */
                if (HAS_VEBOX(dev))
                        pm_irqs |= PM_VEBOX_USER_INTERRUPT;
 
@@ -3520,7 +3542,11 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
        dev_priv->pm_irq_mask = 0xffffffff;
        GEN8_IRQ_INIT_NDX(GT, 0, ~gt_interrupts[0], gt_interrupts[0]);
        GEN8_IRQ_INIT_NDX(GT, 1, ~gt_interrupts[1], gt_interrupts[1]);
-       GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, dev_priv->pm_rps_events);
+       /*
+        * RPS interrupts will get enabled/disabled on demand when RPS itself
+        * is enabled/disabled.
+        */
+       GEN8_IRQ_INIT_NDX(GT, 2, dev_priv->pm_irq_mask, 0);
        GEN8_IRQ_INIT_NDX(GT, 3, ~gt_interrupts[3], gt_interrupts[3]);
 }
 
@@ -3609,7 +3635,7 @@ static void vlv_display_irq_uninstall(struct drm_i915_private *dev_priv)
 
        vlv_display_irq_reset(dev_priv);
 
-       dev_priv->irq_mask = 0;
+       dev_priv->irq_mask = ~0;
 }
 
 static void valleyview_irq_uninstall(struct drm_device *dev)
@@ -3715,8 +3741,6 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
        if ((iir & flip_pending) == 0)
                goto check_page_flip;
 
-       intel_prepare_page_flip(dev, plane);
-
        /* We detect FlipDone by looking for the change in PendingFlip from '1'
         * to '0' on the following vblank, i.e. IIR has the Pendingflip
         * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
@@ -3726,6 +3750,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
        if (I915_READ16(ISR) & flip_pending)
                goto check_page_flip;
 
+       intel_prepare_page_flip(dev, plane);
        intel_finish_page_flip(dev, pipe);
        return true;
 
@@ -3897,8 +3922,6 @@ static bool i915_handle_vblank(struct drm_device *dev,
        if ((iir & flip_pending) == 0)
                goto check_page_flip;
 
-       intel_prepare_page_flip(dev, plane);
-
        /* We detect FlipDone by looking for the change in PendingFlip from '1'
         * to '0' on the following vblank, i.e. IIR has the Pendingflip
         * asserted following the MI_DISPLAY_FLIP, but ISR is deasserted, hence
@@ -3908,6 +3931,7 @@ static bool i915_handle_vblank(struct drm_device *dev,
        if (I915_READ(ISR) & flip_pending)
                goto check_page_flip;
 
+       intel_prepare_page_flip(dev, plane);
        intel_finish_page_flip(dev, pipe);
        return true;
 
index eefdc238f70bd691d584f6d32b5d055f8d1546a5..172de3b3433b20b57d7e57f31ad63d3daa09bba3 100644 (file)
 #define   PIPE_CONTROL_STORE_DATA_INDEX                        (1<<21)
 #define   PIPE_CONTROL_CS_STALL                                (1<<20)
 #define   PIPE_CONTROL_TLB_INVALIDATE                  (1<<18)
+#define   PIPE_CONTROL_MEDIA_STATE_CLEAR               (1<<16)
 #define   PIPE_CONTROL_QW_WRITE                                (1<<14)
 #define   PIPE_CONTROL_POST_SYNC_OP_MASK                (3<<14)
 #define   PIPE_CONTROL_DEPTH_STALL                     (1<<13)
@@ -1128,6 +1129,7 @@ enum punit_power_well {
 #define GEN6_VERSYNC   (RING_SYNC_1(VEBOX_RING_BASE))
 #define GEN6_VEVSYNC   (RING_SYNC_2(VEBOX_RING_BASE))
 #define GEN6_NOSYNC 0
+#define RING_PSMI_CTL(base)    ((base)+0x50)
 #define RING_MAX_IDLE(base)    ((base)+0x54)
 #define RING_HWS_PGA(base)     ((base)+0x80)
 #define RING_HWS_PGA_GEN6(base)        ((base)+0x2080)
@@ -1458,6 +1460,7 @@ enum punit_power_well {
 #define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
 
 #define GEN6_RC_SLEEP_PSMI_CONTROL     0x2050
+#define   GEN6_PSMI_SLEEP_MSG_DISABLE  (1 << 0)
 #define   GEN8_RC_SEMA_IDLE_MSG_DISABLE        (1 << 12)
 #define   GEN8_FF_DOP_CLOCK_GATE_DISABLE       (1<<10)
 
index fb3e3d429191247c5041af8ca0212c6ce1e2f705..e7a16f119a294d0d20d0afa832d6d0b2a803edd7 100644 (file)
@@ -9815,7 +9815,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                if (obj->tiling_mode != work->old_fb_obj->tiling_mode)
                        /* vlv: DISPLAY_FLIP fails to change tiling */
                        ring = NULL;
-       } else if (IS_IVYBRIDGE(dev)) {
+       } else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
                ring = &dev_priv->ring[BCS];
        } else if (INTEL_INFO(dev)->gen >= 7) {
                ring = obj->ring;
@@ -13057,11 +13057,7 @@ static void i915_disable_vga(struct drm_device *dev)
        vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
        udelay(300);
 
-       /*
-        * Fujitsu-Siemens Lifebook S6010 (830) has problems resuming
-        * from S3 without preserving (some of?) the other bits.
-        */
-       I915_WRITE(vga_reg, dev_priv->bios_vgacntr | VGA_DISP_DISABLE);
+       I915_WRITE(vga_reg, VGA_DISP_DISABLE);
        POSTING_READ(vga_reg);
 }
 
@@ -13146,8 +13142,6 @@ void intel_modeset_init(struct drm_device *dev)
 
        intel_shared_dpll_init(dev);
 
-       /* save the BIOS value before clobbering it */
-       dev_priv->bios_vgacntr = I915_READ(i915_vgacntrl_reg(dev));
        /* Just disable it once at startup */
        i915_disable_vga(dev);
        intel_setup_outputs(dev);
index 25fdbb16d4e0defa47f660d2f2a940582b83608f..3b40a17b8852fa7d3ff0519a37baef85c09f467b 100644 (file)
@@ -794,6 +794,7 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void gen6_reset_rps_interrupts(struct drm_device *dev);
 void gen6_enable_rps_interrupts(struct drm_device *dev);
 void gen6_disable_rps_interrupts(struct drm_device *dev);
+u32 gen6_sanitize_rps_pm_mask(struct drm_i915_private *dev_priv, u32 mask);
 void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv);
 void intel_runtime_pm_enable_interrupts(struct drm_i915_private *dev_priv);
 static inline bool intel_irqs_enabled(struct drm_i915_private *dev_priv)
index 4d63839bd9b4c53be99842c38188331f8e7817c7..dfb783a8f2c36e05bc08abfe21a1272c2903a69f 100644 (file)
@@ -962,7 +962,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
 
        WARN_ON(panel->backlight.max == 0);
 
-       if (panel->backlight.level == 0) {
+       if (panel->backlight.level <= panel->backlight.min) {
                panel->backlight.level = panel->backlight.max;
                if (panel->backlight.device)
                        panel->backlight.device->props.brightness =
index 1f4b56e273c811a7c33149e927985b3f973ac4b3..bf814a64582a3eee53964ce4a8f4a62913b860a7 100644 (file)
@@ -4363,16 +4363,7 @@ static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
        mask |= dev_priv->pm_rps_events & (GEN6_PM_RP_DOWN_EI_EXPIRED | GEN6_PM_RP_UP_EI_EXPIRED);
        mask &= dev_priv->pm_rps_events;
 
-       /* IVB and SNB hard hangs on looping batchbuffer
-        * if GEN6_PM_UP_EI_EXPIRED is masked.
-        */
-       if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
-               mask |= GEN6_PM_RP_UP_EI_EXPIRED;
-
-       if (IS_GEN8(dev_priv->dev))
-               mask |= GEN8_PMINTR_REDIRECT_TO_NON_DISP;
-
-       return ~mask;
+       return gen6_sanitize_rps_pm_mask(dev_priv, ~mask);
 }
 
 /* gen6_set_rps is called to update the frequency request, but should also be
@@ -4441,7 +4432,8 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
                return;
 
        /* Mask turbo interrupt so that they will not come in between */
-       I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+       I915_WRITE(GEN6_PMINTRMSK,
+                  gen6_sanitize_rps_pm_mask(dev_priv, ~0));
 
        vlv_force_gfx_clock(dev_priv, true);
 
@@ -6191,6 +6183,20 @@ void intel_cleanup_gt_powersave(struct drm_device *dev)
                valleyview_cleanup_gt_powersave(dev);
 }
 
+static void gen6_suspend_rps(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+       /*
+        * TODO: disable RPS interrupts on GEN9+ too once RPS support
+        * is added for it.
+        */
+       if (INTEL_INFO(dev)->gen < 9)
+               gen6_disable_rps_interrupts(dev);
+}
+
 /**
  * intel_suspend_gt_powersave - suspend PM work and helper threads
  * @dev: drm device
@@ -6206,14 +6212,7 @@ void intel_suspend_gt_powersave(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6)
                return;
 
-       flush_delayed_work(&dev_priv->rps.delayed_resume_work);
-
-       /*
-        * TODO: disable RPS interrupts on GEN9+ too once RPS support
-        * is added for it.
-        */
-       if (INTEL_INFO(dev)->gen < 9)
-               gen6_disable_rps_interrupts(dev);
+       gen6_suspend_rps(dev);
 
        /* Force GPU to min freq during suspend */
        gen6_rps_idle(dev_priv);
@@ -6316,8 +6315,11 @@ void intel_reset_gt_powersave(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
+       if (INTEL_INFO(dev)->gen < 6)
+               return;
+
+       gen6_suspend_rps(dev);
        dev_priv->rps.enabled = false;
-       intel_enable_gt_powersave(dev);
 }
 
 static void ibx_init_clock_gating(struct drm_device *dev)
index 9f445e9a75d1a1788669ab2969a2d769cf7d204e..c7bc93d28d84ec4356c0c5f5c4e4cd67296df709 100644 (file)
@@ -362,12 +362,15 @@ gen7_render_ring_flush(struct intel_engine_cs *ring,
                flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
                flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR;
                /*
                 * TLB invalidate requires a post-sync write.
                 */
                flags |= PIPE_CONTROL_QW_WRITE;
                flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
 
+               flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD;
+
                /* Workaround: we must issue a pipe_control with CS-stall bit
                 * set before a pipe_control command that has the state cache
                 * invalidate bit set. */
index f5a78d53e2978ed1c4f25cdaa73d9fcb0ca887bb..ac6da7102fbbdc53c74e584234c51506191da1ee 100644 (file)
@@ -615,29 +615,6 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv,
                vlv_power_sequencer_reset(dev_priv);
 }
 
-static void check_power_well_state(struct drm_i915_private *dev_priv,
-                                  struct i915_power_well *power_well)
-{
-       bool enabled = power_well->ops->is_enabled(dev_priv, power_well);
-
-       if (power_well->always_on || !i915.disable_power_well) {
-               if (!enabled)
-                       goto mismatch;
-
-               return;
-       }
-
-       if (enabled != (power_well->count > 0))
-               goto mismatch;
-
-       return;
-
-mismatch:
-       WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n",
-                 power_well->name, power_well->always_on, enabled,
-                 power_well->count, i915.disable_power_well);
-}
-
 /**
  * intel_display_power_get - grab a power domain reference
  * @dev_priv: i915 device instance
@@ -669,8 +646,6 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
                        power_well->ops->enable(dev_priv, power_well);
                        power_well->hw_enabled = true;
                }
-
-               check_power_well_state(dev_priv, power_well);
        }
 
        power_domains->domain_use_count[domain]++;
@@ -709,8 +684,6 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
                        power_well->hw_enabled = false;
                        power_well->ops->disable(dev_priv, power_well);
                }
-
-               check_power_well_state(dev_priv, power_well);
        }
 
        mutex_unlock(&power_domains->lock);
index aa873048308b8e6e3e431152963aed5b04c13f02..94a5bee69fe724c94542bc5181e4309e78b78300 100644 (file)
@@ -386,9 +386,7 @@ void adreno_gpu_cleanup(struct adreno_gpu *gpu)
                        msm_gem_put_iova(gpu->memptrs_bo, gpu->base.id);
                drm_gem_object_unreference(gpu->memptrs_bo);
        }
-       if (gpu->pm4)
-               release_firmware(gpu->pm4);
-       if (gpu->pfp)
-               release_firmware(gpu->pfp);
+       release_firmware(gpu->pm4);
+       release_firmware(gpu->pfp);
        msm_gpu_cleanup(&gpu->base);
 }
index fbebb0405d76d7df217c1772a26cc43e78578b29..b4e70e0e3cfa603b1ee8bbf393dd07402c96fbbb 100644 (file)
@@ -141,6 +141,15 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
        uint32_t hpd_ctrl;
        int i, ret;
 
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_enable(hdmi->hpd_regs[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+                       goto fail;
+               }
+       }
+
        ret = gpio_config(hdmi, true);
        if (ret) {
                dev_err(dev->dev, "failed to configure GPIOs: %d\n", ret);
@@ -164,15 +173,6 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
                }
        }
 
-       for (i = 0; i < config->hpd_reg_cnt; i++) {
-               ret = regulator_enable(hdmi->hpd_regs[i]);
-               if (ret) {
-                       dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
-                                       config->hpd_reg_names[i], ret);
-                       goto fail;
-               }
-       }
-
        hdmi_set_mode(hdmi, false);
        phy->funcs->reset(phy);
        hdmi_set_mode(hdmi, true);
@@ -200,7 +200,7 @@ fail:
        return ret;
 }
 
-static int hdp_disable(struct hdmi_connector *hdmi_connector)
+static void hdp_disable(struct hdmi_connector *hdmi_connector)
 {
        struct hdmi *hdmi = hdmi_connector->hdmi;
        const struct hdmi_platform_config *config = hdmi->config;
@@ -212,28 +212,19 @@ static int hdp_disable(struct hdmi_connector *hdmi_connector)
 
        hdmi_set_mode(hdmi, false);
 
-       for (i = 0; i < config->hpd_reg_cnt; i++) {
-               ret = regulator_disable(hdmi->hpd_regs[i]);
-               if (ret) {
-                       dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
-                                       config->hpd_reg_names[i], ret);
-                       goto fail;
-               }
-       }
-
        for (i = 0; i < config->hpd_clk_cnt; i++)
                clk_disable_unprepare(hdmi->hpd_clks[i]);
 
        ret = gpio_config(hdmi, false);
-       if (ret) {
-               dev_err(dev->dev, "failed to unconfigure GPIOs: %d\n", ret);
-               goto fail;
-       }
-
-       return 0;
+       if (ret)
+               dev_warn(dev->dev, "failed to unconfigure GPIOs: %d\n", ret);
 
-fail:
-       return ret;
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_disable(hdmi->hpd_regs[i]);
+               if (ret)
+                       dev_warn(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+       }
 }
 
 static void
@@ -260,11 +251,11 @@ void hdmi_connector_irq(struct drm_connector *connector)
                        (hpd_int_status & HDMI_HPD_INT_STATUS_INT)) {
                bool detected = !!(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED);
 
-               DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
-
-               /* ack the irq: */
+               /* ack & disable (temporarily) HPD events: */
                hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
-                               hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
+                       HDMI_HPD_INT_CTRL_INT_ACK);
+
+               DBG("status=%04x, ctrl=%04x", hpd_int_status, hpd_int_ctrl);
 
                /* detect disconnect if we are connected or visa versa: */
                hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
index a7672e100d8b5bd5f4ac4b782a3b1d0a38197a79..3449213f1e76424f7794754f3009de631b9bd00b 100644 (file)
@@ -331,17 +331,8 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
                struct drm_crtc_state *state)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
-       struct drm_device *dev = crtc->dev;
-
        DBG("%s: check", mdp4_crtc->name);
-
-       if (mdp4_crtc->event) {
-               dev_err(dev->dev, "already pending flip!\n");
-               return -EBUSY;
-       }
-
        // TODO anything else to check?
-
        return 0;
 }
 
@@ -357,7 +348,7 @@ static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        unsigned long flags;
 
-       DBG("%s: flush", mdp4_crtc->name);
+       DBG("%s: event: %p", mdp4_crtc->name, crtc->state->event);
 
        WARN_ON(mdp4_crtc->event);
 
index 0e9a2e3a82d76e1e104fd1e136d8924755706586..f021f960a8a27f7d002fd7be8a01edb722e7323a 100644 (file)
@@ -303,11 +303,6 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc,
 
        DBG("%s: check", mdp5_crtc->name);
 
-       if (mdp5_crtc->event) {
-               dev_err(dev->dev, "already pending flip!\n");
-               return -EBUSY;
-       }
-
        /* request a free CTL, if none is already allocated for this CRTC */
        if (state->enable && !mdp5_crtc->ctl) {
                mdp5_crtc->ctl = mdp5_ctlm_request(mdp5_kms->ctlm, crtc);
@@ -364,7 +359,7 @@ static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        unsigned long flags;
 
-       DBG("%s: flush", mdp5_crtc->name);
+       DBG("%s: event: %p", mdp5_crtc->name, crtc->state->event);
 
        WARN_ON(mdp5_crtc->event);
 
@@ -460,10 +455,7 @@ void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
        /* now that we know what irq's we want: */
        mdp5_crtc->err.irqmask = intf2err(intf);
        mdp5_crtc->vblank.irqmask = intf2vblank(intf);
-
-       /* when called from modeset_init(), skip the rest until later: */
-       if (!mdp5_kms)
-               return;
+       mdp_irq_update(&mdp5_kms->base);
 
        spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
        intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
index a11f1b80c488567d44755ad68eadc4d15dc61375..9f01a4f21af2fa969a58c0dc5e8e74a7346e227d 100644 (file)
@@ -216,17 +216,7 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
                goto fail;
        }
 
-       /* NOTE: the vsync and error irq's are actually associated with
-        * the INTF/encoder.. the easiest way to deal with this (ie. what
-        * we do now) is assume a fixed relationship between crtc's and
-        * encoders.  I'm not sure if there is ever a need to more freely
-        * assign crtcs to encoders, but if there is then we need to take
-        * care of error and vblank irq's that the crtc has registered,
-        * and also update user-requested vblank_mask.
-        */
-       encoder->possible_crtcs = BIT(0);
-       mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI);
-
+       encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
        priv->encoders[priv->num_encoders++] = encoder;
 
        /* Construct bridge/connector for HDMI: */
index 03455b64a2458e28fdcdb724c42865f6280001de..2a731722d8407de40be9d2bbd82d6cabb8f8c737 100644 (file)
@@ -42,7 +42,10 @@ static void update_irq(struct mdp_kms *mdp_kms)
        mdp_kms->funcs->set_irqmask(mdp_kms, irqmask);
 }
 
-static void update_irq_unlocked(struct mdp_kms *mdp_kms)
+/* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder
+ * link changes, this must be called to figure out the new global irqmask
+ */
+void mdp_irq_update(struct mdp_kms *mdp_kms)
 {
        unsigned long flags;
        spin_lock_irqsave(&list_lock, flags);
@@ -122,7 +125,7 @@ void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
        spin_unlock_irqrestore(&list_lock, flags);
 
        if (needs_update)
-               update_irq_unlocked(mdp_kms);
+               mdp_irq_update(mdp_kms);
 }
 
 void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
@@ -141,5 +144,5 @@ void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
        spin_unlock_irqrestore(&list_lock, flags);
 
        if (needs_update)
-               update_irq_unlocked(mdp_kms);
+               mdp_irq_update(mdp_kms);
 }
index 99557b5ad4fd35bedc3fd70b20571322571e9d76..b268ce95d3946fdf2f348250ce5cafeb15635b68 100644 (file)
@@ -75,7 +75,7 @@ void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)
 void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask);
 void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
 void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
-
+void mdp_irq_update(struct mdp_kms *mdp_kms);
 
 /*
  * pixel format helpers:
index f0de412e13dc78bbc01e9b6dd7482c74358a14e9..191968256c5822ae0a7964db31377e5ba7b0e0ce 100644 (file)
@@ -23,10 +23,41 @@ struct msm_commit {
        struct drm_atomic_state *state;
        uint32_t fence;
        struct msm_fence_cb fence_cb;
+       uint32_t crtc_mask;
 };
 
 static void fence_cb(struct msm_fence_cb *cb);
 
+/* block until specified crtcs are no longer pending update, and
+ * atomically mark them as pending update
+ */
+static int start_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
+{
+       int ret;
+
+       spin_lock(&priv->pending_crtcs_event.lock);
+       ret = wait_event_interruptible_locked(priv->pending_crtcs_event,
+                       !(priv->pending_crtcs & crtc_mask));
+       if (ret == 0) {
+               DBG("start: %08x", crtc_mask);
+               priv->pending_crtcs |= crtc_mask;
+       }
+       spin_unlock(&priv->pending_crtcs_event.lock);
+
+       return ret;
+}
+
+/* clear specified crtcs (no longer pending update)
+ */
+static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
+{
+       spin_lock(&priv->pending_crtcs_event.lock);
+       DBG("end: %08x", crtc_mask);
+       priv->pending_crtcs &= ~crtc_mask;
+       wake_up_all_locked(&priv->pending_crtcs_event);
+       spin_unlock(&priv->pending_crtcs_event.lock);
+}
+
 static struct msm_commit *new_commit(struct drm_atomic_state *state)
 {
        struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
@@ -58,12 +89,27 @@ static void complete_commit(struct msm_commit *c)
 
        drm_atomic_helper_commit_post_planes(dev, state);
 
+       /* NOTE: _wait_for_vblanks() only waits for vblank on
+        * enabled CRTCs.  So we end up faulting when disabling
+        * due to (potentially) unref'ing the outgoing fb's
+        * before the vblank when the disable has latched.
+        *
+        * But if it did wait on disabled (or newly disabled)
+        * CRTCs, that would be racy (ie. we could have missed
+        * the irq.  We need some way to poll for pipe shut
+        * down.  Or just live with occasionally hitting the
+        * timeout in the CRTC disable path (which really should
+        * not be critical path)
+        */
+
        drm_atomic_helper_wait_for_vblanks(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
 
        drm_atomic_state_free(state);
 
+       end_atomic(dev->dev_private, c->crtc_mask);
+
        kfree(c);
 }
 
@@ -97,8 +143,9 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb)
 int msm_atomic_commit(struct drm_device *dev,
                struct drm_atomic_state *state, bool async)
 {
-       struct msm_commit *c;
        int nplanes = dev->mode_config.num_total_plane;
+       int ncrtcs = dev->mode_config.num_crtc;
+       struct msm_commit *c;
        int i, ret;
 
        ret = drm_atomic_helper_prepare_planes(dev, state);
@@ -106,6 +153,18 @@ int msm_atomic_commit(struct drm_device *dev,
                return ret;
 
        c = new_commit(state);
+       if (!c)
+               return -ENOMEM;
+
+       /*
+        * Figure out what crtcs we have:
+        */
+       for (i = 0; i < ncrtcs; i++) {
+               struct drm_crtc *crtc = state->crtcs[i];
+               if (!crtc)
+                       continue;
+               c->crtc_mask |= (1 << drm_crtc_index(crtc));
+       }
 
        /*
         * Figure out what fence to wait for:
@@ -121,6 +180,14 @@ int msm_atomic_commit(struct drm_device *dev,
                        add_fb(c, new_state->fb);
        }
 
+       /*
+        * Wait for pending updates on any of the same crtc's and then
+        * mark our set of crtc's as busy:
+        */
+       ret = start_atomic(dev->dev_private, c->crtc_mask);
+       if (ret)
+               return ret;
+
        /*
         * This is the point of no return - everything below never fails except
         * when the hw goes bonghits. Which means we can commit the new state on
index c795217e1bfcc6051b72afd05cb09cfbbff34c2c..9a61546a0b05276cd313b0877306b02930fa2fa5 100644 (file)
@@ -193,6 +193,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
 
        priv->wq = alloc_ordered_workqueue("msm", 0);
        init_waitqueue_head(&priv->fence_event);
+       init_waitqueue_head(&priv->pending_crtcs_event);
 
        INIT_LIST_HEAD(&priv->inactive_list);
        INIT_LIST_HEAD(&priv->fence_cbs);
index 136303818436726004b2f294c6c90d69ccdd2f05..b69ef2d5a26c0a0afa9896ed02a88a087f9cebfe 100644 (file)
@@ -96,6 +96,10 @@ struct msm_drm_private {
        /* callbacks deferred until bo is inactive: */
        struct list_head fence_cbs;
 
+       /* crtcs pending async atomic updates: */
+       uint32_t pending_crtcs;
+       wait_queue_head_t pending_crtcs_event;
+
        /* registered MMUs: */
        unsigned int num_mmus;
        struct msm_mmu *mmus[NUM_DOMAINS];
index 94d55e526b4e0732cba7fcf45a2ce725c2433637..1f3af13ccede96b0aa9ad17a49aca3dbaa358872 100644 (file)
@@ -190,8 +190,7 @@ fail_unlock:
 fail:
 
        if (ret) {
-               if (fbi)
-                       framebuffer_release(fbi);
+               framebuffer_release(fbi);
                if (fb) {
                        drm_framebuffer_unregister_private(fb);
                        drm_framebuffer_remove(fb);
index 4a6f0e49d5b5f0709d586e3dcf4e271a0c99c0f5..49dea4fb55ac5fc0c6aa4efa082326a8c892e08b 100644 (file)
@@ -535,8 +535,7 @@ void msm_gem_free_object(struct drm_gem_object *obj)
                        drm_free_large(msm_obj->pages);
 
        } else {
-               if (msm_obj->vaddr)
-                       vunmap(msm_obj->vaddr);
+               vunmap(msm_obj->vaddr);
                put_pages(obj);
        }
 
index ff2b434b3db480a47aa5b94515476714b2819693..760947e380c93bf429a0459622d62e376d450b13 100644 (file)
@@ -26,7 +26,7 @@
 void
 nvkm_event_put(struct nvkm_event *event, u32 types, int index)
 {
-       BUG_ON(!spin_is_locked(&event->refs_lock));
+       assert_spin_locked(&event->refs_lock);
        while (types) {
                int type = __ffs(types); types &= ~(1 << type);
                if (--event->refs[index * event->types_nr + type] == 0) {
@@ -39,7 +39,7 @@ nvkm_event_put(struct nvkm_event *event, u32 types, int index)
 void
 nvkm_event_get(struct nvkm_event *event, u32 types, int index)
 {
-       BUG_ON(!spin_is_locked(&event->refs_lock));
+       assert_spin_locked(&event->refs_lock);
        while (types) {
                int type = __ffs(types); types &= ~(1 << type);
                if (++event->refs[index * event->types_nr + type] == 1) {
index d1bcde55e9d734df7573366a21f87e8b40a5f18b..839a32577680bf32eecbed59e196e6d6ea3606da 100644 (file)
@@ -98,7 +98,7 @@ nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
        struct nvkm_event *event = notify->event;
        unsigned long flags;
 
-       BUG_ON(!spin_is_locked(&event->list_lock));
+       assert_spin_locked(&event->list_lock);
        BUG_ON(size != notify->size);
 
        spin_lock_irqsave(&event->refs_lock, flags);
index 674da1f095b29a1c1ecc524fef40eb3b60bc3a35..7329226906539fb0ed7f5f3ce6ab9280cd13a20c 100644 (file)
@@ -249,6 +249,39 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass;
                break;
+       case 0x106:
+               device->cname = "GK208B";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] =  nve0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] =  nve0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_FUSE   ] = &gf100_fuse_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  gk20a_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTC    ] =  gk104_ltc_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+               device->oclass[NVDEV_SUBDEV_PWR    ] =  nv108_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] =  nvd0_dmaeng_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  nv108_graph_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
+               device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+               device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
+               device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
+               device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
+               device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+               break;
        case 0x108:
                device->cname = "GK208";
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
index 5e58bba0dd5c5bbcf3527088abdc4a80eaeaec9c..a7a890fad1e537325eb24d477d75c24feb624f46 100644 (file)
@@ -44,8 +44,10 @@ static void
 pramin_fini(void *data)
 {
        struct priv *priv = data;
-       nv_wr32(priv->bios, 0x001700, priv->bar0);
-       kfree(priv);
+       if (priv) {
+               nv_wr32(priv->bios, 0x001700, priv->bar0);
+               kfree(priv);
+       }
 }
 
 static void *
index 00f2ca7e44a56af6bb2bf4db5ce159b6526f2d00..033a8e99949735866c751494fd9deae5765dc49e 100644 (file)
 
 #include "nv50.h"
 
+struct nvaa_ram_priv {
+       struct nouveau_ram base;
+       u64 poller_base;
+};
+
 static int
 nvaa_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
              struct nouveau_oclass *oclass, void *data, u32 datasize,
              struct nouveau_object **pobject)
 {
-       const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
-       const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+       u32 rsvd_head = ( 256 * 1024); /* vga memory */
+       u32 rsvd_tail = (1024 * 1024); /* vbios etc */
        struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nouveau_ram *ram;
+       struct nvaa_ram_priv *priv;
        int ret;
 
-       ret = nouveau_ram_create(parent, engine, oclass, &ram);
-       *pobject = nv_object(ram);
+       ret = nouveau_ram_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       ram->size = nv_rd32(pfb, 0x10020c);
-       ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
+       priv->base.type   = NV_MEM_TYPE_STOLEN;
+       priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+       priv->base.size   = (u64)nv_rd32(pfb, 0x100e14) << 12;
 
-       ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
-                             (rsvd_head + rsvd_tail), 1);
+       rsvd_tail += 0x1000;
+       priv->poller_base = priv->base.size - rsvd_tail;
+
+       ret = nouveau_mm_init(&pfb->vram, rsvd_head >> 12,
+                             (priv->base.size  - (rsvd_head + rsvd_tail)) >> 12,
+                             1);
        if (ret)
                return ret;
 
-       ram->type   = NV_MEM_TYPE_STOLEN;
-       ram->stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
-       ram->get = nv50_ram_get;
-       ram->put = nv50_ram_put;
+       priv->base.get = nv50_ram_get;
+       priv->base.put = nv50_ram_put;
+       return 0;
+}
+
+static int
+nvaa_ram_init(struct nouveau_object *object)
+{
+       struct nouveau_fb *pfb = nouveau_fb(object);
+       struct nvaa_ram_priv *priv = (void *)object;
+       int ret;
+       u64 dniso, hostnb, flush;
+
+       ret = nouveau_ram_init(&priv->base);
+       if (ret)
+               return ret;
+
+       dniso  = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1;
+       hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1;
+       flush  = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1;
+
+       /* Enable NISO poller for various clients and set their associated
+        * read address, only for MCP77/78 and MCP79/7A. (fd#25701)
+        */
+       nv_wr32(pfb, 0x100c18, dniso);
+       nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001);
+       nv_wr32(pfb, 0x100c1c, hostnb);
+       nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002);
+       nv_wr32(pfb, 0x100c24, flush);
+       nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000);
+
        return 0;
 }
 
@@ -60,7 +97,7 @@ nvaa_ram_oclass = {
        .ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nvaa_ram_ctor,
                .dtor = _nouveau_ram_dtor,
-               .init = _nouveau_ram_init,
+               .init = nvaa_ram_init,
                .fini = _nouveau_ram_fini,
        },
 };
index a75c35ccf25c739010ac3f866f7106824e387ff6..165401c4045cfe56ee42eeba1eda1918c4ded5a3 100644 (file)
 
 #include "nv04.h"
 
-static void
-nv4c_mc_msi_rearm(struct nouveau_mc *pmc)
-{
-       struct nv04_mc_priv *priv = (void *)pmc;
-       nv_wr08(priv, 0x088050, 0xff);
-}
-
 struct nouveau_oclass *
 nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
        .base.handle = NV_SUBDEV(MC, 0x4c),
@@ -41,5 +34,4 @@ nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
                .fini = _nouveau_mc_fini,
        },
        .intr = nv04_mc_intr,
-       .msi_rearm = nv4c_mc_msi_rearm,
 }.base;
index 21ec561edc999458c5a8d4f1a99be19e67070ca0..bba2960d3dfbb5de9b6e69d977f72529624ab65c 100644 (file)
@@ -1572,8 +1572,10 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
         * so use the DMA API for them.
         */
        if (!nv_device_is_cpu_coherent(device) &&
-           ttm->caching_state == tt_uncached)
+           ttm->caching_state == tt_uncached) {
                ttm_dma_unpopulate(ttm_dma, dev->dev);
+               return;
+       }
 
 #if __OS_HAS_AGP
        if (drm->agp.stat == ENABLED) {
index 5d93902a91ab038cfe040197f767c0de05d7931f..f8042433752b440d72fd9306009f55e972c68385 100644 (file)
@@ -876,7 +876,6 @@ nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
        if (ret)
                return ret;
 
-       bo->gem.dumb = true;
        ret = drm_gem_handle_create(file_priv, &bo->gem, &args->handle);
        drm_gem_object_unreference_unlocked(&bo->gem);
        return ret;
@@ -892,14 +891,6 @@ nouveau_display_dumb_map_offset(struct drm_file *file_priv,
        gem = drm_gem_object_lookup(dev, file_priv, handle);
        if (gem) {
                struct nouveau_bo *bo = nouveau_gem_object(gem);
-
-               /*
-                * We don't allow dumb mmaps on objects created using another
-                * interface.
-                */
-               WARN_ONCE(!(gem->dumb || gem->import_attach),
-                         "Illegal dumb map of accelerated buffer.\n");
-
                *poffset = drm_vma_node_offset_addr(&bo->bo.vma_node);
                drm_gem_object_unreference_unlocked(gem);
                return 0;
index 28d51a22a4bf18b5729f8f4e9cd159c830cbbfca..bf0f9e21d714a80248749ed0594699054e1b7fea 100644 (file)
@@ -36,7 +36,14 @@ void
 nouveau_gem_object_del(struct drm_gem_object *gem)
 {
        struct nouveau_bo *nvbo = nouveau_gem_object(gem);
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct ttm_buffer_object *bo = &nvbo->bo;
+       struct device *dev = drm->dev->dev;
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (WARN_ON(ret < 0 && ret != -EACCES))
+               return;
 
        if (gem->import_attach)
                drm_prime_gem_destroy(gem, nvbo->bo.sg);
@@ -46,6 +53,9 @@ nouveau_gem_object_del(struct drm_gem_object *gem)
        /* reset filp so nouveau_bo_del_ttm() can test for it */
        gem->filp = NULL;
        ttm_bo_unref(&bo);
+
+       pm_runtime_mark_last_busy(dev);
+       pm_runtime_put_autosuspend(dev);
 }
 
 int
@@ -53,7 +63,9 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
 {
        struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_bo *nvbo = nouveau_gem_object(gem);
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
        struct nouveau_vma *vma;
+       struct device *dev = drm->dev->dev;
        int ret;
 
        if (!cli->vm)
@@ -71,11 +83,16 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
                        goto out;
                }
 
+               ret = pm_runtime_get_sync(dev);
+               if (ret < 0 && ret != -EACCES)
+                       goto out;
+
                ret = nouveau_bo_vma_add(nvbo, cli->vm, vma);
-               if (ret) {
+               if (ret)
                        kfree(vma);
-                       goto out;
-               }
+
+               pm_runtime_mark_last_busy(dev);
+               pm_runtime_put_autosuspend(dev);
        } else {
                vma->refcount++;
        }
@@ -129,6 +146,8 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
 {
        struct nouveau_cli *cli = nouveau_cli(file_priv);
        struct nouveau_bo *nvbo = nouveau_gem_object(gem);
+       struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
+       struct device *dev = drm->dev->dev;
        struct nouveau_vma *vma;
        int ret;
 
@@ -141,8 +160,14 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
 
        vma = nouveau_bo_vma_find(nvbo, cli->vm);
        if (vma) {
-               if (--vma->refcount == 0)
-                       nouveau_gem_object_unmap(nvbo, vma);
+               if (--vma->refcount == 0) {
+                       ret = pm_runtime_get_sync(dev);
+                       if (!WARN_ON(ret < 0 && ret != -EACCES)) {
+                               nouveau_gem_object_unmap(nvbo, vma);
+                               pm_runtime_mark_last_busy(dev);
+                               pm_runtime_put_autosuspend(dev);
+                       }
+               }
        }
        ttm_bo_unreserve(&nvbo->bo);
 }
@@ -444,9 +469,6 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
        list_for_each_entry(nvbo, list, entry) {
                struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
 
-               WARN_ONCE(nvbo->gem.dumb,
-                         "GPU use of dumb buffer is illegal.\n");
-
                ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains,
                                             b->write_domains,
                                             b->valid_domains);
index 753a6def61e7ce474d73b21b9affe84ae8b1a861..3d1cfcb96b6bfd9e7dfa50e282d6e3761009f7e1 100644 (file)
@@ -28,6 +28,7 @@
 #include "nouveau_ttm.h"
 #include "nouveau_gem.h"
 
+#include "drm_legacy.h"
 static int
 nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
 {
@@ -281,7 +282,7 @@ nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma)
        struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev);
 
        if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
-               return -EINVAL;
+               return drm_legacy_mmap(filp, vma);
 
        return ttm_bo_mmap(filp, vma, &drm->ttm.bdev);
 }
index d59ec491dbb9cba64d76369e62ef61b836c094d8..ed644a4f6f57c4254349c3881a16955cd42cbc05 100644 (file)
@@ -1851,10 +1851,9 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                return pll;
                }
                /* otherwise, pick one of the plls */
-               if ((rdev->family == CHIP_KAVERI) ||
-                   (rdev->family == CHIP_KABINI) ||
+               if ((rdev->family == CHIP_KABINI) ||
                    (rdev->family == CHIP_MULLINS)) {
-                       /* KB/KV/ML has PPLL1 and PPLL2 */
+                       /* KB/ML has PPLL1 and PPLL2 */
                        pll_in_use = radeon_get_pll_use_mask(crtc);
                        if (!(pll_in_use & (1 << ATOM_PPLL2)))
                                return ATOM_PPLL2;
@@ -1863,7 +1862,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                        DRM_ERROR("unable to allocate a PPLL\n");
                        return ATOM_PPLL_INVALID;
                } else {
-                       /* CI has PPLL0, PPLL1, and PPLL2 */
+                       /* CI/KV has PPLL0, PPLL1, and PPLL2 */
                        pll_in_use = radeon_get_pll_use_mask(crtc);
                        if (!(pll_in_use & (1 << ATOM_PPLL2)))
                                return ATOM_PPLL2;
@@ -2155,6 +2154,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
        case ATOM_PPLL0:
                /* disable the ppll */
                if ((rdev->family == CHIP_ARUBA) ||
+                   (rdev->family == CHIP_KAVERI) ||
                    (rdev->family == CHIP_BONAIRE) ||
                    (rdev->family == CHIP_HAWAII))
                        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
index 11ba9d21b89b608788f623822bcfb6f9f14dbbf1..db42a670f9957c7fd6c3698b2c0be178ac6a02d2 100644 (file)
@@ -492,6 +492,10 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
        struct radeon_connector_atom_dig *dig_connector;
        int dp_clock;
 
+       if ((mode->clock > 340000) &&
+           (!radeon_connector_is_dp12_capable(connector)))
+               return MODE_CLOCK_HIGH;
+
        if (!radeon_connector->con_priv)
                return MODE_CLOCK_HIGH;
        dig_connector = radeon_connector->con_priv;
index 6dcde3798b45a026f0be30f8e7bffb8b254ace81..64fdae558d36e908cca5af2388b22996db975502 100644 (file)
@@ -6033,6 +6033,17 @@ void cik_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 1 << vm_id);
 
+       /* wait for the invalidate to complete */
+       radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(0) | /* wait */
+                                WAIT_REG_MEM_FUNCTION(0) |  /* always */
+                                WAIT_REG_MEM_ENGINE(0))); /* me */
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0); /* ref */
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, 0x20); /* poll interval */
+
        /* compute doesn't have PFP */
        if (usepfp) {
                /* sync PFP to ME, otherwise we might get invalid PFP reads */
index dde5c7e29eb200b6dc78f1fad46197e43e0013ed..42cd0cffe210934b0dadac9eaff72add715c13f2 100644 (file)
@@ -816,7 +816,6 @@ void cik_sdma_vm_write_pages(struct radeon_device *rdev,
                for (; ndw > 0; ndw -= 2, --count, pe += 8) {
                        if (flags & R600_PTE_SYSTEM) {
                                value = radeon_vm_map_gart(rdev, addr);
-                               value &= 0xFFFFFFFFFFFFF000ULL;
                        } else if (flags & R600_PTE_VALID) {
                                value = addr;
                        } else {
@@ -903,6 +902,9 @@ void cik_sdma_vm_pad_ib(struct radeon_ib *ib)
 void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
                      unsigned vm_id, uint64_t pd_addr)
 {
+       u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(0) |
+                         SDMA_POLL_REG_MEM_EXTRA_FUNC(0)); /* always */
+
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        if (vm_id < 8) {
                radeon_ring_write(ring, (VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + (vm_id << 2)) >> 2);
@@ -943,5 +945,12 @@ void cik_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
        radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
        radeon_ring_write(ring, 1 << vm_id);
+
+       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0); /* reference */
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */
 }
 
index ba85986febea5054762615ee7fc5edbaa275f2cd..03003f8a6de63ba00c741824c053070a009cd319 100644 (file)
 #define ATC_VM_APERTURE1_HIGH_ADDR                             0x330Cu
 #define ATC_VM_APERTURE1_LOW_ADDR                              0x3304u
 
+#define IH_VMID_0_LUT                                          0x3D40u
+
 #endif
index 2fe8cfc966d9304b6845f6f6d29c9e236d80b0cb..bafdf92a5732dfa679f74e47ee582a699f9d635e 100644 (file)
@@ -103,7 +103,7 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
        }
 
        sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
-       if (sad_count < 0) {
+       if (sad_count <= 0) {
                DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
                return;
        }
index 9b42001295ba587197f5bcb317daca4a0f83cb3d..e3e9c10cfba97438571b4b8bc88cbea7c3dab9f7 100644 (file)
@@ -2745,13 +2745,11 @@ int kv_dpm_init(struct radeon_device *rdev)
        pi->enable_auto_thermal_throttling = true;
        pi->disable_nb_ps3_in_battery = false;
        if (radeon_bapm == -1) {
-               /* There are stability issues reported on with
-                * bapm enabled on an asrock system.
-                */
-               if (rdev->pdev->subsystem_vendor == 0x1849)
-                       pi->bapm_enable = false;
-               else
+               /* only enable bapm on KB, ML by default */
+               if (rdev->family == CHIP_KABINI || rdev->family == CHIP_MULLINS)
                        pi->bapm_enable = true;
+               else
+                       pi->bapm_enable = false;
        } else if (radeon_bapm == 0) {
                pi->bapm_enable = false;
        } else {
index 360de9f1f4914079d3de3ad0022a50862b934395..aea48c89b24170e692bc91bf2b4c927ef9d08784 100644 (file)
@@ -2516,6 +2516,16 @@ void cayman_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
        radeon_ring_write(ring, PACKET0(VM_INVALIDATE_REQUEST, 0));
        radeon_ring_write(ring, 1 << vm_id);
 
+       /* wait for the invalidate to complete */
+       radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) |  /* always */
+                                WAIT_REG_MEM_ENGINE(0))); /* me */
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0); /* ref */
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, 0x20); /* poll interval */
+
        /* sync PFP to ME, otherwise we might get invalid PFP reads */
        radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
        radeon_ring_write(ring, 0x0);
index 50f88611ff60c832dc59e767543f91f8baf859eb..ce787a9f12c01fd1f8179d54ef610c27b9be131b 100644 (file)
@@ -372,7 +372,6 @@ void cayman_dma_vm_write_pages(struct radeon_device *rdev,
                for (; ndw > 0; ndw -= 2, --count, pe += 8) {
                        if (flags & R600_PTE_SYSTEM) {
                                value = radeon_vm_map_gart(rdev, addr);
-                               value &= 0xFFFFFFFFFFFFF000ULL;
                        } else if (flags & R600_PTE_VALID) {
                                value = addr;
                        } else {
@@ -463,5 +462,11 @@ void cayman_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0));
        radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
        radeon_ring_write(ring, 1 << vm_id);
+
+       /* wait for invalidate to complete */
+       radeon_ring_write(ring, DMA_SRBM_READ_PACKET);
+       radeon_ring_write(ring, (0xff << 20) | (VM_INVALIDATE_REQUEST >> 2));
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, 0); /* value */
 }
 
index 2e12e4d69253fde453c3fb648566c0224bfe06bc..ad7125486894d18ae90b0bc507d248d92baaf3e6 100644 (file)
 #define        PACKET3_MEM_SEMAPHORE                           0x39
 #define        PACKET3_MPEG_INDEX                              0x3A
 #define        PACKET3_WAIT_REG_MEM                            0x3C
+#define                WAIT_REG_MEM_FUNCTION(x)                ((x) << 0)
+                /* 0 - always
+                * 1 - <
+                * 2 - <=
+                * 3 - ==
+                * 4 - !=
+                * 5 - >=
+                * 6 - >
+                */
+#define                WAIT_REG_MEM_MEM_SPACE(x)               ((x) << 4)
+                /* 0 - reg
+                * 1 - mem
+                */
+#define                WAIT_REG_MEM_ENGINE(x)                  ((x) << 8)
+                /* 0 - me
+                * 1 - pfp
+                */
 #define        PACKET3_MEM_WRITE                               0x3D
 #define        PACKET3_PFP_SYNC_ME                             0x42
 #define        PACKET3_SURFACE_SYNC                            0x43
                                         (1 << 21) |                    \
                                         (((n) & 0xFFFFF) << 0))
 
+#define DMA_SRBM_POLL_PACKET           ((9 << 28) |                    \
+                                        (1 << 27) |                    \
+                                        (1 << 26))
+
+#define DMA_SRBM_READ_PACKET           ((9 << 28) |                    \
+                                        (1 << 27))
+
 /* async DMA Packet types */
 #define        DMA_PACKET_WRITE                                  0x2
 #define        DMA_PACKET_COPY                                   0x3
index 74f06d5405913a7e78c18af9d365c6549b591f45..279801ca5110aff68d80ea452751d7f9b0bf748f 100644 (file)
@@ -644,6 +644,7 @@ int r100_pci_gart_init(struct radeon_device *rdev)
                return r;
        rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
        rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
+       rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry;
        rdev->asic->gart.set_page = &r100_pci_gart_set_page;
        return radeon_gart_table_ram_alloc(rdev);
 }
@@ -681,11 +682,16 @@ void r100_pci_gart_disable(struct radeon_device *rdev)
        WREG32(RADEON_AIC_HI_ADDR, 0);
 }
 
+uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags)
+{
+       return addr;
+}
+
 void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i,
-                           uint64_t addr, uint32_t flags)
+                           uint64_t entry)
 {
        u32 *gtt = rdev->gart.ptr;
-       gtt[i] = cpu_to_le32(lower_32_bits(addr));
+       gtt[i] = cpu_to_le32(lower_32_bits(entry));
 }
 
 void r100_pci_gart_fini(struct radeon_device *rdev)
index 064ad5569ccaac826612aedd8d035db3996106db..08d68f3e13e9887ff7b06f18e899c34fd85ae31a 100644 (file)
@@ -73,11 +73,8 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
 #define R300_PTE_WRITEABLE (1 << 2)
 #define R300_PTE_READABLE  (1 << 3)
 
-void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
-                             uint64_t addr, uint32_t flags)
+uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags)
 {
-       void __iomem *ptr = rdev->gart.ptr;
-
        addr = (lower_32_bits(addr) >> 8) |
                ((upper_32_bits(addr) & 0xff) << 24);
        if (flags & RADEON_GART_PAGE_READ)
@@ -86,10 +83,18 @@ void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
                addr |= R300_PTE_WRITEABLE;
        if (!(flags & RADEON_GART_PAGE_SNOOP))
                addr |= R300_PTE_UNSNOOPED;
+       return addr;
+}
+
+void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
+                             uint64_t entry)
+{
+       void __iomem *ptr = rdev->gart.ptr;
+
        /* on x86 we want this to be CPU endian, on powerpc
         * on powerpc without HW swappers, it'll get swapped on way
         * into VRAM - so no need for cpu_to_le32 on VRAM tables */
-       writel(addr, ((void __iomem *)ptr) + (i * 4));
+       writel(entry, ((void __iomem *)ptr) + (i * 4));
 }
 
 int rv370_pcie_gart_init(struct radeon_device *rdev)
@@ -109,6 +114,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev)
                DRM_ERROR("Failed to register debugfs file for PCIE gart !\n");
        rdev->gart.table_size = rdev->gart.num_gpu_pages * 4;
        rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush;
+       rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry;
        rdev->asic->gart.set_page = &rv370_pcie_gart_set_page;
        return radeon_gart_table_vram_alloc(rdev);
 }
index 54529b837afaa1d76147f764664047af5f09b5f6..3f2a8d3febcab277c2c4ccbb0dd0ecf4a10a26ed 100644 (file)
@@ -242,6 +242,7 @@ bool radeon_get_bios(struct radeon_device *rdev);
  * Dummy page
  */
 struct radeon_dummy_page {
+       uint64_t        entry;
        struct page     *page;
        dma_addr_t      addr;
 };
@@ -645,7 +646,7 @@ struct radeon_gart {
        unsigned                        num_cpu_pages;
        unsigned                        table_size;
        struct page                     **pages;
-       dma_addr_t                      *pages_addr;
+       uint64_t                        *pages_entry;
        bool                            ready;
 };
 
@@ -1847,8 +1848,9 @@ struct radeon_asic {
        /* gart */
        struct {
                void (*tlb_flush)(struct radeon_device *rdev);
+               uint64_t (*get_page_entry)(uint64_t addr, uint32_t flags);
                void (*set_page)(struct radeon_device *rdev, unsigned i,
-                                uint64_t addr, uint32_t flags);
+                                uint64_t entry);
        } gart;
        struct {
                int (*init)(struct radeon_device *rdev);
@@ -2852,7 +2854,8 @@ static inline void radeon_ring_write(struct radeon_ring *ring, uint32_t v)
 #define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
 #define radeon_asic_reset(rdev) (rdev)->asic->asic_reset((rdev))
 #define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart.tlb_flush((rdev))
-#define radeon_gart_set_page(rdev, i, p, f) (rdev)->asic->gart.set_page((rdev), (i), (p), (f))
+#define radeon_gart_get_page_entry(a, f) (rdev)->asic->gart.get_page_entry((a), (f))
+#define radeon_gart_set_page(rdev, i, e) (rdev)->asic->gart.set_page((rdev), (i), (e))
 #define radeon_asic_vm_init(rdev) (rdev)->asic->vm.init((rdev))
 #define radeon_asic_vm_fini(rdev) (rdev)->asic->vm.fini((rdev))
 #define radeon_asic_vm_copy_pages(rdev, ib, pe, src, count) ((rdev)->asic->vm.copy_pages((rdev), (ib), (pe), (src), (count)))
index 850de57069bec0effcadd4a55c6b1abead242314..ed0e10eee2dcd7459d016c4e3e9f1fb6a2254f1c 100644 (file)
@@ -159,11 +159,13 @@ void radeon_agp_disable(struct radeon_device *rdev)
                DRM_INFO("Forcing AGP to PCIE mode\n");
                rdev->flags |= RADEON_IS_PCIE;
                rdev->asic->gart.tlb_flush = &rv370_pcie_gart_tlb_flush;
+               rdev->asic->gart.get_page_entry = &rv370_pcie_gart_get_page_entry;
                rdev->asic->gart.set_page = &rv370_pcie_gart_set_page;
        } else {
                DRM_INFO("Forcing AGP to PCI mode\n");
                rdev->flags |= RADEON_IS_PCI;
                rdev->asic->gart.tlb_flush = &r100_pci_gart_tlb_flush;
+               rdev->asic->gart.get_page_entry = &r100_pci_gart_get_page_entry;
                rdev->asic->gart.set_page = &r100_pci_gart_set_page;
        }
        rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
@@ -199,6 +201,7 @@ static struct radeon_asic r100_asic = {
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
+               .get_page_entry = &r100_pci_gart_get_page_entry,
                .set_page = &r100_pci_gart_set_page,
        },
        .ring = {
@@ -265,6 +268,7 @@ static struct radeon_asic r200_asic = {
        .mc_wait_for_idle = &r100_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
+               .get_page_entry = &r100_pci_gart_get_page_entry,
                .set_page = &r100_pci_gart_set_page,
        },
        .ring = {
@@ -333,6 +337,20 @@ static struct radeon_asic_ring r300_gfx_ring = {
        .set_wptr = &r100_gfx_set_wptr,
 };
 
+static struct radeon_asic_ring rv515_gfx_ring = {
+       .ib_execute = &r100_ring_ib_execute,
+       .emit_fence = &r300_fence_ring_emit,
+       .emit_semaphore = &r100_semaphore_ring_emit,
+       .cs_parse = &r300_cs_parse,
+       .ring_start = &rv515_ring_start,
+       .ring_test = &r100_ring_test,
+       .ib_test = &r100_ib_test,
+       .is_lockup = &r100_gpu_is_lockup,
+       .get_rptr = &r100_gfx_get_rptr,
+       .get_wptr = &r100_gfx_get_wptr,
+       .set_wptr = &r100_gfx_set_wptr,
+};
+
 static struct radeon_asic r300_asic = {
        .init = &r300_init,
        .fini = &r300_fini,
@@ -345,6 +363,7 @@ static struct radeon_asic r300_asic = {
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &r100_pci_gart_tlb_flush,
+               .get_page_entry = &r100_pci_gart_get_page_entry,
                .set_page = &r100_pci_gart_set_page,
        },
        .ring = {
@@ -411,6 +430,7 @@ static struct radeon_asic r300_asic_pcie = {
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
+               .get_page_entry = &rv370_pcie_gart_get_page_entry,
                .set_page = &rv370_pcie_gart_set_page,
        },
        .ring = {
@@ -477,6 +497,7 @@ static struct radeon_asic r420_asic = {
        .mc_wait_for_idle = &r300_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
+               .get_page_entry = &rv370_pcie_gart_get_page_entry,
                .set_page = &rv370_pcie_gart_set_page,
        },
        .ring = {
@@ -543,6 +564,7 @@ static struct radeon_asic rs400_asic = {
        .mc_wait_for_idle = &rs400_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
+               .get_page_entry = &rs400_gart_get_page_entry,
                .set_page = &rs400_gart_set_page,
        },
        .ring = {
@@ -609,6 +631,7 @@ static struct radeon_asic rs600_asic = {
        .mc_wait_for_idle = &rs600_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rs600_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -677,6 +700,7 @@ static struct radeon_asic rs690_asic = {
        .mc_wait_for_idle = &rs690_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rs400_gart_tlb_flush,
+               .get_page_entry = &rs400_gart_get_page_entry,
                .set_page = &rs400_gart_set_page,
        },
        .ring = {
@@ -745,10 +769,11 @@ static struct radeon_asic rv515_asic = {
        .mc_wait_for_idle = &rv515_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
+               .get_page_entry = &rv370_pcie_gart_get_page_entry,
                .set_page = &rv370_pcie_gart_set_page,
        },
        .ring = {
-               [RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring
+               [RADEON_RING_TYPE_GFX_INDEX] = &rv515_gfx_ring
        },
        .irq = {
                .set = &rs600_irq_set,
@@ -811,10 +836,11 @@ static struct radeon_asic r520_asic = {
        .mc_wait_for_idle = &r520_mc_wait_for_idle,
        .gart = {
                .tlb_flush = &rv370_pcie_gart_tlb_flush,
+               .get_page_entry = &rv370_pcie_gart_get_page_entry,
                .set_page = &rv370_pcie_gart_set_page,
        },
        .ring = {
-               [RADEON_RING_TYPE_GFX_INDEX] = &r300_gfx_ring
+               [RADEON_RING_TYPE_GFX_INDEX] = &rv515_gfx_ring
        },
        .irq = {
                .set = &rs600_irq_set,
@@ -905,6 +931,7 @@ static struct radeon_asic r600_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -990,6 +1017,7 @@ static struct radeon_asic rv6xx_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -1081,6 +1109,7 @@ static struct radeon_asic rs780_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -1185,6 +1214,7 @@ static struct radeon_asic rv770_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &r600_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -1303,6 +1333,7 @@ static struct radeon_asic evergreen_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -1395,6 +1426,7 @@ static struct radeon_asic sumo_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -1486,6 +1518,7 @@ static struct radeon_asic btc_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &evergreen_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .ring = {
@@ -1621,6 +1654,7 @@ static struct radeon_asic cayman_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .vm = {
@@ -1724,6 +1758,7 @@ static struct radeon_asic trinity_asic = {
        .get_gpu_clock_counter = &r600_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &cayman_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .vm = {
@@ -1857,6 +1892,7 @@ static struct radeon_asic si_asic = {
        .get_gpu_clock_counter = &si_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &si_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .vm = {
@@ -2018,6 +2054,7 @@ static struct radeon_asic ci_asic = {
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .vm = {
@@ -2125,6 +2162,7 @@ static struct radeon_asic kv_asic = {
        .get_gpu_clock_counter = &cik_get_gpu_clock_counter,
        .gart = {
                .tlb_flush = &cik_pcie_gart_tlb_flush,
+               .get_page_entry = &rs600_gart_get_page_entry,
                .set_page = &rs600_gart_set_page,
        },
        .vm = {
index 2a45d548d5ece5d9cd1cdad32d64fb3808b0c6fd..8d787d115653d20ed2a460fa770416e73eeddbee 100644 (file)
@@ -67,8 +67,9 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *cp);
 int r100_asic_reset(struct radeon_device *rdev);
 u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
+uint64_t r100_pci_gart_get_page_entry(uint64_t addr, uint32_t flags);
 void r100_pci_gart_set_page(struct radeon_device *rdev, unsigned i,
-                           uint64_t addr, uint32_t flags);
+                           uint64_t entry);
 void r100_ring_start(struct radeon_device *rdev, struct radeon_ring *ring);
 int r100_irq_set(struct radeon_device *rdev);
 int r100_irq_process(struct radeon_device *rdev);
@@ -172,8 +173,9 @@ extern void r300_fence_ring_emit(struct radeon_device *rdev,
                                struct radeon_fence *fence);
 extern int r300_cs_parse(struct radeon_cs_parser *p);
 extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev);
+extern uint64_t rv370_pcie_gart_get_page_entry(uint64_t addr, uint32_t flags);
 extern void rv370_pcie_gart_set_page(struct radeon_device *rdev, unsigned i,
-                                    uint64_t addr, uint32_t flags);
+                                    uint64_t entry);
 extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
 extern int rv370_get_pcie_lanes(struct radeon_device *rdev);
 extern void r300_set_reg_safe(struct radeon_device *rdev);
@@ -208,8 +210,9 @@ extern void rs400_fini(struct radeon_device *rdev);
 extern int rs400_suspend(struct radeon_device *rdev);
 extern int rs400_resume(struct radeon_device *rdev);
 void rs400_gart_tlb_flush(struct radeon_device *rdev);
+uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags);
 void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
-                        uint64_t addr, uint32_t flags);
+                        uint64_t entry);
 uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 int rs400_gart_init(struct radeon_device *rdev);
@@ -232,8 +235,9 @@ int rs600_irq_process(struct radeon_device *rdev);
 void rs600_irq_disable(struct radeon_device *rdev);
 u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc);
 void rs600_gart_tlb_flush(struct radeon_device *rdev);
+uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags);
 void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
-                        uint64_t addr, uint32_t flags);
+                        uint64_t entry);
 uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);
 void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void rs600_bandwidth_update(struct radeon_device *rdev);
index 0ec65168f331c73bcbfff24ee719cd6f98790602..bd7519fdd3f431cbce8c2bc6bd3e588e525be5cd 100644 (file)
@@ -774,6 +774,8 @@ int radeon_dummy_page_init(struct radeon_device *rdev)
                rdev->dummy_page.page = NULL;
                return -ENOMEM;
        }
+       rdev->dummy_page.entry = radeon_gart_get_page_entry(rdev->dummy_page.addr,
+                                                           RADEON_GART_PAGE_DUMMY);
        return 0;
 }
 
index 84146d5901aa5aacad168255c14d72cafce5cf15..5450fa95a47efdcde9aa664c740cbe578e4f5b26 100644 (file)
@@ -165,6 +165,19 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev)
                radeon_bo_unpin(rdev->gart.robj);
        radeon_bo_unreserve(rdev->gart.robj);
        rdev->gart.table_addr = gpu_addr;
+
+       if (!r) {
+               int i;
+
+               /* We might have dropped some GART table updates while it wasn't
+                * mapped, restore all entries
+                */
+               for (i = 0; i < rdev->gart.num_gpu_pages; i++)
+                       radeon_gart_set_page(rdev, i, rdev->gart.pages_entry[i]);
+               mb();
+               radeon_gart_tlb_flush(rdev);
+       }
+
        return r;
 }
 
@@ -228,7 +241,6 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
        unsigned t;
        unsigned p;
        int i, j;
-       u64 page_base;
 
        if (!rdev->gart.ready) {
                WARN(1, "trying to unbind memory from uninitialized GART !\n");
@@ -239,14 +251,12 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset,
        for (i = 0; i < pages; i++, p++) {
                if (rdev->gart.pages[p]) {
                        rdev->gart.pages[p] = NULL;
-                       rdev->gart.pages_addr[p] = rdev->dummy_page.addr;
-                       page_base = rdev->gart.pages_addr[p];
                        for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
+                               rdev->gart.pages_entry[t] = rdev->dummy_page.entry;
                                if (rdev->gart.ptr) {
-                                       radeon_gart_set_page(rdev, t, page_base,
-                                                            RADEON_GART_PAGE_DUMMY);
+                                       radeon_gart_set_page(rdev, t,
+                                                            rdev->dummy_page.entry);
                                }
-                               page_base += RADEON_GPU_PAGE_SIZE;
                        }
                }
        }
@@ -274,7 +284,7 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
 {
        unsigned t;
        unsigned p;
-       uint64_t page_base;
+       uint64_t page_base, page_entry;
        int i, j;
 
        if (!rdev->gart.ready) {
@@ -285,14 +295,15 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset,
        p = t / (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
 
        for (i = 0; i < pages; i++, p++) {
-               rdev->gart.pages_addr[p] = dma_addr[i];
                rdev->gart.pages[p] = pagelist[i];
-               if (rdev->gart.ptr) {
-                       page_base = rdev->gart.pages_addr[p];
-                       for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
-                               radeon_gart_set_page(rdev, t, page_base, flags);
-                               page_base += RADEON_GPU_PAGE_SIZE;
+               page_base = dma_addr[i];
+               for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) {
+                       page_entry = radeon_gart_get_page_entry(page_base, flags);
+                       rdev->gart.pages_entry[t] = page_entry;
+                       if (rdev->gart.ptr) {
+                               radeon_gart_set_page(rdev, t, page_entry);
                        }
+                       page_base += RADEON_GPU_PAGE_SIZE;
                }
        }
        mb();
@@ -334,16 +345,15 @@ int radeon_gart_init(struct radeon_device *rdev)
                radeon_gart_fini(rdev);
                return -ENOMEM;
        }
-       rdev->gart.pages_addr = vzalloc(sizeof(dma_addr_t) *
-                                       rdev->gart.num_cpu_pages);
-       if (rdev->gart.pages_addr == NULL) {
+       rdev->gart.pages_entry = vmalloc(sizeof(uint64_t) *
+                                        rdev->gart.num_gpu_pages);
+       if (rdev->gart.pages_entry == NULL) {
                radeon_gart_fini(rdev);
                return -ENOMEM;
        }
        /* set GART entry to point to the dummy page by default */
-       for (i = 0; i < rdev->gart.num_cpu_pages; i++) {
-               rdev->gart.pages_addr[i] = rdev->dummy_page.addr;
-       }
+       for (i = 0; i < rdev->gart.num_gpu_pages; i++)
+               rdev->gart.pages_entry[i] = rdev->dummy_page.entry;
        return 0;
 }
 
@@ -356,15 +366,15 @@ int radeon_gart_init(struct radeon_device *rdev)
  */
 void radeon_gart_fini(struct radeon_device *rdev)
 {
-       if (rdev->gart.pages && rdev->gart.pages_addr && rdev->gart.ready) {
+       if (rdev->gart.ready) {
                /* unbind pages */
                radeon_gart_unbind(rdev, 0, rdev->gart.num_cpu_pages);
        }
        rdev->gart.ready = false;
        vfree(rdev->gart.pages);
-       vfree(rdev->gart.pages_addr);
+       vfree(rdev->gart.pages_entry);
        rdev->gart.pages = NULL;
-       rdev->gart.pages_addr = NULL;
+       rdev->gart.pages_entry = NULL;
 
        radeon_dummy_page_fini(rdev);
 }
index fe48f229043e33720c26bcdd40949d7a8fd41b00..d0b4f7d1140d6a391a9f32c7ec466f099b99b5fe 100644 (file)
@@ -394,10 +394,9 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        return r;
 }
 
-static int radeon_mode_mmap(struct drm_file *filp,
-                           struct drm_device *dev,
-                           uint32_t handle, bool dumb,
-                           uint64_t *offset_p)
+int radeon_mode_dumb_mmap(struct drm_file *filp,
+                         struct drm_device *dev,
+                         uint32_t handle, uint64_t *offset_p)
 {
        struct drm_gem_object *gobj;
        struct radeon_bo *robj;
@@ -406,14 +405,6 @@ static int radeon_mode_mmap(struct drm_file *filp,
        if (gobj == NULL) {
                return -ENOENT;
        }
-
-       /*
-        * We don't allow dumb mmaps on objects created using another
-        * interface.
-        */
-       WARN_ONCE(dumb && !(gobj->dumb || gobj->import_attach),
-               "Illegal dumb map of GPU buffer.\n");
-
        robj = gem_to_radeon_bo(gobj);
        if (radeon_ttm_tt_has_userptr(robj->tbo.ttm)) {
                drm_gem_object_unreference_unlocked(gobj);
@@ -424,20 +415,12 @@ static int radeon_mode_mmap(struct drm_file *filp,
        return 0;
 }
 
-int radeon_mode_dumb_mmap(struct drm_file *filp,
-                         struct drm_device *dev,
-                         uint32_t handle, uint64_t *offset_p)
-{
-       return radeon_mode_mmap(filp, dev, handle, true, offset_p);
-}
-
 int radeon_gem_mmap_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp)
 {
        struct drm_radeon_gem_mmap *args = data;
 
-       return radeon_mode_mmap(filp, dev, args->handle, false,
-                               &args->addr_ptr);
+       return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr);
 }
 
 int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
@@ -593,7 +576,7 @@ error_unreserve:
 error_free:
        drm_free_large(vm_bos);
 
-       if (r)
+       if (r && r != -ERESTARTSYS)
                DRM_ERROR("Couldn't update BO_VA (%d)\n", r);
 }
 
@@ -763,7 +746,6 @@ int radeon_mode_dumb_create(struct drm_file *file_priv,
                return -ENOMEM;
 
        r = drm_gem_handle_create(file_priv, gobj, &handle);
-       gobj->dumb = true;
        /* drop reference from allocate - handle holds it now */
        drm_gem_object_unreference_unlocked(gobj);
        if (r) {
index 065d02068ec3dc14f576c139e31a0b4bfef1580b..bef9a09532844b026fc1197c8692411b0840d8fa 100644 (file)
@@ -28,6 +28,8 @@
 #include "cikd.h"
 #include "cik_reg.h"
 #include "radeon_kfd.h"
+#include "radeon_ucode.h"
+#include <linux/firmware.h>
 
 #define CIK_PIPE_PER_MEC       (4)
 
@@ -49,6 +51,7 @@ static uint64_t get_vmem_size(struct kgd_dev *kgd);
 static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
 
 static uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd);
+static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type);
 
 /*
  * Register access functions
@@ -69,7 +72,7 @@ static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
 static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
                        uint32_t queue_id, uint32_t __user *wptr);
 
-static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address,
+static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id);
 
 static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
@@ -89,14 +92,16 @@ static const struct kfd2kgd_calls kfd2kgd = {
        .init_memory = kgd_init_memory,
        .init_pipeline = kgd_init_pipeline,
        .hqd_load = kgd_hqd_load,
-       .hqd_is_occupies = kgd_hqd_is_occupies,
+       .hqd_is_occupied = kgd_hqd_is_occupied,
        .hqd_destroy = kgd_hqd_destroy,
+       .get_fw_version = get_fw_version
 };
 
 static const struct kgd2kfd_calls *kgd2kfd;
 
 bool radeon_kfd_init(void)
 {
+#if defined(CONFIG_HSA_AMD_MODULE)
        bool (*kgd2kfd_init_p)(unsigned, const struct kfd2kgd_calls*,
                                const struct kgd2kfd_calls**);
 
@@ -113,6 +118,17 @@ bool radeon_kfd_init(void)
        }
 
        return true;
+#elif defined(CONFIG_HSA_AMD)
+       if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kfd2kgd, &kgd2kfd)) {
+               kgd2kfd = NULL;
+
+               return false;
+       }
+
+       return true;
+#else
+       return false;
+#endif
 }
 
 void radeon_kfd_fini(void)
@@ -374,6 +390,10 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
                cpu_relax();
        write_register(kgd, ATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid);
 
+       /* Mapping vmid to pasid also for IH block */
+       write_register(kgd, IH_VMID_0_LUT + vmid * sizeof(uint32_t),
+                       pasid_mapping);
+
        return 0;
 }
 
@@ -416,7 +436,7 @@ static int kgd_init_memory(struct kgd_dev *kgd)
 static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
                                uint32_t hpd_size, uint64_t hpd_gpu_addr)
 {
-       uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1;
+       uint32_t mec = (pipe_id / CIK_PIPE_PER_MEC) + 1;
        uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC);
 
        lock_srbm(kgd, mec, pipe, 0, 0);
@@ -513,7 +533,7 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
        return 0;
 }
 
-static bool kgd_hqd_is_occupies(struct kgd_dev *kgd, uint64_t queue_address,
+static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
                                uint32_t pipe_id, uint32_t queue_id)
 {
        uint32_t act;
@@ -552,6 +572,7 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
                if (timeout == 0) {
                        pr_err("kfd: cp queue preemption time out (%dms)\n",
                                temp);
+                       release_queue(kgd);
                        return -ETIME;
                }
                msleep(20);
@@ -561,3 +582,52 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
        release_queue(kgd);
        return 0;
 }
+
+static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type)
+{
+       struct radeon_device *rdev = (struct radeon_device *) kgd;
+       const union radeon_firmware_header *hdr;
+
+       BUG_ON(kgd == NULL || rdev->mec_fw == NULL);
+
+       switch (type) {
+       case KGD_ENGINE_PFP:
+               hdr = (const union radeon_firmware_header *) rdev->pfp_fw->data;
+               break;
+
+       case KGD_ENGINE_ME:
+               hdr = (const union radeon_firmware_header *) rdev->me_fw->data;
+               break;
+
+       case KGD_ENGINE_CE:
+               hdr = (const union radeon_firmware_header *) rdev->ce_fw->data;
+               break;
+
+       case KGD_ENGINE_MEC1:
+               hdr = (const union radeon_firmware_header *) rdev->mec_fw->data;
+               break;
+
+       case KGD_ENGINE_MEC2:
+               hdr = (const union radeon_firmware_header *)
+                                                       rdev->mec2_fw->data;
+               break;
+
+       case KGD_ENGINE_RLC:
+               hdr = (const union radeon_firmware_header *) rdev->rlc_fw->data;
+               break;
+
+       case KGD_ENGINE_SDMA:
+               hdr = (const union radeon_firmware_header *)
+                                                       rdev->sdma_fw->data;
+               break;
+
+       default:
+               return 0;
+       }
+
+       if (hdr == NULL)
+               return 0;
+
+       /* Only 12 bit in use*/
+       return hdr->common.ucode_version;
+}
index 7d68223eb4692a026fbad21b68bbe9362ee6d87a..86fc56434b2875435aaf9b7dab85fdac3e39e7e9 100644 (file)
@@ -529,9 +529,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
                        u32 current_domain =
                                radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
 
-                       WARN_ONCE(bo->gem_base.dumb,
-                                 "GPU use of dumb buffer is illegal.\n");
-
                        /* Check if this buffer will be moved and don't move it
                         * if we have moved too many buffers for this IB already.
                         *
index 32522cc940a127c4b413c9928121c2b9258457fd..f7da8fe96a66b51e40aedb6ee0255770821cb989 100644 (file)
@@ -1287,8 +1287,39 @@ dpm_failed:
        return ret;
 }
 
+struct radeon_dpm_quirk {
+       u32 chip_vendor;
+       u32 chip_device;
+       u32 subsys_vendor;
+       u32 subsys_device;
+};
+
+/* cards with dpm stability problems */
+static struct radeon_dpm_quirk radeon_dpm_quirk_list[] = {
+       /* TURKS - https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1386534 */
+       { PCI_VENDOR_ID_ATI, 0x6759, 0x1682, 0x3195 },
+       /* TURKS - https://bugzilla.kernel.org/show_bug.cgi?id=83731 */
+       { PCI_VENDOR_ID_ATI, 0x6840, 0x1179, 0xfb81 },
+       { 0, 0, 0, 0 },
+};
+
 int radeon_pm_init(struct radeon_device *rdev)
 {
+       struct radeon_dpm_quirk *p = radeon_dpm_quirk_list;
+       bool disable_dpm = false;
+
+       /* Apply dpm quirks */
+       while (p && p->chip_device != 0) {
+               if (rdev->pdev->vendor == p->chip_vendor &&
+                   rdev->pdev->device == p->chip_device &&
+                   rdev->pdev->subsystem_vendor == p->subsys_vendor &&
+                   rdev->pdev->subsystem_device == p->subsys_device) {
+                       disable_dpm = true;
+                       break;
+               }
+               ++p;
+       }
+
        /* enable dpm on rv6xx+ */
        switch (rdev->family) {
        case CHIP_RV610:
@@ -1344,6 +1375,8 @@ int radeon_pm_init(struct radeon_device *rdev)
                         (!(rdev->flags & RADEON_IS_IGP)) &&
                         (!rdev->smc_fw))
                        rdev->pm.pm_method = PM_METHOD_PROFILE;
+               else if (disable_dpm && (radeon_dpm == -1))
+                       rdev->pm.pm_method = PM_METHOD_PROFILE;
                else if (radeon_dpm == 0)
                        rdev->pm.pm_method = PM_METHOD_PROFILE;
                else
index 535403e0c8a28c20011261decb68eeb3d47b6846..15aee723db77ec171a5b8a32797d75e3d49e1469 100644 (file)
@@ -1703,7 +1703,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
        u32 format;
        u32 *buffer;
        const u8 __user *data;
-       int size, dwords, tex_width, blit_width, spitch;
+       unsigned int size, dwords, tex_width, blit_width, spitch;
        u32 height;
        int i;
        u32 texpitch, microtile;
index cde48c42b30ad4b63c27dde6741f8637840670fc..06d2246d07f19a086cddced0d1c9ffd32a2f86fd 100644 (file)
@@ -587,10 +587,8 @@ uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr)
        uint64_t result;
 
        /* page table offset */
-       result = rdev->gart.pages_addr[addr >> PAGE_SHIFT];
-
-       /* in case cpu page size != gpu page size*/
-       result |= addr & (~PAGE_MASK);
+       result = rdev->gart.pages_entry[addr >> RADEON_GPU_PAGE_SHIFT];
+       result &= ~RADEON_GPU_PAGE_MASK;
 
        return result;
 }
index c5799f16aa4b2f27157b3946ec4c7b65ac85011f..34e3235f41d2bf63a5333e33f63e2518f3668942 100644 (file)
@@ -212,11 +212,9 @@ void rs400_gart_fini(struct radeon_device *rdev)
 #define RS400_PTE_WRITEABLE (1 << 2)
 #define RS400_PTE_READABLE  (1 << 3)
 
-void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
-                        uint64_t addr, uint32_t flags)
+uint64_t rs400_gart_get_page_entry(uint64_t addr, uint32_t flags)
 {
        uint32_t entry;
-       u32 *gtt = rdev->gart.ptr;
 
        entry = (lower_32_bits(addr) & PAGE_MASK) |
                ((upper_32_bits(addr) & 0xff) << 4);
@@ -226,8 +224,14 @@ void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
                entry |= RS400_PTE_WRITEABLE;
        if (!(flags & RADEON_GART_PAGE_SNOOP))
                entry |= RS400_PTE_UNSNOOPED;
-       entry = cpu_to_le32(entry);
-       gtt[i] = entry;
+       return entry;
+}
+
+void rs400_gart_set_page(struct radeon_device *rdev, unsigned i,
+                        uint64_t entry)
+{
+       u32 *gtt = rdev->gart.ptr;
+       gtt[i] = cpu_to_le32(lower_32_bits(entry));
 }
 
 int rs400_mc_wait_for_idle(struct radeon_device *rdev)
index 9acb1c3c005b6ead68e940ba5443b88d3de0be0b..74bce91aecc11856dd5601c1fb19326014029471 100644 (file)
@@ -625,11 +625,8 @@ static void rs600_gart_fini(struct radeon_device *rdev)
        radeon_gart_table_vram_free(rdev);
 }
 
-void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
-                        uint64_t addr, uint32_t flags)
+uint64_t rs600_gart_get_page_entry(uint64_t addr, uint32_t flags)
 {
-       void __iomem *ptr = (void *)rdev->gart.ptr;
-
        addr = addr & 0xFFFFFFFFFFFFF000ULL;
        addr |= R600_PTE_SYSTEM;
        if (flags & RADEON_GART_PAGE_VALID)
@@ -640,7 +637,14 @@ void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
                addr |= R600_PTE_WRITEABLE;
        if (flags & RADEON_GART_PAGE_SNOOP)
                addr |= R600_PTE_SNOOPED;
-       writeq(addr, ptr + (i * 8));
+       return addr;
+}
+
+void rs600_gart_set_page(struct radeon_device *rdev, unsigned i,
+                        uint64_t entry)
+{
+       void __iomem *ptr = (void *)rdev->gart.ptr;
+       writeq(entry, ptr + (i * 8));
 }
 
 int rs600_irq_set(struct radeon_device *rdev)
index 60df444bd0756fbe42b5a5dab1072f47c5c73a3a..5d89b874a1a25851aa331af54f3ae6a0fd7c39cc 100644 (file)
@@ -5057,6 +5057,16 @@ void si_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 1 << vm_id);
 
+       /* wait for the invalidate to complete */
+       radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       radeon_ring_write(ring, (WAIT_REG_MEM_FUNCTION(0) |  /* always */
+                                WAIT_REG_MEM_ENGINE(0))); /* me */
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST >> 2);
+       radeon_ring_write(ring, 0);
+       radeon_ring_write(ring, 0); /* ref */
+       radeon_ring_write(ring, 0); /* mask */
+       radeon_ring_write(ring, 0x20); /* poll interval */
+
        /* sync PFP to ME, otherwise we might get invalid PFP reads */
        radeon_ring_write(ring, PACKET3(PACKET3_PFP_SYNC_ME, 0));
        radeon_ring_write(ring, 0x0);
index f5cc777e1c5f142ff00b383e3863b70b47a96b3e..83207929fc627f9a813acada5740c9ad14bb6bf1 100644 (file)
@@ -123,7 +123,6 @@ void si_dma_vm_write_pages(struct radeon_device *rdev,
                for (; ndw > 0; ndw -= 2, --count, pe += 8) {
                        if (flags & R600_PTE_SYSTEM) {
                                value = radeon_vm_map_gart(rdev, addr);
-                               value &= 0xFFFFFFFFFFFFF000ULL;
                        } else if (flags & R600_PTE_VALID) {
                                value = addr;
                        } else {
@@ -206,6 +205,14 @@ void si_dma_vm_flush(struct radeon_device *rdev, struct radeon_ring *ring,
        radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_SRBM_WRITE, 0, 0, 0, 0));
        radeon_ring_write(ring, (0xf << 16) | (VM_INVALIDATE_REQUEST >> 2));
        radeon_ring_write(ring, 1 << vm_id);
+
+       /* wait for invalidate to complete */
+       radeon_ring_write(ring, DMA_PACKET(DMA_PACKET_POLL_REG_MEM, 0, 0, 0, 0));
+       radeon_ring_write(ring, VM_INVALIDATE_REQUEST);
+       radeon_ring_write(ring, 0xff << 16); /* retry */
+       radeon_ring_write(ring, 1 << vm_id); /* mask */
+       radeon_ring_write(ring, 0); /* value */
+       radeon_ring_write(ring, (0 << 28) | 0x20); /* func(always) | poll interval */
 }
 
 /**
index 32e354b8b0aba6b96cfc8e94b1519b7fca4f47fb..eff8a6444956310a591afdf3d980f2f3288cf386 100644 (file)
@@ -2908,6 +2908,22 @@ static int si_init_smc_spll_table(struct radeon_device *rdev)
        return ret;
 }
 
+struct si_dpm_quirk {
+       u32 chip_vendor;
+       u32 chip_device;
+       u32 subsys_vendor;
+       u32 subsys_device;
+       u32 max_sclk;
+       u32 max_mclk;
+};
+
+/* cards with dpm stability problems */
+static struct si_dpm_quirk si_dpm_quirk_list[] = {
+       /* PITCAIRN - https://bugs.freedesktop.org/show_bug.cgi?id=76490 */
+       { PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
+       { 0, 0, 0, 0 },
+};
+
 static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                                        struct radeon_ps *rps)
 {
@@ -2918,7 +2934,22 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
        u32 mclk, sclk;
        u16 vddc, vddci;
        u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
+       u32 max_sclk = 0, max_mclk = 0;
        int i;
+       struct si_dpm_quirk *p = si_dpm_quirk_list;
+
+       /* Apply dpm quirks */
+       while (p && p->chip_device != 0) {
+               if (rdev->pdev->vendor == p->chip_vendor &&
+                   rdev->pdev->device == p->chip_device &&
+                   rdev->pdev->subsystem_vendor == p->subsys_vendor &&
+                   rdev->pdev->subsystem_device == p->subsys_device) {
+                       max_sclk = p->max_sclk;
+                       max_mclk = p->max_mclk;
+                       break;
+               }
+               ++p;
+       }
 
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
            ni_dpm_vblank_too_short(rdev))
@@ -2972,6 +3003,14 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev,
                        if (ps->performance_levels[i].mclk > max_mclk_vddc)
                                ps->performance_levels[i].mclk = max_mclk_vddc;
                }
+               if (max_mclk) {
+                       if (ps->performance_levels[i].mclk > max_mclk)
+                               ps->performance_levels[i].mclk = max_mclk;
+               }
+               if (max_sclk) {
+                       if (ps->performance_levels[i].sclk > max_sclk)
+                               ps->performance_levels[i].sclk = max_sclk;
+               }
        }
 
        /* XXX validate the min clocks required for display */
index 4069be89e5852852ff4e884630571908dda6e387..84999242c74746317dfeed4954fee7baec4019e7 100644 (file)
 #define        PACKET3_MPEG_INDEX                              0x3A
 #define        PACKET3_COPY_DW                                 0x3B
 #define        PACKET3_WAIT_REG_MEM                            0x3C
+#define                WAIT_REG_MEM_FUNCTION(x)                ((x) << 0)
+                /* 0 - always
+                * 1 - <
+                * 2 - <=
+                * 3 - ==
+                * 4 - !=
+                * 5 - >=
+                * 6 - >
+                */
+#define                WAIT_REG_MEM_MEM_SPACE(x)               ((x) << 4)
+                /* 0 - reg
+                * 1 - mem
+                */
+#define                WAIT_REG_MEM_ENGINE(x)                  ((x) << 8)
+                /* 0 - me
+                * 1 - pfp
+                */
 #define        PACKET3_MEM_WRITE                               0x3D
 #define        PACKET3_COPY_DATA                               0x40
 #define        PACKET3_CP_DMA                                  0x41
 #define        DMA_PACKET_TRAP                                   0x7
 #define        DMA_PACKET_SRBM_WRITE                             0x9
 #define        DMA_PACKET_CONSTANT_FILL                          0xd
+#define        DMA_PACKET_POLL_REG_MEM                           0xe
 #define        DMA_PACKET_NOP                                    0xf
 
 #define VCE_STATUS                                     0x20004
index 3367960286a6f162455e0363a54dace2c6882883..978993fa3a360ef426b6dc48a3c287c3eda0cf48 100644 (file)
@@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
                                 const struct tegra_dc_window *window)
 {
        unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
-       unsigned long value;
+       unsigned long value, flags;
        bool yuv, planar;
 
        /*
@@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
        else
                bpp = planar ? 1 : 2;
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        value = WINDOW_A_SELECT << index;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
 
@@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
 
                case TEGRA_BO_TILING_MODE_BLOCK:
                        DRM_ERROR("hardware doesn't support block linear mode\n");
+                       spin_unlock_irqrestore(&dc->lock, flags);
                        return -EINVAL;
                }
 
@@ -331,6 +334,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
 
        tegra_dc_window_commit(dc, index);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        return 0;
 }
 
@@ -338,11 +343,14 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
 {
        struct tegra_dc *dc = to_tegra_dc(plane->crtc);
        struct tegra_plane *p = to_tegra_plane(plane);
+       unsigned long flags;
        u32 value;
 
        if (!plane->crtc)
                return 0;
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        value = WINDOW_A_SELECT << p->index;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
 
@@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
 
        tegra_dc_window_commit(dc, p->index);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        return 0;
 }
 
@@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
        unsigned int h_offset = 0, v_offset = 0;
        struct tegra_bo_tiling tiling;
+       unsigned long value, flags;
        unsigned int format, swap;
-       unsigned long value;
        int err;
 
        err = tegra_fb_get_tiling(fb, &tiling);
        if (err < 0)
                return err;
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
 
        value = fb->offsets[0] + y * fb->pitches[0] +
@@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
 
                case TEGRA_BO_TILING_MODE_BLOCK:
                        DRM_ERROR("hardware doesn't support block linear mode\n");
+                       spin_unlock_irqrestore(&dc->lock, flags);
                        return -EINVAL;
                }
 
@@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
        tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
        tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        return 0;
 }
 
@@ -814,23 +829,32 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
        unsigned long flags, base;
        struct tegra_bo *bo;
 
-       if (!dc->event)
+       spin_lock_irqsave(&drm->event_lock, flags);
+
+       if (!dc->event) {
+               spin_unlock_irqrestore(&drm->event_lock, flags);
                return;
+       }
 
        bo = tegra_fb_get_plane(crtc->primary->fb, 0);
 
+       spin_lock_irqsave(&dc->lock, flags);
+
        /* check if new start address has been latched */
+       tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
        tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
        base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
        tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
 
+       spin_unlock_irqrestore(&dc->lock, flags);
+
        if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
-               spin_lock_irqsave(&drm->event_lock, flags);
-               drm_send_vblank_event(drm, dc->pipe, dc->event);
-               drm_vblank_put(drm, dc->pipe);
+               drm_crtc_send_vblank_event(crtc, dc->event);
+               drm_crtc_vblank_put(crtc);
                dc->event = NULL;
-               spin_unlock_irqrestore(&drm->event_lock, flags);
        }
+
+       spin_unlock_irqrestore(&drm->event_lock, flags);
 }
 
 void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
@@ -843,7 +867,7 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
 
        if (dc->event && dc->event->base.file_priv == file) {
                dc->event->base.destroy(&dc->event->base);
-               drm_vblank_put(drm, dc->pipe);
+               drm_crtc_vblank_put(crtc);
                dc->event = NULL;
        }
 
@@ -853,16 +877,16 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
 static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                              struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
 {
+       unsigned int pipe = drm_crtc_index(crtc);
        struct tegra_dc *dc = to_tegra_dc(crtc);
-       struct drm_device *drm = crtc->dev;
 
        if (dc->event)
                return -EBUSY;
 
        if (event) {
-               event->pipe = dc->pipe;
+               event->pipe = pipe;
                dc->event = event;
-               drm_vblank_get(drm, dc->pipe);
+               drm_crtc_vblank_get(crtc);
        }
 
        tegra_dc_set_base(dc, 0, 0, fb);
@@ -1127,7 +1151,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *data)
                /*
                dev_dbg(dc->dev, "%s(): vertical blank\n", __func__);
                */
-               drm_handle_vblank(dc->base.dev, dc->pipe);
+               drm_crtc_handle_vblank(&dc->base);
                tegra_dc_finish_page_flip(dc);
        }
 
index e549afeece1ff12c899afc9f21dd52ff5e3e64ff..d4f827593dfa2041a386dba733f9436cbed1d111 100644 (file)
@@ -694,24 +694,28 @@ static const struct file_operations tegra_drm_fops = {
        .llseek = noop_llseek,
 };
 
-static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe)
+static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
+                                            unsigned int pipe)
 {
        struct drm_crtc *crtc;
 
        list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) {
-               struct tegra_dc *dc = to_tegra_dc(crtc);
-
-               if (dc->pipe == pipe)
+               if (pipe == drm_crtc_index(crtc))
                        return crtc;
        }
 
        return NULL;
 }
 
-static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc)
+static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
 {
+       struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
+
+       if (!crtc)
+               return 0;
+
        /* TODO: implement real hardware counter using syncpoints */
-       return drm_vblank_count(dev, crtc);
+       return drm_crtc_vblank_count(crtc);
 }
 
 static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
index da32086cbeaf28bbe0c0528eeeac4c0bb9fcb326..8777b7f757916a704ceaec670c44d34a0aee813d 100644 (file)
@@ -216,32 +216,58 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
        }
 }
 
-static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo,
-                             size_t size)
+static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
 {
+       struct scatterlist *s;
+       struct sg_table *sgt;
+       unsigned int i;
+
        bo->pages = drm_gem_get_pages(&bo->gem);
        if (IS_ERR(bo->pages))
                return PTR_ERR(bo->pages);
 
-       bo->num_pages = size >> PAGE_SHIFT;
-
-       bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
-       if (IS_ERR(bo->sgt)) {
-               drm_gem_put_pages(&bo->gem, bo->pages, false, false);
-               return PTR_ERR(bo->sgt);
+       bo->num_pages = bo->gem.size >> PAGE_SHIFT;
+
+       sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages);
+       if (IS_ERR(sgt))
+               goto put_pages;
+
+       /*
+        * Fake up the SG table so that dma_map_sg() can be used to flush the
+        * pages associated with it. Note that this relies on the fact that
+        * the DMA API doesn't hook into IOMMU on Tegra, therefore mapping is
+        * only cache maintenance.
+        *
+        * TODO: Replace this by drm_clflash_sg() once it can be implemented
+        * without relying on symbols that are not exported.
+        */
+       for_each_sg(sgt->sgl, s, sgt->nents, i)
+               sg_dma_address(s) = sg_phys(s);
+
+       if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) {
+               sgt = ERR_PTR(-ENOMEM);
+               goto release_sgt;
        }
 
+       bo->sgt = sgt;
+
        return 0;
+
+release_sgt:
+       sg_free_table(sgt);
+       kfree(sgt);
+put_pages:
+       drm_gem_put_pages(&bo->gem, bo->pages, false, false);
+       return PTR_ERR(sgt);
 }
 
-static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo,
-                         size_t size)
+static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo)
 {
        struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        if (tegra->domain) {
-               err = tegra_bo_get_pages(drm, bo, size);
+               err = tegra_bo_get_pages(drm, bo);
                if (err < 0)
                        return err;
 
@@ -251,6 +277,8 @@ static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo,
                        return err;
                }
        } else {
+               size_t size = bo->gem.size;
+
                bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr,
                                                   GFP_KERNEL | __GFP_NOWARN);
                if (!bo->vaddr) {
@@ -274,7 +302,7 @@ struct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size,
        if (IS_ERR(bo))
                return bo;
 
-       err = tegra_bo_alloc(drm, bo, size);
+       err = tegra_bo_alloc(drm, bo);
        if (err < 0)
                goto release;
 
index 7b5d22110f25e7619c37eac7fd66858fa25b93e8..6c6b655defcf4eac679913e70896810208dfd6ce 100644 (file)
@@ -406,11 +406,9 @@ int vmw_3d_resource_inc(struct vmw_private *dev_priv,
                if (unlikely(ret != 0))
                        --dev_priv->num_3d_resources;
        } else if (unhide_svga) {
-               mutex_lock(&dev_priv->hw_mutex);
                vmw_write(dev_priv, SVGA_REG_ENABLE,
                          vmw_read(dev_priv, SVGA_REG_ENABLE) &
                          ~SVGA_REG_ENABLE_HIDE);
-               mutex_unlock(&dev_priv->hw_mutex);
        }
 
        mutex_unlock(&dev_priv->release_mutex);
@@ -433,13 +431,10 @@ void vmw_3d_resource_dec(struct vmw_private *dev_priv,
        mutex_lock(&dev_priv->release_mutex);
        if (unlikely(--dev_priv->num_3d_resources == 0))
                vmw_release_device(dev_priv);
-       else if (hide_svga) {
-               mutex_lock(&dev_priv->hw_mutex);
+       else if (hide_svga)
                vmw_write(dev_priv, SVGA_REG_ENABLE,
                          vmw_read(dev_priv, SVGA_REG_ENABLE) |
                          SVGA_REG_ENABLE_HIDE);
-               mutex_unlock(&dev_priv->hw_mutex);
-       }
 
        n3d = (int32_t) dev_priv->num_3d_resources;
        mutex_unlock(&dev_priv->release_mutex);
@@ -600,12 +595,14 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        dev_priv->dev = dev;
        dev_priv->vmw_chipset = chipset;
        dev_priv->last_read_seqno = (uint32_t) -100;
-       mutex_init(&dev_priv->hw_mutex);
        mutex_init(&dev_priv->cmdbuf_mutex);
        mutex_init(&dev_priv->release_mutex);
        mutex_init(&dev_priv->binding_mutex);
        rwlock_init(&dev_priv->resource_lock);
        ttm_lock_init(&dev_priv->reservation_sem);
+       spin_lock_init(&dev_priv->hw_lock);
+       spin_lock_init(&dev_priv->waiter_lock);
+       spin_lock_init(&dev_priv->cap_lock);
 
        for (i = vmw_res_context; i < vmw_res_max; ++i) {
                idr_init(&dev_priv->res_idr[i]);
@@ -626,14 +623,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 
        dev_priv->enable_fb = enable_fbdev;
 
-       mutex_lock(&dev_priv->hw_mutex);
-
        vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
        svga_id = vmw_read(dev_priv, SVGA_REG_ID);
        if (svga_id != SVGA_ID_2) {
                ret = -ENOSYS;
                DRM_ERROR("Unsupported SVGA ID 0x%x\n", svga_id);
-               mutex_unlock(&dev_priv->hw_mutex);
                goto out_err0;
        }
 
@@ -683,10 +677,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                dev_priv->prim_bb_mem = dev_priv->vram_size;
 
        ret = vmw_dma_masks(dev_priv);
-       if (unlikely(ret != 0)) {
-               mutex_unlock(&dev_priv->hw_mutex);
+       if (unlikely(ret != 0))
                goto out_err0;
-       }
 
        /*
         * Limit back buffer size to VRAM size.  Remove this once
@@ -695,8 +687,6 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        if (dev_priv->prim_bb_mem > dev_priv->vram_size)
                dev_priv->prim_bb_mem = dev_priv->vram_size;
 
-       mutex_unlock(&dev_priv->hw_mutex);
-
        vmw_print_capabilities(dev_priv->capabilities);
 
        if (dev_priv->capabilities & SVGA_CAP_GMR2) {
@@ -1160,9 +1150,7 @@ static int vmw_master_set(struct drm_device *dev,
                if (unlikely(ret != 0))
                        return ret;
                vmw_kms_save_vga(dev_priv);
-               mutex_lock(&dev_priv->hw_mutex);
                vmw_write(dev_priv, SVGA_REG_TRACES, 0);
-               mutex_unlock(&dev_priv->hw_mutex);
        }
 
        if (active) {
@@ -1196,9 +1184,7 @@ out_no_active_lock:
        if (!dev_priv->enable_fb) {
                vmw_kms_restore_vga(dev_priv);
                vmw_3d_resource_dec(dev_priv, true);
-               mutex_lock(&dev_priv->hw_mutex);
                vmw_write(dev_priv, SVGA_REG_TRACES, 1);
-               mutex_unlock(&dev_priv->hw_mutex);
        }
        return ret;
 }
@@ -1233,9 +1219,7 @@ static void vmw_master_drop(struct drm_device *dev,
                        DRM_ERROR("Unable to clean VRAM on master drop.\n");
                vmw_kms_restore_vga(dev_priv);
                vmw_3d_resource_dec(dev_priv, true);
-               mutex_lock(&dev_priv->hw_mutex);
                vmw_write(dev_priv, SVGA_REG_TRACES, 1);
-               mutex_unlock(&dev_priv->hw_mutex);
        }
 
        dev_priv->active_master = &dev_priv->fbdev_master;
@@ -1367,10 +1351,8 @@ static void vmw_pm_complete(struct device *kdev)
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct vmw_private *dev_priv = vmw_priv(dev);
 
-       mutex_lock(&dev_priv->hw_mutex);
        vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
        (void) vmw_read(dev_priv, SVGA_REG_ID);
-       mutex_unlock(&dev_priv->hw_mutex);
 
        /**
         * Reclaim 3d reference held by fbdev and potentially
index 4ee799b43d5dfc40a8077e60e9f34b17a8dddcf9..d26a6daa9719a23542cb8c575691f1d63851dba4 100644 (file)
@@ -399,7 +399,8 @@ struct vmw_private {
        uint32_t memory_size;
        bool has_gmr;
        bool has_mob;
-       struct mutex hw_mutex;
+       spinlock_t hw_lock;
+       spinlock_t cap_lock;
 
        /*
         * VGA registers.
@@ -449,8 +450,9 @@ struct vmw_private {
        atomic_t marker_seq;
        wait_queue_head_t fence_queue;
        wait_queue_head_t fifo_queue;
-       int fence_queue_waiters; /* Protected by hw_mutex */
-       int goal_queue_waiters; /* Protected by hw_mutex */
+       spinlock_t waiter_lock;
+       int fence_queue_waiters; /* Protected by waiter_lock */
+       int goal_queue_waiters; /* Protected by waiter_lock */
        atomic_t fifo_queue_waiters;
        uint32_t last_read_seqno;
        spinlock_t irq_lock;
@@ -553,20 +555,35 @@ static inline struct vmw_master *vmw_master(struct drm_master *master)
        return (struct vmw_master *) master->driver_priv;
 }
 
+/*
+ * The locking here is fine-grained, so that it is performed once
+ * for every read- and write operation. This is of course costly, but we
+ * don't perform much register access in the timing critical paths anyway.
+ * Instead we have the extra benefit of being sure that we don't forget
+ * the hw lock around register accesses.
+ */
 static inline void vmw_write(struct vmw_private *dev_priv,
                             unsigned int offset, uint32_t value)
 {
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&dev_priv->hw_lock, irq_flags);
        outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT);
        outl(value, dev_priv->io_start + VMWGFX_VALUE_PORT);
+       spin_unlock_irqrestore(&dev_priv->hw_lock, irq_flags);
 }
 
 static inline uint32_t vmw_read(struct vmw_private *dev_priv,
                                unsigned int offset)
 {
-       uint32_t val;
+       unsigned long irq_flags;
+       u32 val;
 
+       spin_lock_irqsave(&dev_priv->hw_lock, irq_flags);
        outl(offset, dev_priv->io_start + VMWGFX_INDEX_PORT);
        val = inl(dev_priv->io_start + VMWGFX_VALUE_PORT);
+       spin_unlock_irqrestore(&dev_priv->hw_lock, irq_flags);
+
        return val;
 }
 
index b7594cb758afc4299493122f4f6e44c68ef4d919..945f1e0dad9278145eed43708cb820dc54a566a3 100644 (file)
@@ -35,7 +35,7 @@ struct vmw_fence_manager {
        struct vmw_private *dev_priv;
        spinlock_t lock;
        struct list_head fence_list;
-       struct work_struct work, ping_work;
+       struct work_struct work;
        u32 user_fence_size;
        u32 fence_size;
        u32 event_fence_action_size;
@@ -134,14 +134,6 @@ static const char *vmw_fence_get_timeline_name(struct fence *f)
        return "svga";
 }
 
-static void vmw_fence_ping_func(struct work_struct *work)
-{
-       struct vmw_fence_manager *fman =
-               container_of(work, struct vmw_fence_manager, ping_work);
-
-       vmw_fifo_ping_host(fman->dev_priv, SVGA_SYNC_GENERIC);
-}
-
 static bool vmw_fence_enable_signaling(struct fence *f)
 {
        struct vmw_fence_obj *fence =
@@ -155,11 +147,7 @@ static bool vmw_fence_enable_signaling(struct fence *f)
        if (seqno - fence->base.seqno < VMW_FENCE_WRAP)
                return false;
 
-       if (mutex_trylock(&dev_priv->hw_mutex)) {
-               vmw_fifo_ping_host_locked(dev_priv, SVGA_SYNC_GENERIC);
-               mutex_unlock(&dev_priv->hw_mutex);
-       } else
-               schedule_work(&fman->ping_work);
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
 
        return true;
 }
@@ -305,7 +293,6 @@ struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
        INIT_LIST_HEAD(&fman->fence_list);
        INIT_LIST_HEAD(&fman->cleanup_list);
        INIT_WORK(&fman->work, &vmw_fence_work_func);
-       INIT_WORK(&fman->ping_work, &vmw_fence_ping_func);
        fman->fifo_down = true;
        fman->user_fence_size = ttm_round_pot(sizeof(struct vmw_user_fence));
        fman->fence_size = ttm_round_pot(sizeof(struct vmw_fence_obj));
@@ -323,7 +310,6 @@ void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
        bool lists_empty;
 
        (void) cancel_work_sync(&fman->work);
-       (void) cancel_work_sync(&fman->ping_work);
 
        spin_lock_irqsave(&fman->lock, irq_flags);
        lists_empty = list_empty(&fman->fence_list) &&
index 09e10aefcd8eb94e6a22182b59591cdb30cbcd36..39f2b03888e7e5b7beb107cd0a32aa0345a328be 100644 (file)
@@ -44,10 +44,10 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
                if (!dev_priv->has_mob)
                        return false;
 
-               mutex_lock(&dev_priv->hw_mutex);
+               spin_lock(&dev_priv->cap_lock);
                vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D);
                result = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
-               mutex_unlock(&dev_priv->hw_mutex);
+               spin_unlock(&dev_priv->cap_lock);
 
                return (result != 0);
        }
@@ -120,7 +120,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
        DRM_INFO("height %d\n", vmw_read(dev_priv, SVGA_REG_HEIGHT));
        DRM_INFO("bpp %d\n", vmw_read(dev_priv, SVGA_REG_BITS_PER_PIXEL));
 
-       mutex_lock(&dev_priv->hw_mutex);
        dev_priv->enable_state = vmw_read(dev_priv, SVGA_REG_ENABLE);
        dev_priv->config_done_state = vmw_read(dev_priv, SVGA_REG_CONFIG_DONE);
        dev_priv->traces_state = vmw_read(dev_priv, SVGA_REG_TRACES);
@@ -143,7 +142,6 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
        mb();
 
        vmw_write(dev_priv, SVGA_REG_CONFIG_DONE, 1);
-       mutex_unlock(&dev_priv->hw_mutex);
 
        max = ioread32(fifo_mem + SVGA_FIFO_MAX);
        min = ioread32(fifo_mem  + SVGA_FIFO_MIN);
@@ -160,31 +158,28 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
        return vmw_fifo_send_fence(dev_priv, &dummy);
 }
 
-void vmw_fifo_ping_host_locked(struct vmw_private *dev_priv, uint32_t reason)
+void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
 {
        __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+       static DEFINE_SPINLOCK(ping_lock);
+       unsigned long irq_flags;
 
+       /*
+        * The ping_lock is needed because we don't have an atomic
+        * test-and-set of the SVGA_FIFO_BUSY register.
+        */
+       spin_lock_irqsave(&ping_lock, irq_flags);
        if (unlikely(ioread32(fifo_mem + SVGA_FIFO_BUSY) == 0)) {
                iowrite32(1, fifo_mem + SVGA_FIFO_BUSY);
                vmw_write(dev_priv, SVGA_REG_SYNC, reason);
        }
-}
-
-void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason)
-{
-       mutex_lock(&dev_priv->hw_mutex);
-
-       vmw_fifo_ping_host_locked(dev_priv, reason);
-
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock_irqrestore(&ping_lock, irq_flags);
 }
 
 void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
 {
        __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
 
-       mutex_lock(&dev_priv->hw_mutex);
-
        vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
        while (vmw_read(dev_priv, SVGA_REG_BUSY) != 0)
                ;
@@ -198,7 +193,6 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
        vmw_write(dev_priv, SVGA_REG_TRACES,
                  dev_priv->traces_state);
 
-       mutex_unlock(&dev_priv->hw_mutex);
        vmw_marker_queue_takedown(&fifo->marker_queue);
 
        if (likely(fifo->static_buffer != NULL)) {
@@ -271,7 +265,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
                return vmw_fifo_wait_noirq(dev_priv, bytes,
                                           interruptible, timeout);
 
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->waiter_lock);
        if (atomic_add_return(1, &dev_priv->fifo_queue_waiters) > 0) {
                spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
                outl(SVGA_IRQFLAG_FIFO_PROGRESS,
@@ -280,7 +274,7 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
                vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->waiter_lock);
 
        if (interruptible)
                ret = wait_event_interruptible_timeout
@@ -296,14 +290,14 @@ static int vmw_fifo_wait(struct vmw_private *dev_priv,
        else if (likely(ret > 0))
                ret = 0;
 
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->waiter_lock);
        if (atomic_dec_and_test(&dev_priv->fifo_queue_waiters)) {
                spin_lock_irqsave(&dev_priv->irq_lock, irq_flags);
                dev_priv->irq_mask &= ~SVGA_IRQFLAG_FIFO_PROGRESS;
                vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->waiter_lock);
 
        return ret;
 }
index 37881ecf5d7a9f74c49d4e1c018abc1cc2a9dffd..69c8ce23123c96af22c44011ff2b8fcdab837584 100644 (file)
@@ -135,13 +135,13 @@ static int vmw_fill_compat_cap(struct vmw_private *dev_priv, void *bounce,
                (pair_offset + max_size * sizeof(SVGA3dCapPair)) / sizeof(u32);
        compat_cap->header.type = SVGA3DCAPS_RECORD_DEVCAPS;
 
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->cap_lock);
        for (i = 0; i < max_size; ++i) {
                vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
                compat_cap->pairs[i][0] = i;
                compat_cap->pairs[i][1] = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->cap_lock);
 
        return 0;
 }
@@ -191,12 +191,12 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
                if (num > SVGA3D_DEVCAP_MAX)
                        num = SVGA3D_DEVCAP_MAX;
 
-               mutex_lock(&dev_priv->hw_mutex);
+               spin_lock(&dev_priv->cap_lock);
                for (i = 0; i < num; ++i) {
                        vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
                        *bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
                }
-               mutex_unlock(&dev_priv->hw_mutex);
+               spin_unlock(&dev_priv->cap_lock);
        } else if (gb_objects) {
                ret = vmw_fill_compat_cap(dev_priv, bounce, size);
                if (unlikely(ret != 0))
index 0c423766c44119ca923825e879e3d05b7058cc90..9fe9827ee499c177e50735d1acbf84d13eb606f0 100644 (file)
@@ -62,13 +62,8 @@ irqreturn_t vmw_irq_handler(int irq, void *arg)
 
 static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t seqno)
 {
-       uint32_t busy;
 
-       mutex_lock(&dev_priv->hw_mutex);
-       busy = vmw_read(dev_priv, SVGA_REG_BUSY);
-       mutex_unlock(&dev_priv->hw_mutex);
-
-       return (busy == 0);
+       return (vmw_read(dev_priv, SVGA_REG_BUSY) == 0);
 }
 
 void vmw_update_seqno(struct vmw_private *dev_priv,
@@ -184,7 +179,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
 
 void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
 {
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->waiter_lock);
        if (dev_priv->fence_queue_waiters++ == 0) {
                unsigned long irq_flags;
 
@@ -195,12 +190,12 @@ void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
                vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->waiter_lock);
 }
 
 void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
 {
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->waiter_lock);
        if (--dev_priv->fence_queue_waiters == 0) {
                unsigned long irq_flags;
 
@@ -209,13 +204,13 @@ void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
                vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->waiter_lock);
 }
 
 
 void vmw_goal_waiter_add(struct vmw_private *dev_priv)
 {
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->waiter_lock);
        if (dev_priv->goal_queue_waiters++ == 0) {
                unsigned long irq_flags;
 
@@ -226,12 +221,12 @@ void vmw_goal_waiter_add(struct vmw_private *dev_priv)
                vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->waiter_lock);
 }
 
 void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
 {
-       mutex_lock(&dev_priv->hw_mutex);
+       spin_lock(&dev_priv->waiter_lock);
        if (--dev_priv->goal_queue_waiters == 0) {
                unsigned long irq_flags;
 
@@ -240,7 +235,7 @@ void vmw_goal_waiter_remove(struct vmw_private *dev_priv)
                vmw_write(dev_priv, SVGA_REG_IRQMASK, dev_priv->irq_mask);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irq_flags);
        }
-       mutex_unlock(&dev_priv->hw_mutex);
+       spin_unlock(&dev_priv->waiter_lock);
 }
 
 int vmw_wait_seqno(struct vmw_private *dev_priv,
@@ -315,9 +310,7 @@ void vmw_irq_uninstall(struct drm_device *dev)
        if (!(dev_priv->capabilities & SVGA_CAP_IRQMASK))
                return;
 
-       mutex_lock(&dev_priv->hw_mutex);
        vmw_write(dev_priv, SVGA_REG_IRQMASK, 0);
-       mutex_unlock(&dev_priv->hw_mutex);
 
        status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
        outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
index 3725b521d9319c9b952bf3920bfcd3a27c61dac3..8725b79e7847d68239a25413c482883e44024704 100644 (file)
@@ -1828,9 +1828,7 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force)
        struct vmw_private *dev_priv = vmw_priv(dev);
        struct vmw_display_unit *du = vmw_connector_to_du(connector);
 
-       mutex_lock(&dev_priv->hw_mutex);
        num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS);
-       mutex_unlock(&dev_priv->hw_mutex);
 
        return ((vmw_connector_to_du(connector)->unit < num_displays &&
                 du->pref_active) ?
index 230b6f887cd86e9b4d3d4bf625166c878d5524ed..dfdc26970022998adfb951f50baacb0e4df38474 100644 (file)
@@ -27,7 +27,8 @@ if HID
 
 config HID_BATTERY_STRENGTH
        bool "Battery level reporting for HID devices"
-       depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
+       depends on HID
+       select POWER_SUPPLY
        default n
        ---help---
        This option adds support of reporting battery strength (for HID devices
index c3d0ac1a0988096eaacbe8063b354399b6a85e14..8b638792cb43c426c2e4fffb0bb594e76617f554 100644 (file)
@@ -1805,6 +1805,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
index 7460f3402298c2e1925059a1ef5cbf669e9d381b..9243359c18219ab75c5e47bda83ed44f3d322f05 100644 (file)
 #define USB_DEVICE_ID_KYE_GPEN_560     0x5003
 #define USB_DEVICE_ID_KYE_EASYPEN_I405X        0x5010
 #define USB_DEVICE_ID_KYE_MOUSEPEN_I608X       0x5011
+#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2     0x501a
 #define USB_DEVICE_ID_KYE_EASYPEN_M610X        0x5013
 
 #define USB_VENDOR_ID_LABTEC           0x1020
index e0a0f06ac5ef6168c8fcdd5c2462df3f3130c941..9505605b6e22a72b29661d568aa6fe4dcaa32643 100644 (file)
@@ -311,6 +311,9 @@ static const struct hid_device_id hid_battery_quirks[] = {
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                               USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
          HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+                              USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
+         HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
                USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
          HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
index b92bf01a1ae8122f486ea333288558f082162f5d..158fcf577fae570d331a37c46d650a151141c19c 100644 (file)
@@ -323,6 +323,7 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
                }
                break;
        case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
+       case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2:
                if (*rsize == MOUSEPEN_I608X_RDESC_ORIG_SIZE) {
                        rdesc = mousepen_i608x_rdesc_fixed;
                        *rsize = sizeof(mousepen_i608x_rdesc_fixed);
@@ -415,6 +416,7 @@ static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id)
        switch (id->product) {
        case USB_DEVICE_ID_KYE_EASYPEN_I405X:
        case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
+       case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2:
        case USB_DEVICE_ID_KYE_EASYPEN_M610X:
                ret = kye_tablet_enable(hdev);
                if (ret) {
@@ -445,6 +447,8 @@ static const struct hid_device_id kye_devices[] = {
                                USB_DEVICE_ID_KYE_EASYPEN_I405X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
                                USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
+                               USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
                                USB_DEVICE_ID_KYE_EASYPEN_M610X) },
        { HID_USB_DEVICE(USB_VENDOR_ID_KYE,
index c917ab61aafa6156b433ed3148a31384ac6d4292..5bc6d80d5be79f465f3cbbb686c471db6162eb63 100644 (file)
@@ -962,10 +962,24 @@ static int logi_dj_raw_event(struct hid_device *hdev,
 
        switch (data[0]) {
        case REPORT_ID_DJ_SHORT:
+               if (size != DJREPORT_SHORT_LENGTH) {
+                       dev_err(&hdev->dev, "DJ report of bad size (%d)", size);
+                       return false;
+               }
                return logi_dj_dj_event(hdev, report, data, size);
        case REPORT_ID_HIDPP_SHORT:
-               /* intentional fallthrough */
+               if (size != HIDPP_REPORT_SHORT_LENGTH) {
+                       dev_err(&hdev->dev,
+                               "Short HID++ report of bad size (%d)", size);
+                       return false;
+               }
+               return logi_dj_hidpp_event(hdev, report, data, size);
        case REPORT_ID_HIDPP_LONG:
+               if (size != HIDPP_REPORT_LONG_LENGTH) {
+                       dev_err(&hdev->dev,
+                               "Long HID++ report of bad size (%d)", size);
+                       return false;
+               }
                return logi_dj_hidpp_event(hdev, report, data, size);
        }
 
index 2f420c0b6609b1f197a15be182d07102323b3973..a93cefe0e522e66fe670a28a269f13da9ff25d5d 100644 (file)
@@ -282,6 +282,33 @@ static inline bool hidpp_report_is_connect_event(struct hidpp_report *report)
                (report->rap.sub_id == 0x41);
 }
 
+/**
+ * hidpp_prefix_name() prefixes the current given name with "Logitech ".
+ */
+static void hidpp_prefix_name(char **name, int name_length)
+{
+#define PREFIX_LENGTH 9 /* "Logitech " */
+
+       int new_length;
+       char *new_name;
+
+       if (name_length > PREFIX_LENGTH &&
+           strncmp(*name, "Logitech ", PREFIX_LENGTH) == 0)
+               /* The prefix has is already in the name */
+               return;
+
+       new_length = PREFIX_LENGTH + name_length;
+       new_name = kzalloc(new_length, GFP_KERNEL);
+       if (!new_name)
+               return;
+
+       snprintf(new_name, new_length, "Logitech %s", *name);
+
+       kfree(*name);
+
+       *name = new_name;
+}
+
 /* -------------------------------------------------------------------------- */
 /* HIDP++ 1.0 commands                                                        */
 /* -------------------------------------------------------------------------- */
@@ -321,6 +348,10 @@ static char *hidpp_get_unifying_name(struct hidpp_device *hidpp_dev)
                return NULL;
 
        memcpy(name, &response.rap.params[2], len);
+
+       /* include the terminating '\0' */
+       hidpp_prefix_name(&name, len + 1);
+
        return name;
 }
 
@@ -498,6 +529,9 @@ static char *hidpp_get_device_name(struct hidpp_device *hidpp)
                index += ret;
        }
 
+       /* include the terminating '\0' */
+       hidpp_prefix_name(&name, __name_length + 1);
+
        return name;
 }
 
@@ -794,18 +828,25 @@ static int wtp_raw_event(struct hid_device *hdev, u8 *data, int size)
 
        switch (data[0]) {
        case 0x02:
+               if (size < 2) {
+                       hid_err(hdev, "Received HID report of bad size (%d)",
+                               size);
+                       return 1;
+               }
                if (hidpp->quirks & HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS) {
                        input_event(wd->input, EV_KEY, BTN_LEFT,
                                        !!(data[1] & 0x01));
                        input_event(wd->input, EV_KEY, BTN_RIGHT,
                                        !!(data[1] & 0x02));
                        input_sync(wd->input);
+                       return 0;
                } else {
                        if (size < 21)
                                return 1;
                        return wtp_mouse_raw_xy_event(hidpp, &data[7]);
                }
        case REPORT_ID_HIDPP_LONG:
+               /* size is already checked in hidpp_raw_event. */
                if ((report->fap.feature_index != wd->mt_feature_index) ||
                    (report->fap.funcindex_clientid != EVENT_TOUCHPAD_RAW_XY))
                        return 1;
index 1a07e07d99a06c8972a2d80b8fefa8aa4f4b3848..47d7e74231e5a3245461eb5f34a3acecc5bd67d1 100644 (file)
@@ -35,6 +35,8 @@ static struct class *pyra_class;
 static void profile_activated(struct pyra_device *pyra,
                unsigned int new_profile)
 {
+       if (new_profile >= ARRAY_SIZE(pyra->profile_settings))
+               return;
        pyra->actual_profile = new_profile;
        pyra->actual_cpi = pyra->profile_settings[pyra->actual_profile].y_cpi;
 }
@@ -257,9 +259,11 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
        if (off != 0 || count != PYRA_SIZE_SETTINGS)
                return -EINVAL;
 
-       mutex_lock(&pyra->pyra_lock);
-
        settings = (struct pyra_settings const *)buf;
+       if (settings->startup_profile >= ARRAY_SIZE(pyra->profile_settings))
+               return -EINVAL;
+
+       mutex_lock(&pyra->pyra_lock);
 
        retval = pyra_set_settings(usb_dev, settings);
        if (retval) {
index d32037cbf9db5e3bf9b1f4d96a3f8c98259a65a5..d43e967e75339ec7972e734e284c4356e31a4e38 100644 (file)
@@ -706,12 +706,7 @@ static int i2c_hid_start(struct hid_device *hid)
 
 static void i2c_hid_stop(struct hid_device *hid)
 {
-       struct i2c_client *client = hid->driver_data;
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
-
        hid->claimed = 0;
-
-       i2c_hid_free_buffers(ihid);
 }
 
 static int i2c_hid_open(struct hid_device *hid)
index dc89be90b35e80f7d14d5dcaa71dda082c8ab84b..b27b3d33ebab02b9afb7d9fc9dad2e99b31afb14 100644 (file)
@@ -124,6 +124,7 @@ static const struct hid_blacklist {
        { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
+       { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_2, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
        { USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS },
index 6529c09c46f0fe99a02ddfbcd5a643954e1d6e22..a7de26d1ac801383e2ecc57acad47f082c016ce4 100644 (file)
@@ -574,6 +574,16 @@ config SENSORS_IIO_HWMON
          for those channels specified in the map.  This map can be provided
          either via platform data or the device tree bindings.
 
+config SENSORS_I5500
+       tristate "Intel 5500/5520/X58 temperature sensor"
+       depends on X86 && PCI
+       help
+         If you say yes here you get support for the temperature
+         sensor inside the Intel 5500, 5520 and X58 chipsets.
+
+         This driver can also be built as a module. If so, the module
+         will be called i5500_temp.
+
 config SENSORS_CORETEMP
        tristate "Intel Core/Core2/Atom temperature sensor"
        depends on X86
index 67280643bcf009e5b4af58bcf61787f963f3c043..6c941472e707a51b2dfb5f6889aea07bad4ff5b7 100644 (file)
@@ -68,6 +68,7 @@ obj-$(CONFIG_SENSORS_GPIO_FAN)        += gpio-fan.o
 obj-$(CONFIG_SENSORS_HIH6130)  += hih6130.o
 obj-$(CONFIG_SENSORS_HTU21)    += htu21.o
 obj-$(CONFIG_SENSORS_ULTRA45)  += ultra45_env.o
+obj-$(CONFIG_SENSORS_I5500)    += i5500_temp.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c
new file mode 100644 (file)
index 0000000..3e3ccbf
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * i5500_temp - Driver for Intel 5500/5520/X58 chipset thermal sensor
+ *
+ * Copyright (C) 2012, 2014 Jean Delvare <jdelvare@suse.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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/device.h>
+#include <linux/pci.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/* Register definitions from datasheet */
+#define REG_TSTHRCATA  0xE2
+#define REG_TSCTRL     0xE8
+#define REG_TSTHRRPEX  0xEB
+#define REG_TSTHRLO    0xEC
+#define REG_TSTHRHI    0xEE
+#define REG_CTHINT     0xF0
+#define REG_TSFSC      0xF3
+#define REG_CTSTS      0xF4
+#define REG_TSTHRRQPI  0xF5
+#define REG_CTCTRL     0xF7
+#define REG_TSTIMER    0xF8
+
+/*
+ * Sysfs stuff
+ */
+
+/* Sensor resolution : 0.5 degree C */
+static ssize_t show_temp(struct device *dev,
+                        struct device_attribute *devattr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev->parent);
+       long temp;
+       u16 tsthrhi;
+       s8 tsfsc;
+
+       pci_read_config_word(pdev, REG_TSTHRHI, &tsthrhi);
+       pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
+       temp = ((long)tsthrhi - tsfsc) * 500;
+
+       return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t show_thresh(struct device *dev,
+                          struct device_attribute *devattr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev->parent);
+       int reg = to_sensor_dev_attr(devattr)->index;
+       long temp;
+       u16 tsthr;
+
+       pci_read_config_word(pdev, reg, &tsthr);
+       temp = tsthr * 500;
+
+       return sprintf(buf, "%ld\n", temp);
+}
+
+static ssize_t show_alarm(struct device *dev,
+                         struct device_attribute *devattr, char *buf)
+{
+       struct pci_dev *pdev = to_pci_dev(dev->parent);
+       int nr = to_sensor_dev_attr(devattr)->index;
+       u8 ctsts;
+
+       pci_read_config_byte(pdev, REG_CTSTS, &ctsts);
+       return sprintf(buf, "%u\n", (unsigned int)ctsts & (1 << nr));
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_thresh, NULL, 0xE2);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_thresh, NULL, 0xEC);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_thresh, NULL, 0xEE);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1);
+
+static struct attribute *i5500_temp_attrs[] = {
+       &dev_attr_temp1_input.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       NULL
+};
+
+ATTRIBUTE_GROUPS(i5500_temp);
+
+static const struct pci_device_id i5500_temp_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x3438) },
+       { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, i5500_temp_ids);
+
+static int i5500_temp_probe(struct pci_dev *pdev,
+                           const struct pci_device_id *id)
+{
+       int err;
+       struct device *hwmon_dev;
+       u32 tstimer;
+       s8 tsfsc;
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "Failed to enable device\n");
+               return err;
+       }
+
+       pci_read_config_byte(pdev, REG_TSFSC, &tsfsc);
+       pci_read_config_dword(pdev, REG_TSTIMER, &tstimer);
+       if (tsfsc == 0x7F && tstimer == 0x07D30D40) {
+               dev_notice(&pdev->dev, "Sensor seems to be disabled\n");
+               return -ENODEV;
+       }
+
+       hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
+                                                          "intel5500", NULL,
+                                                          i5500_temp_groups);
+       return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static struct pci_driver i5500_temp_driver = {
+       .name = "i5500_temp",
+       .id_table = i5500_temp_ids,
+       .probe = i5500_temp_probe,
+};
+
+module_pci_driver(i5500_temp_driver);
+
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
+MODULE_DESCRIPTION("Intel 5500/5520/X58 chipset thermal sensor driver");
+MODULE_LICENSE("GPL");
index 31e8308ba8990bffbaa6217aafa2bc0e72b62939..ab838d9e28b6389dc6d97dc633ea6259d2126ca3 100644 (file)
@@ -881,6 +881,7 @@ config I2C_XLR
 config I2C_RCAR
        tristate "Renesas R-Car I2C Controller"
        depends on ARCH_SHMOBILE || COMPILE_TEST
+       select I2C_SLAVE
        help
          If you say yes to this option, support will be included for the
          R-Car I2C controller.
index bff20a589621a031b37d1d1a661e4d5ba8e291b7..958c8db4ec30740e2d9aae00a7835256700d3424 100644 (file)
@@ -785,14 +785,16 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
        int ret;
 
        pm_runtime_get_sync(&adap->dev);
-       clk_prepare_enable(i2c->clk);
+       ret = clk_enable(i2c->clk);
+       if (ret)
+               return ret;
 
        for (retry = 0; retry < adap->retries; retry++) {
 
                ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
 
                if (ret != -EAGAIN) {
-                       clk_disable_unprepare(i2c->clk);
+                       clk_disable(i2c->clk);
                        pm_runtime_put(&adap->dev);
                        return ret;
                }
@@ -802,7 +804,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
                udelay(100);
        }
 
-       clk_disable_unprepare(i2c->clk);
+       clk_disable(i2c->clk);
        pm_runtime_put(&adap->dev);
        return -EREMOTEIO;
 }
@@ -1197,7 +1199,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
        clk_prepare_enable(i2c->clk);
        ret = s3c24xx_i2c_init(i2c);
-       clk_disable_unprepare(i2c->clk);
+       clk_disable(i2c->clk);
        if (ret != 0) {
                dev_err(&pdev->dev, "I2C controller init failed\n");
                return ret;
@@ -1210,6 +1212,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
                i2c->irq = ret = platform_get_irq(pdev, 0);
                if (ret <= 0) {
                        dev_err(&pdev->dev, "cannot find IRQ\n");
+                       clk_unprepare(i2c->clk);
                        return ret;
                }
 
@@ -1218,6 +1221,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
 
                if (ret != 0) {
                        dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+                       clk_unprepare(i2c->clk);
                        return ret;
                }
        }
@@ -1225,6 +1229,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        ret = s3c24xx_i2c_register_cpufreq(i2c);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+               clk_unprepare(i2c->clk);
                return ret;
        }
 
@@ -1241,6 +1246,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to add bus to i2c core\n");
                s3c24xx_i2c_deregister_cpufreq(i2c);
+               clk_unprepare(i2c->clk);
                return ret;
        }
 
@@ -1262,6 +1268,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
 {
        struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
+       clk_unprepare(i2c->clk);
+
        pm_runtime_disable(&i2c->adap.dev);
        pm_runtime_disable(&pdev->dev);
 
@@ -1293,13 +1301,16 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+       int ret;
 
        if (!IS_ERR(i2c->sysreg))
                regmap_write(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, i2c->sys_i2c_cfg);
 
-       clk_prepare_enable(i2c->clk);
+       ret = clk_enable(i2c->clk);
+       if (ret)
+               return ret;
        s3c24xx_i2c_init(i2c);
-       clk_disable_unprepare(i2c->clk);
+       clk_disable(i2c->clk);
        i2c->suspended = 0;
 
        return 0;
index 440d5dbc8b5f0c90ca3dd4341cb4a4e4858f791e..007818b3e1745bd1cb0e41a7581572aa70b2f4ea 100644 (file)
@@ -139,6 +139,7 @@ struct sh_mobile_i2c_data {
        int pos;
        int sr;
        bool send_stop;
+       bool stop_after_dma;
 
        struct resource *res;
        struct dma_chan *dma_tx;
@@ -407,7 +408,7 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
 
        if (pd->pos == pd->msg->len) {
                /* Send stop if we haven't yet (DMA case) */
-               if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY))
+               if (pd->send_stop && pd->stop_after_dma)
                        i2c_op(pd, OP_TX_STOP, 0);
                return 1;
        }
@@ -449,6 +450,13 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
                real_pos = pd->pos - 2;
 
                if (pd->pos == pd->msg->len) {
+                       if (pd->stop_after_dma) {
+                               /* Simulate PIO end condition after DMA transfer */
+                               i2c_op(pd, OP_RX_STOP, 0);
+                               pd->pos++;
+                               break;
+                       }
+
                        if (real_pos < 0) {
                                i2c_op(pd, OP_RX_STOP, 0);
                                break;
@@ -536,6 +544,7 @@ static void sh_mobile_i2c_dma_callback(void *data)
 
        sh_mobile_i2c_dma_unmap(pd);
        pd->pos = pd->msg->len;
+       pd->stop_after_dma = true;
 
        iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
 }
@@ -726,6 +735,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
                bool do_start = pd->send_stop || !i;
                msg = &msgs[i];
                pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
+               pd->stop_after_dma = false;
 
                err = start_ch(pd, msg, do_start);
                if (err)
index 39d25a8cb1ad355e099b8958afa2b5e8c2c16f75..e9eae57a2b50f77e3d25c4d9fcfa003728464740 100644 (file)
@@ -2972,6 +2972,7 @@ trace:
 }
 EXPORT_SYMBOL(i2c_smbus_xfer);
 
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
 int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
 {
        int ret;
@@ -3019,6 +3020,7 @@ int i2c_slave_unregister(struct i2c_client *client)
        return ret;
 }
 EXPORT_SYMBOL_GPL(i2c_slave_unregister);
+#endif
 
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");
index 6631400b5f02028f804343099793c780ae4c0ee5..cf9b09db092f4e9969666565ba1562220d6b2a46 100644 (file)
@@ -74,7 +74,7 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count >= attr->size)
+       if (off + count > attr->size)
                return -EFBIG;
 
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
@@ -92,7 +92,7 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
        struct eeprom_data *eeprom;
        unsigned long flags;
 
-       if (off + count >= attr->size)
+       if (off + count > attr->size)
                return -EFBIG;
 
        eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
index e37412da15f5c8ea300c7a096368d564a0acfba0..b99de00e57b86ce8164eb0b3ad02a8de11b8597e 100644 (file)
@@ -143,9 +143,15 @@ static int ad799x_write_config(struct ad799x_state *st, u16 val)
        case ad7998:
                return i2c_smbus_write_word_swapped(st->client, AD7998_CONF_REG,
                        val);
-       default:
+       case ad7992:
+       case ad7993:
+       case ad7994:
                return i2c_smbus_write_byte_data(st->client, AD7998_CONF_REG,
                        val);
+       default:
+               /* Will be written when doing a conversion */
+               st->config = val;
+               return 0;
        }
 }
 
@@ -155,8 +161,13 @@ static int ad799x_read_config(struct ad799x_state *st)
        case ad7997:
        case ad7998:
                return i2c_smbus_read_word_swapped(st->client, AD7998_CONF_REG);
-       default:
+       case ad7992:
+       case ad7993:
+       case ad7994:
                return i2c_smbus_read_byte_data(st->client, AD7998_CONF_REG);
+       default:
+               /* No readback support */
+               return st->config;
        }
 }
 
index 866fe904cba29e9f9f06d26fb0da16a9ce62b4d4..90c8cb727cc700b63f25c451c5eb4758bb3e400b 100644 (file)
@@ -449,6 +449,9 @@ static int iio_channel_read(struct iio_channel *chan, int *val, int *val2,
        if (val2 == NULL)
                val2 = &unused;
 
+       if(!iio_channel_has_info(chan->channel, info))
+               return -EINVAL;
+
        if (chan->indio_dev->info->read_raw_multi) {
                ret = chan->indio_dev->info->read_raw_multi(chan->indio_dev,
                                        chan->channel, INDIO_MAX_RAW_ELEMENTS,
index 57ecc5b204f3f6fdb01f1c2bebcdb6c752ad2ece..9117b7a2d5f8beeddebb367e421bbf7a8ca81807 100644 (file)
@@ -1114,7 +1114,8 @@ static int mlx4_ib_tunnel_steer_add(struct ib_qp *qp, struct ib_flow_attr *flow_
        struct mlx4_dev *dev = to_mdev(qp->device)->dev;
        int err = 0;
 
-       if (dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+       if (dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN ||
+           dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC)
                return 0; /* do nothing */
 
        ib_flow = flow_attr + 1;
index 8afa28e4570ed099bb3fb9fc4b2d7e1c1a5ba9d6..18d4b2c8fe55092aa8e31c411faf051d968fb49d 100644 (file)
 #include <linux/cdev.h>
 #include "input-compat.h"
 
+enum evdev_clock_type {
+       EV_CLK_REAL = 0,
+       EV_CLK_MONO,
+       EV_CLK_BOOT,
+       EV_CLK_MAX
+};
+
 struct evdev {
        int open;
        struct input_handle handle;
@@ -49,12 +56,32 @@ struct evdev_client {
        struct fasync_struct *fasync;
        struct evdev *evdev;
        struct list_head node;
-       int clkid;
+       int clk_type;
        bool revoked;
        unsigned int bufsize;
        struct input_event buffer[];
 };
 
+static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
+{
+       switch (clkid) {
+
+       case CLOCK_REALTIME:
+               client->clk_type = EV_CLK_REAL;
+               break;
+       case CLOCK_MONOTONIC:
+               client->clk_type = EV_CLK_MONO;
+               break;
+       case CLOCK_BOOTTIME:
+               client->clk_type = EV_CLK_BOOT;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /* flush queued events of type @type, caller must hold client->buffer_lock */
 static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
 {
@@ -108,8 +135,11 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
        struct input_event ev;
        ktime_t time;
 
-       time = (client->clkid == CLOCK_MONOTONIC) ?
-               ktime_get() : ktime_get_real();
+       time = client->clk_type == EV_CLK_REAL ?
+                       ktime_get_real() :
+                       client->clk_type == EV_CLK_MONO ?
+                               ktime_get() :
+                               ktime_get_boottime();
 
        ev.time = ktime_to_timeval(time);
        ev.type = EV_SYN;
@@ -159,7 +189,7 @@ static void __pass_event(struct evdev_client *client,
 
 static void evdev_pass_values(struct evdev_client *client,
                        const struct input_value *vals, unsigned int count,
-                       ktime_t mono, ktime_t real)
+                       ktime_t *ev_time)
 {
        struct evdev *evdev = client->evdev;
        const struct input_value *v;
@@ -169,8 +199,7 @@ static void evdev_pass_values(struct evdev_client *client,
        if (client->revoked)
                return;
 
-       event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
-                                     mono : real);
+       event.time = ktime_to_timeval(ev_time[client->clk_type]);
 
        /* Interrupts are disabled, just acquire the lock. */
        spin_lock(&client->buffer_lock);
@@ -198,21 +227,22 @@ static void evdev_events(struct input_handle *handle,
 {
        struct evdev *evdev = handle->private;
        struct evdev_client *client;
-       ktime_t time_mono, time_real;
+       ktime_t ev_time[EV_CLK_MAX];
 
-       time_mono = ktime_get();
-       time_real = ktime_mono_to_real(time_mono);
+       ev_time[EV_CLK_MONO] = ktime_get();
+       ev_time[EV_CLK_REAL] = ktime_mono_to_real(ev_time[EV_CLK_MONO]);
+       ev_time[EV_CLK_BOOT] = ktime_mono_to_any(ev_time[EV_CLK_MONO],
+                                                TK_OFFS_BOOT);
 
        rcu_read_lock();
 
        client = rcu_dereference(evdev->grab);
 
        if (client)
-               evdev_pass_values(client, vals, count, time_mono, time_real);
+               evdev_pass_values(client, vals, count, ev_time);
        else
                list_for_each_entry_rcu(client, &evdev->client_list, node)
-                       evdev_pass_values(client, vals, count,
-                                         time_mono, time_real);
+                       evdev_pass_values(client, vals, count, ev_time);
 
        rcu_read_unlock();
 }
@@ -877,10 +907,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
        case EVIOCSCLOCKID:
                if (copy_from_user(&i, p, sizeof(unsigned int)))
                        return -EFAULT;
-               if (i != CLOCK_MONOTONIC && i != CLOCK_REALTIME)
-                       return -EINVAL;
-               client->clkid = i;
-               return 0;
+
+               return evdev_set_clk_type(client, i);
 
        case EVIOCGKEYCODE:
                return evdev_handle_get_keycode(dev, p);
index 04217c2e345c0ddcaa8e5b1d2525dbb14b5854fe..213e3a1903ee1ddecf84a797ba19da6fa8d7b50c 100644 (file)
@@ -1974,18 +1974,22 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
 
        events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */
 
-       for (i = 0; i < ABS_CNT; i++) {
-               if (test_bit(i, dev->absbit)) {
-                       if (input_is_mt_axis(i))
-                               events += mt_slots;
-                       else
-                               events++;
+       if (test_bit(EV_ABS, dev->evbit)) {
+               for (i = 0; i < ABS_CNT; i++) {
+                       if (test_bit(i, dev->absbit)) {
+                               if (input_is_mt_axis(i))
+                                       events += mt_slots;
+                               else
+                                       events++;
+                       }
                }
        }
 
-       for (i = 0; i < REL_CNT; i++)
-               if (test_bit(i, dev->relbit))
-                       events++;
+       if (test_bit(EV_REL, dev->evbit)) {
+               for (i = 0; i < REL_CNT; i++)
+                       if (test_bit(i, dev->relbit))
+                               events++;
+       }
 
        /* Make room for KEY and MSC events */
        events += 7;
index 96ee26c555e02dd2b69530382170ae3e365facc4..a5d9b3f3c8714ee5a307e166afa4bf90e23864bf 100644 (file)
@@ -559,6 +559,7 @@ config KEYBOARD_SH_KEYSC
 config KEYBOARD_STMPE
        tristate "STMPE keypad support"
        depends on MFD_STMPE
+       depends on OF
        select INPUT_MATRIXKMAP
        help
          Say Y here if you want to use the keypad controller on STMPE I/O
index d4dd78a7d56b5b1bf3dbe8865025bd5559a82ce2..883d6aed5b9ac12f47bc3a137bbf8e61c0bd1ec2 100644 (file)
 struct gpio_button_data {
        const struct gpio_keys_button *button;
        struct input_dev *input;
-       struct timer_list timer;
-       struct work_struct work;
-       unsigned int timer_debounce;    /* in msecs */
+
+       struct timer_list release_timer;
+       unsigned int release_delay;     /* in msecs, for IRQ-only buttons */
+
+       struct delayed_work work;
+       unsigned int software_debounce; /* in msecs, for GPIO-driven buttons */
+
        unsigned int irq;
        spinlock_t lock;
        bool disabled;
@@ -116,11 +120,14 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
 {
        if (!bdata->disabled) {
                /*
-                * Disable IRQ and possible debouncing timer.
+                * Disable IRQ and associated timer/work structure.
                 */
                disable_irq(bdata->irq);
-               if (bdata->timer_debounce)
-                       del_timer_sync(&bdata->timer);
+
+               if (gpio_is_valid(bdata->button->gpio))
+                       cancel_delayed_work_sync(&bdata->work);
+               else
+                       del_timer_sync(&bdata->release_timer);
 
                bdata->disabled = true;
        }
@@ -343,7 +350,7 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
 static void gpio_keys_gpio_work_func(struct work_struct *work)
 {
        struct gpio_button_data *bdata =
-               container_of(work, struct gpio_button_data, work);
+               container_of(work, struct gpio_button_data, work.work);
 
        gpio_keys_gpio_report_event(bdata);
 
@@ -351,13 +358,6 @@ static void gpio_keys_gpio_work_func(struct work_struct *work)
                pm_relax(bdata->input->dev.parent);
 }
 
-static void gpio_keys_gpio_timer(unsigned long _data)
-{
-       struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
-
-       schedule_work(&bdata->work);
-}
-
 static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 {
        struct gpio_button_data *bdata = dev_id;
@@ -366,11 +366,10 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 
        if (bdata->button->wakeup)
                pm_stay_awake(bdata->input->dev.parent);
-       if (bdata->timer_debounce)
-               mod_timer(&bdata->timer,
-                       jiffies + msecs_to_jiffies(bdata->timer_debounce));
-       else
-               schedule_work(&bdata->work);
+
+       mod_delayed_work(system_wq,
+                        &bdata->work,
+                        msecs_to_jiffies(bdata->software_debounce));
 
        return IRQ_HANDLED;
 }
@@ -408,7 +407,7 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
                input_event(input, EV_KEY, button->code, 1);
                input_sync(input);
 
-               if (!bdata->timer_debounce) {
+               if (!bdata->release_delay) {
                        input_event(input, EV_KEY, button->code, 0);
                        input_sync(input);
                        goto out;
@@ -417,9 +416,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
                bdata->key_pressed = true;
        }
 
-       if (bdata->timer_debounce)
-               mod_timer(&bdata->timer,
-                       jiffies + msecs_to_jiffies(bdata->timer_debounce));
+       if (bdata->release_delay)
+               mod_timer(&bdata->release_timer,
+                       jiffies + msecs_to_jiffies(bdata->release_delay));
 out:
        spin_unlock_irqrestore(&bdata->lock, flags);
        return IRQ_HANDLED;
@@ -429,10 +428,10 @@ static void gpio_keys_quiesce_key(void *data)
 {
        struct gpio_button_data *bdata = data;
 
-       if (bdata->timer_debounce)
-               del_timer_sync(&bdata->timer);
-
-       cancel_work_sync(&bdata->work);
+       if (gpio_is_valid(bdata->button->gpio))
+               cancel_delayed_work_sync(&bdata->work);
+       else
+               del_timer_sync(&bdata->release_timer);
 }
 
 static int gpio_keys_setup_key(struct platform_device *pdev,
@@ -466,23 +465,25 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                                        button->debounce_interval * 1000);
                        /* use timer if gpiolib doesn't provide debounce */
                        if (error < 0)
-                               bdata->timer_debounce =
+                               bdata->software_debounce =
                                                button->debounce_interval;
                }
 
-               irq = gpio_to_irq(button->gpio);
-               if (irq < 0) {
-                       error = irq;
-                       dev_err(dev,
-                               "Unable to get irq number for GPIO %d, error %d\n",
-                               button->gpio, error);
-                       return error;
+               if (button->irq) {
+                       bdata->irq = button->irq;
+               } else {
+                       irq = gpio_to_irq(button->gpio);
+                       if (irq < 0) {
+                               error = irq;
+                               dev_err(dev,
+                                       "Unable to get irq number for GPIO %d, error %d\n",
+                                       button->gpio, error);
+                               return error;
+                       }
+                       bdata->irq = irq;
                }
-               bdata->irq = irq;
 
-               INIT_WORK(&bdata->work, gpio_keys_gpio_work_func);
-               setup_timer(&bdata->timer,
-                           gpio_keys_gpio_timer, (unsigned long)bdata);
+               INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
 
                isr = gpio_keys_gpio_isr;
                irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -499,8 +500,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
                        return -EINVAL;
                }
 
-               bdata->timer_debounce = button->debounce_interval;
-               setup_timer(&bdata->timer,
+               bdata->release_delay = button->debounce_interval;
+               setup_timer(&bdata->release_timer,
                            gpio_keys_irq_timer, (unsigned long)bdata);
 
                isr = gpio_keys_irq_isr;
@@ -510,7 +511,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
        input_set_capability(input, button->type ?: EV_KEY, button->code);
 
        /*
-        * Install custom action to cancel debounce timer and
+        * Install custom action to cancel release timer and
         * workqueue item.
         */
        error = devm_add_action(&pdev->dev, gpio_keys_quiesce_key, bdata);
@@ -618,33 +619,30 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
        i = 0;
        for_each_child_of_node(node, pp) {
-               int gpio = -1;
                enum of_gpio_flags flags;
 
                button = &pdata->buttons[i++];
 
-               if (!of_find_property(pp, "gpios", NULL)) {
-                       button->irq = irq_of_parse_and_map(pp, 0);
-                       if (button->irq == 0) {
-                               i--;
-                               pdata->nbuttons--;
-                               dev_warn(dev, "Found button without gpios or irqs\n");
-                               continue;
-                       }
-               } else {
-                       gpio = of_get_gpio_flags(pp, 0, &flags);
-                       if (gpio < 0) {
-                               error = gpio;
+               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               if (button->gpio < 0) {
+                       error = button->gpio;
+                       if (error != -ENOENT) {
                                if (error != -EPROBE_DEFER)
                                        dev_err(dev,
                                                "Failed to get gpio flags, error: %d\n",
                                                error);
                                return ERR_PTR(error);
                        }
+               } else {
+                       button->active_low = flags & OF_GPIO_ACTIVE_LOW;
                }
 
-               button->gpio = gpio;
-               button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+               button->irq = irq_of_parse_and_map(pp, 0);
+
+               if (!gpio_is_valid(button->gpio) && !button->irq) {
+                       dev_err(dev, "Found button without gpios or irqs\n");
+                       return ERR_PTR(-EINVAL);
+               }
 
                if (of_property_read_u32(pp, "linux,code", &button->code)) {
                        dev_err(dev, "Button without keycode: 0x%x\n",
@@ -659,6 +657,8 @@ gpio_keys_get_devtree_pdata(struct device *dev)
 
                button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
 
+               button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
+
                if (of_property_read_u32(pp, "debounce-interval",
                                         &button->debounce_interval))
                        button->debounce_interval = 5;
index 610a8af795a1f5b090b73d7bb8919bf41d3e331a..5b152f25a8e1ff72e613608f08876b3098627469 100644 (file)
@@ -473,7 +473,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
        if (error)
                goto bail1;
 
-       init_completion(&dev->cmd_done);
+       reinit_completion(&dev->cmd_done);
        serio_write(serio, 0);
        serio_write(serio, 0);
        serio_write(serio, HIL_PKT_CMD >> 8);
@@ -482,7 +482,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
        if (error)
                goto bail1;
 
-       init_completion(&dev->cmd_done);
+       reinit_completion(&dev->cmd_done);
        serio_write(serio, 0);
        serio_write(serio, 0);
        serio_write(serio, HIL_PKT_CMD >> 8);
@@ -491,7 +491,7 @@ static int hil_dev_connect(struct serio *serio, struct serio_driver *drv)
        if (error)
                goto bail1;
 
-       init_completion(&dev->cmd_done);
+       reinit_completion(&dev->cmd_done);
        serio_write(serio, 0);
        serio_write(serio, 0);
        serio_write(serio, HIL_PKT_CMD >> 8);
index ef5e67fb567e701365767a9949dd3ea722e4f260..fe6e3f22eed76157c42a1d9b873b01e34f38b5f2 100644 (file)
 #define STMPE_KEYPAD_MAX_ROWS          8
 #define STMPE_KEYPAD_MAX_COLS          8
 #define STMPE_KEYPAD_ROW_SHIFT         3
-#define STMPE_KEYPAD_KEYMAP_SIZE       \
+#define STMPE_KEYPAD_KEYMAP_MAX_SIZE \
        (STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS)
 
 /**
  * struct stmpe_keypad_variant - model-specific attributes
  * @auto_increment: whether the KPC_DATA_BYTE register address
  *                 auto-increments on multiple read
+ * @set_pullup: whether the pins need to have their pull-ups set
  * @num_data: number of data bytes
  * @num_normal_data: number of normal keys' data bytes
  * @max_cols: maximum number of columns supported
@@ -61,6 +62,7 @@
  */
 struct stmpe_keypad_variant {
        bool            auto_increment;
+       bool            set_pullup;
        int             num_data;
        int             num_normal_data;
        int             max_cols;
@@ -81,6 +83,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
        },
        [STMPE2401] = {
                .auto_increment         = false,
+               .set_pullup             = true,
                .num_data               = 3,
                .num_normal_data        = 2,
                .max_cols               = 8,
@@ -90,6 +93,7 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
        },
        [STMPE2403] = {
                .auto_increment         = true,
+               .set_pullup             = true,
                .num_data               = 5,
                .num_normal_data        = 3,
                .max_cols               = 8,
@@ -99,16 +103,30 @@ static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
        },
 };
 
+/**
+ * struct stmpe_keypad - STMPE keypad state container
+ * @stmpe: pointer to parent STMPE device
+ * @input: spawned input device
+ * @variant: STMPE variant
+ * @debounce_ms: debounce interval, in ms.  Maximum is
+ *              %STMPE_KEYPAD_MAX_DEBOUNCE.
+ * @scan_count: number of key scanning cycles to confirm key data.
+ *             Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT.
+ * @no_autorepeat: disable key autorepeat
+ * @rows: bitmask for the rows
+ * @cols: bitmask for the columns
+ * @keymap: the keymap
+ */
 struct stmpe_keypad {
        struct stmpe *stmpe;
        struct input_dev *input;
        const struct stmpe_keypad_variant *variant;
-       const struct stmpe_keypad_platform_data *plat;
-
+       unsigned int debounce_ms;
+       unsigned int scan_count;
+       bool no_autorepeat;
        unsigned int rows;
        unsigned int cols;
-
-       unsigned short keymap[STMPE_KEYPAD_KEYMAP_SIZE];
+       unsigned short keymap[STMPE_KEYPAD_KEYMAP_MAX_SIZE];
 };
 
 static int stmpe_keypad_read_data(struct stmpe_keypad *keypad, u8 *data)
@@ -171,7 +189,10 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
        unsigned int col_gpios = variant->col_gpios;
        unsigned int row_gpios = variant->row_gpios;
        struct stmpe *stmpe = keypad->stmpe;
+       u8 pureg = stmpe->regs[STMPE_IDX_GPPUR_LSB];
        unsigned int pins = 0;
+       unsigned int pu_pins = 0;
+       int ret;
        int i;
 
        /*
@@ -188,8 +209,10 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
        for (i = 0; i < variant->max_cols; i++) {
                int num = __ffs(col_gpios);
 
-               if (keypad->cols & (1 << i))
+               if (keypad->cols & (1 << i)) {
                        pins |= 1 << num;
+                       pu_pins |= 1 << num;
+               }
 
                col_gpios &= ~(1 << num);
        }
@@ -203,20 +226,43 @@ static int stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
                row_gpios &= ~(1 << num);
        }
 
-       return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD);
+       ret = stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD);
+       if (ret)
+               return ret;
+
+       /*
+        * On STMPE24xx, set pin bias to pull-up on all keypad input
+        * pins (columns), this incidentally happen to be maximum 8 pins
+        * and placed at GPIO0-7 so only the LSB of the pull up register
+        * ever needs to be written.
+        */
+       if (variant->set_pullup) {
+               u8 val;
+
+               ret = stmpe_reg_read(stmpe, pureg);
+               if (ret)
+                       return ret;
+
+               /* Do not touch unused pins, may be used for GPIO */
+               val = ret & ~pu_pins;
+               val |= pu_pins;
+
+               ret = stmpe_reg_write(stmpe, pureg, val);
+       }
+
+       return 0;
 }
 
 static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
 {
-       const struct stmpe_keypad_platform_data *plat = keypad->plat;
        const struct stmpe_keypad_variant *variant = keypad->variant;
        struct stmpe *stmpe = keypad->stmpe;
        int ret;
 
-       if (plat->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE)
+       if (keypad->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE)
                return -EINVAL;
 
-       if (plat->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT)
+       if (keypad->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT)
                return -EINVAL;
 
        ret = stmpe_enable(stmpe, STMPE_BLOCK_KEYPAD);
@@ -245,7 +291,7 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
 
        ret = stmpe_set_bits(stmpe, STMPE_KPC_CTRL_MSB,
                             STMPE_KPC_CTRL_MSB_SCAN_COUNT,
-                            plat->scan_count << 4);
+                            keypad->scan_count << 4);
        if (ret < 0)
                return ret;
 
@@ -253,17 +299,18 @@ static int stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
                              STMPE_KPC_CTRL_LSB_SCAN |
                              STMPE_KPC_CTRL_LSB_DEBOUNCE,
                              STMPE_KPC_CTRL_LSB_SCAN |
-                             (plat->debounce_ms << 1));
+                             (keypad->debounce_ms << 1));
 }
 
-static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad)
+static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad,
+                                       u32 used_rows, u32 used_cols)
 {
        int row, col;
 
-       for (row = 0; row < STMPE_KEYPAD_MAX_ROWS; row++) {
-               for (col = 0; col < STMPE_KEYPAD_MAX_COLS; col++) {
+       for (row = 0; row < used_rows; row++) {
+               for (col = 0; col < used_cols; col++) {
                        int code = MATRIX_SCAN_CODE(row, col,
-                                               STMPE_KEYPAD_ROW_SHIFT);
+                                                   STMPE_KEYPAD_ROW_SHIFT);
                        if (keypad->keymap[code] != KEY_RESERVED) {
                                keypad->rows |= 1 << row;
                                keypad->cols |= 1 << col;
@@ -272,51 +319,17 @@ static void stmpe_keypad_fill_used_pins(struct stmpe_keypad *keypad)
        }
 }
 
-#ifdef CONFIG_OF
-static const struct stmpe_keypad_platform_data *
-stmpe_keypad_of_probe(struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct stmpe_keypad_platform_data *plat;
-
-       if (!np)
-               return ERR_PTR(-ENODEV);
-
-       plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL);
-       if (!plat)
-               return ERR_PTR(-ENOMEM);
-
-       of_property_read_u32(np, "debounce-interval", &plat->debounce_ms);
-       of_property_read_u32(np, "st,scan-count", &plat->scan_count);
-
-       plat->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat");
-
-       return plat;
-}
-#else
-static inline const struct stmpe_keypad_platform_data *
-stmpe_keypad_of_probe(struct device *dev)
-{
-       return ERR_PTR(-EINVAL);
-}
-#endif
-
 static int stmpe_keypad_probe(struct platform_device *pdev)
 {
        struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
-       const struct stmpe_keypad_platform_data *plat;
+       struct device_node *np = pdev->dev.of_node;
        struct stmpe_keypad *keypad;
        struct input_dev *input;
+       u32 rows;
+       u32 cols;
        int error;
        int irq;
 
-       plat = stmpe->pdata->keypad;
-       if (!plat) {
-               plat = stmpe_keypad_of_probe(&pdev->dev);
-               if (IS_ERR(plat))
-                       return PTR_ERR(plat);
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
@@ -326,6 +339,13 @@ static int stmpe_keypad_probe(struct platform_device *pdev)
        if (!keypad)
                return -ENOMEM;
 
+       keypad->stmpe = stmpe;
+       keypad->variant = &stmpe_keypad_variants[stmpe->partnum];
+
+       of_property_read_u32(np, "debounce-interval", &keypad->debounce_ms);
+       of_property_read_u32(np, "st,scan-count", &keypad->scan_count);
+       keypad->no_autorepeat = of_property_read_bool(np, "st,no-autorepeat");
+
        input = devm_input_allocate_device(&pdev->dev);
        if (!input)
                return -ENOMEM;
@@ -334,23 +354,22 @@ static int stmpe_keypad_probe(struct platform_device *pdev)
        input->id.bustype = BUS_I2C;
        input->dev.parent = &pdev->dev;
 
-       error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
-                                          STMPE_KEYPAD_MAX_ROWS,
-                                          STMPE_KEYPAD_MAX_COLS,
+       error = matrix_keypad_parse_of_params(&pdev->dev, &rows, &cols);
+       if (error)
+               return error;
+
+       error = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
                                           keypad->keymap, input);
        if (error)
                return error;
 
        input_set_capability(input, EV_MSC, MSC_SCAN);
-       if (!plat->no_autorepeat)
+       if (!keypad->no_autorepeat)
                __set_bit(EV_REP, input->evbit);
 
-       stmpe_keypad_fill_used_pins(keypad);
+       stmpe_keypad_fill_used_pins(keypad, rows, cols);
 
-       keypad->stmpe = stmpe;
-       keypad->plat = plat;
        keypad->input = input;
-       keypad->variant = &stmpe_keypad_variants[stmpe->partnum];
 
        error = stmpe_keypad_chip_init(keypad);
        if (error < 0)
index d125a019383f10155dcafb88903f47e0f5297080..d88d73d835526a16d2e5e4e48c6a2562c802a4cf 100644 (file)
@@ -881,6 +881,34 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
                                          unsigned char *pkt,
                                          unsigned char pkt_id)
 {
+       /*
+        *       packet-fmt    b7   b6    b5   b4   b3   b2   b1   b0
+        * Byte0 TWO & MULTI    L    1     R    M    1 Y0-2 Y0-1 Y0-0
+        * Byte0 NEW            L    1  X1-5    1    1 Y0-2 Y0-1 Y0-0
+        * Byte1            Y0-10 Y0-9  Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3
+        * Byte2            X0-11    1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5
+        * Byte3            X1-11    1  X0-4 X0-3    1 X0-2 X0-1 X0-0
+        * Byte4 TWO        X1-10  TWO  X1-9 X1-8 X1-7 X1-6 X1-5 X1-4
+        * Byte4 MULTI      X1-10  TWO  X1-9 X1-8 X1-7 X1-6 Y1-5    1
+        * Byte4 NEW        X1-10  TWO  X1-9 X1-8 X1-7 X1-6    0    0
+        * Byte5 TWO & NEW  Y1-10    0  Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4
+        * Byte5 MULTI      Y1-10    0  Y1-9 Y1-8 Y1-7 Y1-6  F-1  F-0
+        * L:         Left button
+        * R / M:     Non-clickpads: Right / Middle button
+        *            Clickpads: When > 2 fingers are down, and some fingers
+        *            are in the button area, then the 2 coordinates reported
+        *            are for fingers outside the button area and these report
+        *            extra fingers being present in the right / left button
+        *            area. Note these fingers are not added to the F field!
+        *            so if a TWO packet is received and R = 1 then there are
+        *            3 fingers down, etc.
+        * TWO:       1: Two touches present, byte 0/4/5 are in TWO fmt
+        *            0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt
+        *               otherwise byte 0 bit 4 must be set and byte 0/4/5 are
+        *               in NEW fmt
+        * F:         Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
+        */
+
        mt[0].x = ((pkt[2] & 0x80) << 4);
        mt[0].x |= ((pkt[2] & 0x3F) << 5);
        mt[0].x |= ((pkt[3] & 0x30) >> 1);
@@ -919,18 +947,21 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
 
 static int alps_get_mt_count(struct input_mt_pos *mt)
 {
-       int i;
+       int i, fingers = 0;
 
-       for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
-               /* empty */;
+       for (i = 0; i < MAX_TOUCHES; i++) {
+               if (mt[i].x != 0 || mt[i].y != 0)
+                       fingers++;
+       }
 
-       return i;
+       return fingers;
 }
 
 static int alps_decode_packet_v7(struct alps_fields *f,
                                  unsigned char *p,
                                  struct psmouse *psmouse)
 {
+       struct alps_data *priv = psmouse->private;
        unsigned char pkt_id;
 
        pkt_id = alps_get_packet_id_v7(p);
@@ -938,19 +969,52 @@ static int alps_decode_packet_v7(struct alps_fields *f,
                return 0;
        if (pkt_id == V7_PACKET_ID_UNKNOWN)
                return -1;
+       /*
+        * NEW packets are send to indicate a discontinuity in the finger
+        * coordinate reporting. Specifically a finger may have moved from
+        * slot 0 to 1 or vice versa. INPUT_MT_TRACK takes care of this for
+        * us.
+        *
+        * NEW packets have 3 problems:
+        * 1) They do not contain middle / right button info (on non clickpads)
+        *    this can be worked around by preserving the old button state
+        * 2) They do not contain an accurate fingercount, and they are
+        *    typically send when the number of fingers changes. We cannot use
+        *    the old finger count as that may mismatch with the amount of
+        *    touch coordinates we've available in the NEW packet
+        * 3) Their x data for the second touch is inaccurate leading to
+        *    a possible jump of the x coordinate by 16 units when the first
+        *    non NEW packet comes in
+        * Since problems 2 & 3 cannot be worked around, just ignore them.
+        */
+       if (pkt_id == V7_PACKET_ID_NEW)
+               return 1;
 
        alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
 
-       if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
-               f->left = (p[0] & 0x80) >> 7;
+       if (pkt_id == V7_PACKET_ID_TWO)
+               f->fingers = alps_get_mt_count(f->mt);
+       else /* pkt_id == V7_PACKET_ID_MULTI */
+               f->fingers = 3 + (p[5] & 0x03);
+
+       f->left = (p[0] & 0x80) >> 7;
+       if (priv->flags & ALPS_BUTTONPAD) {
+               if (p[0] & 0x20)
+                       f->fingers++;
+               if (p[0] & 0x10)
+                       f->fingers++;
+       } else {
                f->right = (p[0] & 0x20) >> 5;
                f->middle = (p[0] & 0x10) >> 4;
        }
 
-       if (pkt_id == V7_PACKET_ID_TWO)
-               f->fingers = alps_get_mt_count(f->mt);
-       else if (pkt_id == V7_PACKET_ID_MULTI)
-               f->fingers = 3 + (p[5] & 0x03);
+       /* Sometimes a single touch is reported in mt[1] rather then mt[0] */
+       if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) {
+               f->mt[0].x = f->mt[1].x;
+               f->mt[0].y = f->mt[1].y;
+               f->mt[1].x = 0;
+               f->mt[1].y = 0;
+       }
 
        return 0;
 }
index f2b97802640755aacfcde04005b125717cb63818..6e22682c8255cfff41e1fc49f6a76198911aafc5 100644 (file)
@@ -1097,6 +1097,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
  * Asus UX31               0x361f00        20, 15, 0e      clickpad
  * Asus UX32VD             0x361f02        00, 15, 0e      clickpad
  * Avatar AVIU-145A2       0x361f00        ?               clickpad
+ * Fujitsu LIFEBOOK E544   0x470f00        d0, 12, 09      2 hw buttons
+ * Fujitsu LIFEBOOK E554   0x570f01        40, 14, 0c      2 hw buttons
  * Fujitsu H730            0x570f00        c0, 14, 0c      3 hw buttons (**)
  * Gigabyte U2442          0x450f01        58, 17, 0c      2 hw buttons
  * Lenovo L430             0x350f02        b9, 15, 0c      2 hw buttons (*)
@@ -1475,6 +1477,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"),
                },
        },
+       {
+               /* Fujitsu LIFEBOOK E554  does not work with crc_enabled == 0 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
+               },
+       },
+       {
+               /* Fujitsu LIFEBOOK E544  does not work with crc_enabled == 0 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"),
+               },
+       },
 #endif
        { }
 };
@@ -1520,6 +1536,8 @@ static int elantech_set_properties(struct elantech_data *etd)
                case 7:
                case 8:
                case 9:
+               case 10:
+               case 13:
                        etd->hw_version = 4;
                        break;
                default:
index f9472920d986368f7aa83eb7d0621489d774b050..23e26e0768b54af037990dbe4999d0486470f56c 100644 (file)
@@ -135,8 +135,9 @@ static const struct min_max_quirk min_max_pnpid_table[] = {
                1232, 5710, 1156, 4696
        },
        {
-               (const char * const []){"LEN0034", "LEN0036", "LEN0039",
-                                       "LEN2002", "LEN2004", NULL},
+               (const char * const []){"LEN0034", "LEN0036", "LEN0037",
+                                       "LEN0039", "LEN2002", "LEN2004",
+                                       NULL},
                1024, 5112, 2024, 4832
        },
        {
@@ -165,7 +166,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
        "LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */
        "LEN0035", /* X240 */
        "LEN0036", /* T440 */
-       "LEN0037",
+       "LEN0037", /* X1 Carbon 2nd */
        "LEN0038",
        "LEN0039", /* T440s */
        "LEN0041",
index 30c8b6998808fa452a19e437c33bd7e9db8a0888..354d47ecd66a01c8b0ab732eb038bbad19857d19 100644 (file)
@@ -227,6 +227,7 @@ TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH);
 TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH);
 TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME);
 TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV);
+TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME);
 
 TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0,
                    TP_DEF_PTSON);
@@ -246,6 +247,7 @@ static struct attribute *trackpoint_attrs[] = {
        &psmouse_attr_upthresh.dattr.attr,
        &psmouse_attr_ztime.dattr.attr,
        &psmouse_attr_jenks.dattr.attr,
+       &psmouse_attr_drift_time.dattr.attr,
        &psmouse_attr_press_to_select.dattr.attr,
        &psmouse_attr_skipback.dattr.attr,
        &psmouse_attr_ext_dev.dattr.attr,
@@ -312,6 +314,7 @@ static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state)
        TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh);
        TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime);
        TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks);
+       TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, drift_time);
 
        /* toggles */
        TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select);
@@ -332,6 +335,7 @@ static void trackpoint_defaults(struct trackpoint_data *tp)
        TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh);
        TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime);
        TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks);
+       TRACKPOINT_SET_POWER_ON_DEFAULT(tp, drift_time);
        TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia);
 
        /* toggles */
index ecd0547964a570048a2ad9ecf228d9eda98290a3..5617ed3a7d7a15d0f9769086afb8c740b5739fcc 100644 (file)
@@ -70,6 +70,9 @@
 #define TP_UP_THRESH           0x5A    /* Used to generate a 'click' on Z-axis */
 #define TP_Z_TIME              0x5E    /* How sharp of a press */
 #define TP_JENKS_CURV          0x5D    /* Minimum curvature for double click */
+#define TP_DRIFT_TIME          0x5F    /* How long a 'hands off' condition */
+                                       /* must last (x*107ms) for drift */
+                                       /* correction to occur */
 
 /*
  * Toggling Flag bits
 #define TP_DEF_UP_THRESH       0xFF
 #define TP_DEF_Z_TIME          0x26
 #define TP_DEF_JENKS_CURV      0x87
+#define TP_DEF_DRIFT_TIME      0x05
 
 /* Toggles */
 #define TP_DEF_MB              0x00
@@ -137,6 +141,7 @@ struct trackpoint_data
        unsigned char draghys, mindrag;
        unsigned char thresh, upthresh;
        unsigned char ztime, jenks;
+       unsigned char drift_time;
 
        /* toggles */
        unsigned char press_to_select;
index c66d1b53843e326a246aadd9050cd089c69e112a..c11556563ef0633f746edc9bc9e3ebca80879e8b 100644 (file)
@@ -151,6 +151,14 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
                        DMI_MATCH(DMI_PRODUCT_VERSION, "5a"),
                },
        },
+       {
+               /* Medion Akoya E7225 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
+               },
+       },
        {
                /* Blue FB5601 */
                .matches = {
@@ -414,6 +422,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"),
                },
        },
+       {
+               /* Acer Aspire 7738 */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7738"),
+               },
+       },
        {
                /* Gericom Bellagio */
                .matches = {
@@ -745,6 +760,35 @@ static const struct dmi_system_id __initconst i8042_dmi_dritek_table[] = {
        { }
 };
 
+/*
+ * Some laptops need keyboard reset before probing for the trackpad to get
+ * it detected, initialised & finally work.
+ */
+static const struct dmi_system_id __initconst i8042_dmi_kbdreset_table[] = {
+       {
+               /* Gigabyte P35 v2 - Elantech touchpad */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "P35V2"),
+               },
+       },
+               {
+               /* Aorus branded Gigabyte X3 Plus - Elantech touchpad */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "X3"),
+               },
+       },
+       {
+               /* Gigabyte P34 - Elantech touchpad */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "P34"),
+               },
+       },
+       { }
+};
+
 #endif /* CONFIG_X86 */
 
 #ifdef CONFIG_PNP
@@ -1040,6 +1084,9 @@ static int __init i8042_platform_init(void)
        if (dmi_check_system(i8042_dmi_dritek_table))
                i8042_dritek = true;
 
+       if (dmi_check_system(i8042_dmi_kbdreset_table))
+               i8042_kbdreset = true;
+
        /*
         * A20 was already enabled during early kernel init. But some buggy
         * BIOSes (in MSI Laptops) require A20 to be enabled using 8042 to
index 924e4bf357fb2607bb14fdf32173cc049830c3ab..986a71c614b0461bce7825ba34fc78aefcd4a7e4 100644 (file)
@@ -67,6 +67,10 @@ static bool i8042_notimeout;
 module_param_named(notimeout, i8042_notimeout, bool, 0);
 MODULE_PARM_DESC(notimeout, "Ignore timeouts signalled by i8042");
 
+static bool i8042_kbdreset;
+module_param_named(kbdreset, i8042_kbdreset, bool, 0);
+MODULE_PARM_DESC(kbdreset, "Reset device connected to KBD port");
+
 #ifdef CONFIG_X86
 static bool i8042_dritek;
 module_param_named(dritek, i8042_dritek, bool, 0);
@@ -789,6 +793,16 @@ static int __init i8042_check_aux(void)
        if (i8042_toggle_aux(true))
                return -1;
 
+/*
+ * Reset keyboard (needed on some laptops to successfully detect
+ * touchpad, e.g., some Gigabyte laptop models with Elantech
+ * touchpads).
+ */
+       if (i8042_kbdreset) {
+               pr_warn("Attempting to reset device connected to KBD port\n");
+               i8042_kbd_write(NULL, (unsigned char) 0xff);
+       }
+
 /*
  * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
  * used it for a PCI card or somethig else.
index bb070206223c1e9eeee4f4964a8f9f6ed848806b..95ee92a91bd21353bf58020c9d87fda42fad6633 100644 (file)
 #define MXT_T6_STATUS_COMSERR  (1 << 2)
 
 /* MXT_GEN_POWER_T7 field */
-struct t7_config {
-       u8 idle;
-       u8 active;
-} __packed;
-
-#define MXT_POWER_CFG_RUN              0
-#define MXT_POWER_CFG_DEEPSLEEP                1
+#define MXT_POWER_IDLEACQINT   0
+#define MXT_POWER_ACTVACQINT   1
+#define MXT_POWER_ACTV2IDLETO  2
 
 /* MXT_GEN_ACQUIRE_T8 field */
 #define MXT_ACQUIRE_CHRGTIME   0
@@ -117,6 +113,7 @@ struct t7_config {
 #define MXT_ACQUIRE_ATCHCALSTHR        7
 
 /* MXT_TOUCH_MULTI_T9 field */
+#define MXT_TOUCH_CTRL         0
 #define MXT_T9_ORIENT          9
 #define MXT_T9_RANGE           18
 
@@ -256,7 +253,6 @@ struct mxt_data {
        bool update_input;
        u8 last_message_count;
        u8 num_touchids;
-       struct t7_config t7_cfg;
 
        /* Cached parameters from object table */
        u16 T5_address;
@@ -672,6 +668,20 @@ static void mxt_proc_t6_messages(struct mxt_data *data, u8 *msg)
        data->t6_status = status;
 }
 
+static int mxt_write_object(struct mxt_data *data,
+                                u8 type, u8 offset, u8 val)
+{
+       struct mxt_object *object;
+       u16 reg;
+
+       object = mxt_get_object(data, type);
+       if (!object || offset >= mxt_obj_size(object))
+               return -EINVAL;
+
+       reg = object->start_address;
+       return mxt_write_reg(data->client, reg + offset, val);
+}
+
 static void mxt_input_button(struct mxt_data *data, u8 *message)
 {
        struct input_dev *input = data->input_dev;
@@ -1742,60 +1752,6 @@ err_free_object_table:
        return error;
 }
 
-static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep)
-{
-       struct device *dev = &data->client->dev;
-       int error;
-       struct t7_config *new_config;
-       struct t7_config deepsleep = { .active = 0, .idle = 0 };
-
-       if (sleep == MXT_POWER_CFG_DEEPSLEEP)
-               new_config = &deepsleep;
-       else
-               new_config = &data->t7_cfg;
-
-       error = __mxt_write_reg(data->client, data->T7_address,
-                               sizeof(data->t7_cfg), new_config);
-       if (error)
-               return error;
-
-       dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n",
-               new_config->active, new_config->idle);
-
-       return 0;
-}
-
-static int mxt_init_t7_power_cfg(struct mxt_data *data)
-{
-       struct device *dev = &data->client->dev;
-       int error;
-       bool retry = false;
-
-recheck:
-       error = __mxt_read_reg(data->client, data->T7_address,
-                               sizeof(data->t7_cfg), &data->t7_cfg);
-       if (error)
-               return error;
-
-       if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) {
-               if (!retry) {
-                       dev_dbg(dev, "T7 cfg zero, resetting\n");
-                       mxt_soft_reset(data);
-                       retry = true;
-                       goto recheck;
-               } else {
-                       dev_dbg(dev, "T7 cfg zero after reset, overriding\n");
-                       data->t7_cfg.active = 20;
-                       data->t7_cfg.idle = 100;
-                       return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
-               }
-       }
-
-       dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n",
-               data->t7_cfg.active, data->t7_cfg.idle);
-       return 0;
-}
-
 static int mxt_configure_objects(struct mxt_data *data,
                                 const struct firmware *cfg)
 {
@@ -1809,12 +1765,6 @@ static int mxt_configure_objects(struct mxt_data *data,
                        dev_warn(dev, "Error %d updating config\n", error);
        }
 
-       error = mxt_init_t7_power_cfg(data);
-       if (error) {
-               dev_err(dev, "Failed to initialize power cfg\n");
-               return error;
-       }
-
        error = mxt_initialize_t9_input_device(data);
        if (error)
                return error;
@@ -2093,15 +2043,16 @@ static const struct attribute_group mxt_attr_group = {
 
 static void mxt_start(struct mxt_data *data)
 {
-       mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
-
-       /* Recalibrate since chip has been in deep sleep */
-       mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
+       /* Touch enable */
+       mxt_write_object(data,
+                       MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83);
 }
 
 static void mxt_stop(struct mxt_data *data)
 {
-       mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
+       /* Touch disable */
+       mxt_write_object(data,
+                       MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0);
 }
 
 static int mxt_input_open(struct input_dev *dev)
@@ -2266,6 +2217,8 @@ static int __maybe_unused mxt_resume(struct device *dev)
        struct mxt_data *data = i2c_get_clientdata(client);
        struct input_dev *input_dev = data->input_dev;
 
+       mxt_soft_reset(data);
+
        mutex_lock(&input_dev->mutex);
 
        if (input_dev->users)
index 3793fcc7e5db31117404e819272da27f4fd15d90..d4c24fb7704f5e2d87f299ac01e2aa2ba5866521 100644 (file)
@@ -850,9 +850,11 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
 }
 
 #define EDT_ATTR_CHECKSET(name, reg) \
+do {                                                           \
        if (pdata->name >= edt_ft5x06_attr_##name.limit_low &&          \
            pdata->name <= edt_ft5x06_attr_##name.limit_high)           \
-               edt_ft5x06_register_write(tsdata, reg, pdata->name)
+               edt_ft5x06_register_write(tsdata, reg, pdata->name);    \
+} while (0)
 
 #define EDT_GET_PROP(name, reg) {                              \
        u32 val;                                                \
index 1232336b960edb163278d59510a56e51840df9b9..40dfbc0444c0eaccdeca8cebfcd5f567e3d84ae4 100644 (file)
@@ -4029,14 +4029,6 @@ static int device_notifier(struct notifier_block *nb,
        if (action != BUS_NOTIFY_REMOVED_DEVICE)
                return 0;
 
-       /*
-        * If the device is still attached to a device driver we can't
-        * tear down the domain yet as DMA mappings may still be in use.
-        * Wait for the BUS_NOTIFY_UNBOUND_DRIVER event to do that.
-        */
-       if (action == BUS_NOTIFY_DEL_DEVICE && dev->driver != NULL)
-               return 0;
-
        domain = find_domain(dev);
        if (!domain)
                return 0;
@@ -4428,6 +4420,10 @@ static int intel_iommu_attach_device(struct iommu_domain *domain,
                                domain_remove_one_dev_info(old_domain, dev);
                        else
                                domain_remove_dev_info(old_domain);
+
+                       if (!domain_type_is_vm_or_si(old_domain) &&
+                            list_empty(&old_domain->devices))
+                               domain_exit(old_domain);
                }
        }
 
index 68dfb0fd5ee9af38f6586ea994ef4a6ba997b282..748693192c20a0dd862f799ace8d20450bc436fe 100644 (file)
@@ -558,7 +558,7 @@ static pmd_t *ipmmu_alloc_pmd(struct ipmmu_vmsa_device *mmu, pgd_t *pgd,
 
 static u64 ipmmu_page_prot(unsigned int prot, u64 type)
 {
-       u64 pgprot = ARM_VMSA_PTE_XN | ARM_VMSA_PTE_nG | ARM_VMSA_PTE_AF
+       u64 pgprot = ARM_VMSA_PTE_nG | ARM_VMSA_PTE_AF
                   | ARM_VMSA_PTE_SH_IS | ARM_VMSA_PTE_AP_UNPRIV
                   | ARM_VMSA_PTE_NS | type;
 
@@ -568,8 +568,8 @@ static u64 ipmmu_page_prot(unsigned int prot, u64 type)
        if (prot & IOMMU_CACHE)
                pgprot |= IMMAIR_ATTR_IDX_WBRWA << ARM_VMSA_PTE_ATTRINDX_SHIFT;
 
-       if (prot & IOMMU_EXEC)
-               pgprot &= ~ARM_VMSA_PTE_XN;
+       if (prot & IOMMU_NOEXEC)
+               pgprot |= ARM_VMSA_PTE_XN;
        else if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
                /* If no access create a faulting entry to avoid TLB fills. */
                pgprot &= ~ARM_VMSA_PTE_PAGE;
index b2023af384b9be0852c04195f75cea93582d47a8..6a8b1ec4a48a1f1100bc0f9f301fc658758a35ca 100644 (file)
@@ -1009,7 +1009,6 @@ static struct platform_driver rk_iommu_driver = {
        .remove = rk_iommu_remove,
        .driver = {
                   .name = "rk_iommu",
-                  .owner = THIS_MODULE,
                   .of_match_table = of_match_ptr(rk_iommu_dt_ids),
        },
 };
index f722a0c466cfee07de8f982a9c223478d1765c25..c48da057dbb1e5b6be38e6b28daced1046454687 100644 (file)
@@ -315,6 +315,7 @@ static const struct iommu_ops gart_iommu_ops = {
        .attach_dev     = gart_iommu_attach_dev,
        .detach_dev     = gart_iommu_detach_dev,
        .map            = gart_iommu_map,
+       .map_sg         = default_iommu_map_sg,
        .unmap          = gart_iommu_unmap,
        .iova_to_phys   = gart_iommu_iova_to_phys,
        .pgsize_bitmap  = GART_IOMMU_PGSIZES,
@@ -395,7 +396,7 @@ static int tegra_gart_probe(struct platform_device *pdev)
        do_gart_setup(gart, NULL);
 
        gart_handle = gart;
-       bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
+
        return 0;
 }
 
index d111ac779c4058e94c6051536cdb7fb5d2d34863..63cd031b2c28d40c9c1296ae466005a5d48843d3 100644 (file)
@@ -28,7 +28,7 @@
 #define AT91_AIC_IRQ_MIN_PRIORITY      0
 #define AT91_AIC_IRQ_MAX_PRIORITY      7
 
-#define AT91_AIC_SRCTYPE               GENMASK(7, 6)
+#define AT91_AIC_SRCTYPE               GENMASK(6, 5)
 #define AT91_AIC_SRCTYPE_LOW           (0 << 5)
 #define AT91_AIC_SRCTYPE_FALLING       (1 << 5)
 #define AT91_AIC_SRCTYPE_HIGH          (2 << 5)
@@ -74,7 +74,7 @@ int aic_common_set_type(struct irq_data *d, unsigned type, unsigned *val)
                return -EINVAL;
        }
 
-       *val &= AT91_AIC_SRCTYPE;
+       *val &= ~AT91_AIC_SRCTYPE;
        *val |= aic_type;
 
        return 0;
index 86e4684adeb12d8f8f493dfaa686310c3c0bc4de..d8996bdf0f61e95e45ee670e44e565d045fb9535 100644 (file)
@@ -1053,7 +1053,7 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
         * of two entries. No, the architecture doesn't let you
         * express an ITT with a single entry.
         */
-       nr_ites = max(2, roundup_pow_of_two(nvecs));
+       nr_ites = max(2UL, roundup_pow_of_two(nvecs));
        sz = nr_ites * its->ite_size;
        sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
        itt = kmalloc(sz, GFP_KERNEL);
index 29b8f21b74d0a5868b7ee4034bee285c07bb332b..6bc2deb73d533b3a226f66c2ef17ed2aa3eaf3bb 100644 (file)
@@ -381,7 +381,7 @@ hip04_of_init(struct device_node *node, struct device_node *parent)
         * It will be refined as each CPU probes its ID.
         */
        for (i = 0; i < NR_HIP04_CPU_IF; i++)
-               hip04_cpu_map[i] = 0xff;
+               hip04_cpu_map[i] = 0xffff;
 
        /*
         * Find out how many interrupts are supported.
index 7e342df6a62f58be6e5fcc6a60b71cc81ed15b9c..0b0d2c00a2df8dfda1000cbd92e7d5b1bad824ae 100644 (file)
@@ -137,9 +137,9 @@ static int __init mtk_sysirq_of_init(struct device_node *node,
                return -ENOMEM;
 
        chip_data->intpol_base = of_io_request_and_map(node, 0, "intpol");
-       if (!chip_data->intpol_base) {
+       if (IS_ERR(chip_data->intpol_base)) {
                pr_err("mtk_sysirq: unable to map sysirq register\n");
-               ret = -ENOMEM;
+               ret = PTR_ERR(chip_data->intpol_base);
                goto out_free;
        }
 
index 28718d3e8281032d422d2c9985d7ca450b7763a1..c03f140acbaebf9b29c55548833ffe60a7163907 100644 (file)
@@ -263,7 +263,7 @@ static int __init omap_init_irq_of(struct device_node *node)
        return ret;
 }
 
-static int __init omap_init_irq_legacy(u32 base)
+static int __init omap_init_irq_legacy(u32 base, struct device_node *node)
 {
        int j, irq_base;
 
@@ -277,7 +277,7 @@ static int __init omap_init_irq_legacy(u32 base)
                irq_base = 0;
        }
 
-       domain = irq_domain_add_legacy(NULL, omap_nr_irqs, irq_base, 0,
+       domain = irq_domain_add_legacy(node, omap_nr_irqs, irq_base, 0,
                        &irq_domain_simple_ops, NULL);
 
        omap_irq_soft_reset();
@@ -301,10 +301,26 @@ static int __init omap_init_irq(u32 base, struct device_node *node)
 {
        int ret;
 
-       if (node)
+       /*
+        * FIXME legacy OMAP DMA driver sitting under arch/arm/plat-omap/dma.c
+        * depends is still not ready for linear IRQ domains; because of that
+        * we need to temporarily "blacklist" OMAP2 and OMAP3 devices from using
+        * linear IRQ Domain until that driver is finally fixed.
+        */
+       if (of_device_is_compatible(node, "ti,omap2-intc") ||
+                       of_device_is_compatible(node, "ti,omap3-intc")) {
+               struct resource res;
+
+               if (of_address_to_resource(node, 0, &res))
+                       return -ENOMEM;
+
+               base = res.start;
+               ret = omap_init_irq_legacy(base, node);
+       } else if (node) {
                ret = omap_init_irq_of(node);
-       else
-               ret = omap_init_irq_legacy(base);
+       } else {
+               ret = omap_init_irq_legacy(base, NULL);
+       }
 
        if (ret == 0)
                omap_irq_enable_protection();
index a82e542ffc21dd4dccf9d1b810ab9373984c1d0d..0b380603a578543bcd275d248ade94f3f07b24a8 100644 (file)
@@ -4880,7 +4880,7 @@ static void sig_ind(PLCI *plci)
        byte SS_Ind[] = "\x05\x02\x00\x02\x00\x00"; /* Hold_Ind struct*/
        byte CF_Ind[] = "\x09\x02\x00\x06\x00\x00\x00\x00\x00\x00";
        byte Interr_Err_Ind[] = "\x0a\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
-       byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\0x00\0x00\0x00\0x00";
+       byte CONF_Ind[] = "\x09\x16\x00\x06\x00\x00\x00\x00\x00\x00";
        byte force_mt_info = false;
        byte dir;
        dword d;
index 26515c27ea8cca18a2e5f5ac24f82a6158194182..25e419752a7b7c5719baa69bd114d57720a62f92 100644 (file)
@@ -330,18 +330,18 @@ create_netxbig_led(struct platform_device *pdev,
        led_dat->sata = 0;
        led_dat->cdev.brightness = LED_OFF;
        led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
-       /*
-        * If available, expose the SATA activity blink capability through
-        * a "sata" sysfs attribute.
-        */
-       if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
-               led_dat->cdev.groups = netxbig_led_groups;
        led_dat->mode_addr = template->mode_addr;
        led_dat->mode_val = template->mode_val;
        led_dat->bright_addr = template->bright_addr;
        led_dat->bright_max = (1 << pdata->gpio_ext->num_data) - 1;
        led_dat->timer = pdata->timer;
        led_dat->num_timer = pdata->num_timer;
+       /*
+        * If available, expose the SATA activity blink capability through
+        * a "sata" sysfs attribute.
+        */
+       if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
+               led_dat->cdev.groups = netxbig_led_groups;
 
        return led_classdev_register(&pdev->dev, &led_dat->cdev);
 }
index f956ef26c0ce2ddc1f81014b8ab5e0b658eb9977..fb7493dcfb79f409a8f483480f1c8d50bdba2278 100644 (file)
@@ -7,6 +7,7 @@
 #define PCI_DEVICE_ID_MEN_CHAMELEON    0x4d45
 #define CHAMELEON_FILENAME_LEN         12
 #define CHAMELEONV2_MAGIC              0xabce
+#define CHAM_HEADER_SIZE               0x200
 
 enum chameleon_descriptor_type {
        CHAMELEON_DTYPE_GENERAL = 0x0,
index b5918196564376b028e825ccc75131ae74b1cdd0..5e1bd5db02c8ee7f21e0de9b778d2d1bb17a2d6c 100644 (file)
@@ -17,6 +17,7 @@
 
 struct priv {
        struct mcb_bus *bus;
+       phys_addr_t mapbase;
        void __iomem *base;
 };
 
@@ -31,8 +32,8 @@ static int mcb_pci_get_irq(struct mcb_device *mdev)
 
 static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       struct resource *res;
        struct priv *priv;
-       phys_addr_t mapbase;
        int ret;
        int num_cells;
        unsigned long flags;
@@ -47,19 +48,21 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                return -ENODEV;
        }
 
-       mapbase = pci_resource_start(pdev, 0);
-       if (!mapbase) {
+       priv->mapbase = pci_resource_start(pdev, 0);
+       if (!priv->mapbase) {
                dev_err(&pdev->dev, "No PCI resource\n");
                goto err_start;
        }
 
-       ret = pci_request_region(pdev, 0, KBUILD_MODNAME);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to request PCI BARs\n");
+       res = request_mem_region(priv->mapbase, CHAM_HEADER_SIZE,
+                                KBUILD_MODNAME);
+       if (IS_ERR(res)) {
+               dev_err(&pdev->dev, "Failed to request PCI memory\n");
+               ret = PTR_ERR(res);
                goto err_start;
        }
 
-       priv->base = pci_iomap(pdev, 0, 0);
+       priv->base = ioremap(priv->mapbase, CHAM_HEADER_SIZE);
        if (!priv->base) {
                dev_err(&pdev->dev, "Cannot ioremap\n");
                ret = -ENOMEM;
@@ -84,7 +87,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        priv->bus->get_irq = mcb_pci_get_irq;
 
-       ret = chameleon_parse_cells(priv->bus, mapbase, priv->base);
+       ret = chameleon_parse_cells(priv->bus, priv->mapbase, priv->base);
        if (ret < 0)
                goto err_drvdata;
        num_cells = ret;
@@ -93,8 +96,10 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
        mcb_bus_add_devices(priv->bus);
 
+       return 0;
+
 err_drvdata:
-       pci_iounmap(pdev, priv->base);
+       iounmap(priv->base);
 err_ioremap:
        pci_release_region(pdev, 0);
 err_start:
@@ -107,6 +112,10 @@ static void mcb_pci_remove(struct pci_dev *pdev)
        struct priv *priv = pci_get_drvdata(pdev);
 
        mcb_release_bus(priv->bus);
+
+       iounmap(priv->base);
+       release_region(priv->mapbase, CHAM_HEADER_SIZE);
+       pci_disable_device(pdev);
 }
 
 static const struct pci_device_id mcb_pci_tbl[] = {
index 9fc616c2755ed752a50930e1095df8a7a34303f2..c1c010498a21b99a9bf730b0cd4277776abc159a 100644 (file)
@@ -94,6 +94,9 @@ struct cache_disk_superblock {
 } __packed;
 
 struct dm_cache_metadata {
+       atomic_t ref_count;
+       struct list_head list;
+
        struct block_device *bdev;
        struct dm_block_manager *bm;
        struct dm_space_map *metadata_sm;
@@ -669,10 +672,10 @@ static void unpack_value(__le64 value_le, dm_oblock_t *block, unsigned *flags)
 
 /*----------------------------------------------------------------*/
 
-struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
-                                                sector_t data_block_size,
-                                                bool may_format_device,
-                                                size_t policy_hint_size)
+static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
+                                              sector_t data_block_size,
+                                              bool may_format_device,
+                                              size_t policy_hint_size)
 {
        int r;
        struct dm_cache_metadata *cmd;
@@ -680,9 +683,10 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (!cmd) {
                DMERR("could not allocate metadata struct");
-               return NULL;
+               return ERR_PTR(-ENOMEM);
        }
 
+       atomic_set(&cmd->ref_count, 1);
        init_rwsem(&cmd->root_lock);
        cmd->bdev = bdev;
        cmd->data_block_size = data_block_size;
@@ -705,10 +709,96 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
        return cmd;
 }
 
+/*
+ * We keep a little list of ref counted metadata objects to prevent two
+ * different target instances creating separate bufio instances.  This is
+ * an issue if a table is reloaded before the suspend.
+ */
+static DEFINE_MUTEX(table_lock);
+static LIST_HEAD(table);
+
+static struct dm_cache_metadata *lookup(struct block_device *bdev)
+{
+       struct dm_cache_metadata *cmd;
+
+       list_for_each_entry(cmd, &table, list)
+               if (cmd->bdev == bdev) {
+                       atomic_inc(&cmd->ref_count);
+                       return cmd;
+               }
+
+       return NULL;
+}
+
+static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
+                                               sector_t data_block_size,
+                                               bool may_format_device,
+                                               size_t policy_hint_size)
+{
+       struct dm_cache_metadata *cmd, *cmd2;
+
+       mutex_lock(&table_lock);
+       cmd = lookup(bdev);
+       mutex_unlock(&table_lock);
+
+       if (cmd)
+               return cmd;
+
+       cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size);
+       if (!IS_ERR(cmd)) {
+               mutex_lock(&table_lock);
+               cmd2 = lookup(bdev);
+               if (cmd2) {
+                       mutex_unlock(&table_lock);
+                       __destroy_persistent_data_objects(cmd);
+                       kfree(cmd);
+                       return cmd2;
+               }
+               list_add(&cmd->list, &table);
+               mutex_unlock(&table_lock);
+       }
+
+       return cmd;
+}
+
+static bool same_params(struct dm_cache_metadata *cmd, sector_t data_block_size)
+{
+       if (cmd->data_block_size != data_block_size) {
+               DMERR("data_block_size (%llu) different from that in metadata (%llu)\n",
+                     (unsigned long long) data_block_size,
+                     (unsigned long long) cmd->data_block_size);
+               return false;
+       }
+
+       return true;
+}
+
+struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
+                                                sector_t data_block_size,
+                                                bool may_format_device,
+                                                size_t policy_hint_size)
+{
+       struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size,
+                                                      may_format_device, policy_hint_size);
+
+       if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) {
+               dm_cache_metadata_close(cmd);
+               return ERR_PTR(-EINVAL);
+       }
+
+       return cmd;
+}
+
 void dm_cache_metadata_close(struct dm_cache_metadata *cmd)
 {
-       __destroy_persistent_data_objects(cmd);
-       kfree(cmd);
+       if (atomic_dec_and_test(&cmd->ref_count)) {
+               mutex_lock(&table_lock);
+               list_del(&cmd->list);
+               mutex_unlock(&table_lock);
+
+               __destroy_persistent_data_objects(cmd);
+               kfree(cmd);
+       }
 }
 
 /*
index 1e96d7889f51eaa08b7d65b04c1a43e063931708..e1650539cc2f826d9efe7f878352570bcc31e101 100644 (file)
@@ -221,7 +221,13 @@ struct cache {
        struct list_head need_commit_migrations;
        sector_t migration_threshold;
        wait_queue_head_t migration_wait;
-       atomic_t nr_migrations;
+       atomic_t nr_allocated_migrations;
+
+       /*
+        * The number of in flight migrations that are performing
+        * background io. eg, promotion, writeback.
+        */
+       atomic_t nr_io_migrations;
 
        wait_queue_head_t quiescing_wait;
        atomic_t quiescing;
@@ -258,7 +264,6 @@ struct cache {
        struct dm_deferred_set *all_io_ds;
 
        mempool_t *migration_pool;
-       struct dm_cache_migration *next_migration;
 
        struct dm_cache_policy *policy;
        unsigned policy_nr_args;
@@ -350,10 +355,31 @@ static void free_prison_cell(struct cache *cache, struct dm_bio_prison_cell *cel
        dm_bio_prison_free_cell(cache->prison, cell);
 }
 
+static struct dm_cache_migration *alloc_migration(struct cache *cache)
+{
+       struct dm_cache_migration *mg;
+
+       mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT);
+       if (mg) {
+               mg->cache = cache;
+               atomic_inc(&mg->cache->nr_allocated_migrations);
+       }
+
+       return mg;
+}
+
+static void free_migration(struct dm_cache_migration *mg)
+{
+       if (atomic_dec_and_test(&mg->cache->nr_allocated_migrations))
+               wake_up(&mg->cache->migration_wait);
+
+       mempool_free(mg, mg->cache->migration_pool);
+}
+
 static int prealloc_data_structs(struct cache *cache, struct prealloc *p)
 {
        if (!p->mg) {
-               p->mg = mempool_alloc(cache->migration_pool, GFP_NOWAIT);
+               p->mg = alloc_migration(cache);
                if (!p->mg)
                        return -ENOMEM;
        }
@@ -382,7 +408,7 @@ static void prealloc_free_structs(struct cache *cache, struct prealloc *p)
                free_prison_cell(cache, p->cell1);
 
        if (p->mg)
-               mempool_free(p->mg, cache->migration_pool);
+               free_migration(p->mg);
 }
 
 static struct dm_cache_migration *prealloc_get_migration(struct prealloc *p)
@@ -854,24 +880,14 @@ static void remap_to_origin_then_cache(struct cache *cache, struct bio *bio,
  * Migration covers moving data from the origin device to the cache, or
  * vice versa.
  *--------------------------------------------------------------*/
-static void free_migration(struct dm_cache_migration *mg)
-{
-       mempool_free(mg, mg->cache->migration_pool);
-}
-
-static void inc_nr_migrations(struct cache *cache)
+static void inc_io_migrations(struct cache *cache)
 {
-       atomic_inc(&cache->nr_migrations);
+       atomic_inc(&cache->nr_io_migrations);
 }
 
-static void dec_nr_migrations(struct cache *cache)
+static void dec_io_migrations(struct cache *cache)
 {
-       atomic_dec(&cache->nr_migrations);
-
-       /*
-        * Wake the worker in case we're suspending the target.
-        */
-       wake_up(&cache->migration_wait);
+       atomic_dec(&cache->nr_io_migrations);
 }
 
 static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell,
@@ -894,11 +910,10 @@ static void cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell,
        wake_worker(cache);
 }
 
-static void cleanup_migration(struct dm_cache_migration *mg)
+static void free_io_migration(struct dm_cache_migration *mg)
 {
-       struct cache *cache = mg->cache;
+       dec_io_migrations(mg->cache);
        free_migration(mg);
-       dec_nr_migrations(cache);
 }
 
 static void migration_failure(struct dm_cache_migration *mg)
@@ -923,7 +938,7 @@ static void migration_failure(struct dm_cache_migration *mg)
                cell_defer(cache, mg->new_ocell, true);
        }
 
-       cleanup_migration(mg);
+       free_io_migration(mg);
 }
 
 static void migration_success_pre_commit(struct dm_cache_migration *mg)
@@ -934,7 +949,7 @@ static void migration_success_pre_commit(struct dm_cache_migration *mg)
        if (mg->writeback) {
                clear_dirty(cache, mg->old_oblock, mg->cblock);
                cell_defer(cache, mg->old_ocell, false);
-               cleanup_migration(mg);
+               free_io_migration(mg);
                return;
 
        } else if (mg->demote) {
@@ -944,14 +959,14 @@ static void migration_success_pre_commit(struct dm_cache_migration *mg)
                                             mg->old_oblock);
                        if (mg->promote)
                                cell_defer(cache, mg->new_ocell, true);
-                       cleanup_migration(mg);
+                       free_io_migration(mg);
                        return;
                }
        } else {
                if (dm_cache_insert_mapping(cache->cmd, mg->cblock, mg->new_oblock)) {
                        DMWARN_LIMIT("promotion failed; couldn't update on disk metadata");
                        policy_remove_mapping(cache->policy, mg->new_oblock);
-                       cleanup_migration(mg);
+                       free_io_migration(mg);
                        return;
                }
        }
@@ -984,7 +999,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg)
                } else {
                        if (mg->invalidate)
                                policy_remove_mapping(cache->policy, mg->old_oblock);
-                       cleanup_migration(mg);
+                       free_io_migration(mg);
                }
 
        } else {
@@ -999,7 +1014,7 @@ static void migration_success_post_commit(struct dm_cache_migration *mg)
                        bio_endio(mg->new_ocell->holder, 0);
                        cell_defer(cache, mg->new_ocell, false);
                }
-               cleanup_migration(mg);
+               free_io_migration(mg);
        }
 }
 
@@ -1251,7 +1266,7 @@ static void promote(struct cache *cache, struct prealloc *structs,
        mg->new_ocell = cell;
        mg->start_jiffies = jiffies;
 
-       inc_nr_migrations(cache);
+       inc_io_migrations(cache);
        quiesce_migration(mg);
 }
 
@@ -1275,7 +1290,7 @@ static void writeback(struct cache *cache, struct prealloc *structs,
        mg->new_ocell = NULL;
        mg->start_jiffies = jiffies;
 
-       inc_nr_migrations(cache);
+       inc_io_migrations(cache);
        quiesce_migration(mg);
 }
 
@@ -1302,7 +1317,7 @@ static void demote_then_promote(struct cache *cache, struct prealloc *structs,
        mg->new_ocell = new_ocell;
        mg->start_jiffies = jiffies;
 
-       inc_nr_migrations(cache);
+       inc_io_migrations(cache);
        quiesce_migration(mg);
 }
 
@@ -1330,7 +1345,7 @@ static void invalidate(struct cache *cache, struct prealloc *structs,
        mg->new_ocell = NULL;
        mg->start_jiffies = jiffies;
 
-       inc_nr_migrations(cache);
+       inc_io_migrations(cache);
        quiesce_migration(mg);
 }
 
@@ -1412,7 +1427,7 @@ static void process_discard_bio(struct cache *cache, struct prealloc *structs,
 
 static bool spare_migration_bandwidth(struct cache *cache)
 {
-       sector_t current_volume = (atomic_read(&cache->nr_migrations) + 1) *
+       sector_t current_volume = (atomic_read(&cache->nr_io_migrations) + 1) *
                cache->sectors_per_block;
        return current_volume < cache->migration_threshold;
 }
@@ -1764,7 +1779,7 @@ static void stop_quiescing(struct cache *cache)
 
 static void wait_for_migrations(struct cache *cache)
 {
-       wait_event(cache->migration_wait, !atomic_read(&cache->nr_migrations));
+       wait_event(cache->migration_wait, !atomic_read(&cache->nr_allocated_migrations));
 }
 
 static void stop_worker(struct cache *cache)
@@ -1876,9 +1891,6 @@ static void destroy(struct cache *cache)
 {
        unsigned i;
 
-       if (cache->next_migration)
-               mempool_free(cache->next_migration, cache->migration_pool);
-
        if (cache->migration_pool)
                mempool_destroy(cache->migration_pool);
 
@@ -2424,7 +2436,8 @@ static int cache_create(struct cache_args *ca, struct cache **result)
        INIT_LIST_HEAD(&cache->quiesced_migrations);
        INIT_LIST_HEAD(&cache->completed_migrations);
        INIT_LIST_HEAD(&cache->need_commit_migrations);
-       atomic_set(&cache->nr_migrations, 0);
+       atomic_set(&cache->nr_allocated_migrations, 0);
+       atomic_set(&cache->nr_io_migrations, 0);
        init_waitqueue_head(&cache->migration_wait);
 
        init_waitqueue_head(&cache->quiescing_wait);
@@ -2487,8 +2500,6 @@ static int cache_create(struct cache_args *ca, struct cache **result)
                goto bad;
        }
 
-       cache->next_migration = NULL;
-
        cache->need_tick_bio = true;
        cache->sized = false;
        cache->invalidate = false;
index 8735543eacdb9ae0961ed841c3f8e81628100520..07705ee181e3d2837c47954626276f9dea52cac0 100644 (file)
@@ -1127,6 +1127,24 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block,
                schedule_zero(tc, virt_block, data_dest, cell, bio);
 }
 
+static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
+
+static void check_for_space(struct pool *pool)
+{
+       int r;
+       dm_block_t nr_free;
+
+       if (get_pool_mode(pool) != PM_OUT_OF_DATA_SPACE)
+               return;
+
+       r = dm_pool_get_free_block_count(pool->pmd, &nr_free);
+       if (r)
+               return;
+
+       if (nr_free)
+               set_pool_mode(pool, PM_WRITE);
+}
+
 /*
  * A non-zero return indicates read_only or fail_io mode.
  * Many callers don't care about the return value.
@@ -1141,6 +1159,8 @@ static int commit(struct pool *pool)
        r = dm_pool_commit_metadata(pool->pmd);
        if (r)
                metadata_operation_failed(pool, "dm_pool_commit_metadata", r);
+       else
+               check_for_space(pool);
 
        return r;
 }
@@ -1159,8 +1179,6 @@ static void check_low_water_mark(struct pool *pool, dm_block_t free_blocks)
        }
 }
 
-static void set_pool_mode(struct pool *pool, enum pool_mode new_mode);
-
 static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
 {
        int r;
@@ -2155,7 +2173,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
                pool->process_cell = process_cell_read_only;
                pool->process_discard_cell = process_discard_cell;
                pool->process_prepared_mapping = process_prepared_mapping;
-               pool->process_prepared_discard = process_prepared_discard_passdown;
+               pool->process_prepared_discard = process_prepared_discard;
 
                if (!pool->pf.error_if_no_space && no_space_timeout)
                        queue_delayed_work(pool->wq, &pool->no_space_timeout, no_space_timeout);
@@ -3367,6 +3385,12 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
 
+       if (get_pool_mode(pool) >= PM_READ_ONLY) {
+               DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode",
+                     dm_device_name(pool->pool_md));
+               return -EINVAL;
+       }
+
        if (!strcasecmp(argv[0], "create_thin"))
                r = process_create_thin_mesg(argc, argv, pool);
 
@@ -3814,6 +3838,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
                r = -EINVAL;
                goto bad;
        }
+       atomic_set(&tc->refcount, 1);
+       init_completion(&tc->can_destroy);
        list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
        spin_unlock_irqrestore(&tc->pool->lock, flags);
        /*
@@ -3826,9 +3852,6 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
 
        dm_put(pool_md);
 
-       atomic_set(&tc->refcount, 1);
-       init_completion(&tc->can_destroy);
-
        return 0;
 
 bad:
index 4c06585bf1657b076835c073f973b1dc780968d6..2caf5b374649afaecff37a5ab5153d7ccc5ec437 100644 (file)
@@ -206,6 +206,9 @@ struct mapped_device {
        /* zero-length flush that will be cloned and submitted to targets */
        struct bio flush_bio;
 
+       /* the number of internal suspends */
+       unsigned internal_suspend_count;
+
        struct dm_stats stats;
 };
 
@@ -899,7 +902,7 @@ static void disable_write_same(struct mapped_device *md)
 
 static void clone_endio(struct bio *bio, int error)
 {
-       int r = 0;
+       int r = error;
        struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
        struct dm_io *io = tio->io;
        struct mapped_device *md = tio->io->md;
@@ -2928,7 +2931,7 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla
 {
        struct dm_table *map = NULL;
 
-       if (dm_suspended_internally_md(md))
+       if (md->internal_suspend_count++)
                return; /* nested internal suspend */
 
        if (dm_suspended_md(md)) {
@@ -2953,7 +2956,9 @@ static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_fla
 
 static void __dm_internal_resume(struct mapped_device *md)
 {
-       if (!dm_suspended_internally_md(md))
+       BUG_ON(!md->internal_suspend_count);
+
+       if (--md->internal_suspend_count)
                return; /* resume from nested internal suspend */
 
        if (dm_suspended_md(md))
index db99ca2613ba422d20c60afcbe34a4750a9876c0..06931f6fa26cc0003db9789440ebf9c5277759df 100644 (file)
@@ -614,7 +614,7 @@ struct cx23885_board cx23885_boards[] = {
                .portb          = CX23885_MPEG_DVB,
        },
        [CX23885_BOARD_HAUPPAUGE_HVR4400] = {
-               .name           = "Hauppauge WinTV-HVR4400",
+               .name           = "Hauppauge WinTV-HVR4400/HVR5500",
                .porta          = CX23885_ANALOG_VIDEO,
                .portb          = CX23885_MPEG_DVB,
                .portc          = CX23885_MPEG_DVB,
@@ -622,6 +622,10 @@ struct cx23885_board cx23885_boards[] = {
                .tuner_addr     = 0x60, /* 0xc0 >> 1 */
                .tuner_bus      = 1,
        },
+       [CX23885_BOARD_HAUPPAUGE_STARBURST] = {
+               .name           = "Hauppauge WinTV Starburst",
+               .portb          = CX23885_MPEG_DVB,
+       },
        [CX23885_BOARD_AVERMEDIA_HC81R] = {
                .name           = "AVerTV Hybrid Express Slim HC81R",
                .tuner_type     = TUNER_XC2028,
@@ -936,19 +940,19 @@ struct cx23885_subid cx23885_subids[] = {
        }, {
                .subvendor = 0x0070,
                .subdevice = 0xc108,
-               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400, /* Hauppauge WinTV HVR-4400 (Model 121xxx, Hybrid DVB-T/S2, IR) */
        }, {
                .subvendor = 0x0070,
                .subdevice = 0xc138,
-               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400, /* Hauppauge WinTV HVR-5500 (Model 121xxx, Hybrid DVB-T/C/S2, IR) */
        }, {
                .subvendor = 0x0070,
                .subdevice = 0xc12a,
-               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400,
+               .card      = CX23885_BOARD_HAUPPAUGE_STARBURST, /* Hauppauge WinTV Starburst (Model 121x00, DVB-S2, IR) */
        }, {
                .subvendor = 0x0070,
                .subdevice = 0xc1f8,
-               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400,
+               .card      = CX23885_BOARD_HAUPPAUGE_HVR4400, /* Hauppauge WinTV HVR-5500 (Model 121xxx, Hybrid DVB-T/C/S2, IR) */
        }, {
                .subvendor = 0x1461,
                .subdevice = 0xd939,
@@ -1545,8 +1549,9 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
                cx_write(GPIO_ISM, 0x00000000);/* INTERRUPTS active low*/
                break;
        case CX23885_BOARD_HAUPPAUGE_HVR4400:
+       case CX23885_BOARD_HAUPPAUGE_STARBURST:
                /* GPIO-8 tda10071 demod reset */
-               /* GPIO-9 si2165 demod reset */
+               /* GPIO-9 si2165 demod reset (only HVR4400/HVR5500)*/
 
                /* Put the parts into reset and back */
                cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
@@ -1872,6 +1877,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
        case CX23885_BOARD_HAUPPAUGE_HVR4400:
+       case CX23885_BOARD_HAUPPAUGE_STARBURST:
        case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
                if (dev->i2c_bus[0].i2c_rc == 0)
                        hauppauge_eeprom(dev, eeprom+0xc0);
@@ -1980,6 +1986,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
                ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
                ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
                break;
+       case CX23885_BOARD_HAUPPAUGE_STARBURST:
+               ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+               ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+               ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+               break;
        case CX23885_BOARD_DVBSKY_T9580:
        case CX23885_BOARD_DVBSKY_T982:
                ts1->gen_ctrl_val  = 0x5; /* Parallel */
index 1d9d0f86ca8cbe3effb833fe7e43d26185aefb41..1ad49946d7fa9c1ef8f6cb71d8e91c85d566e4a6 100644 (file)
@@ -2049,11 +2049,11 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
 
        cx23885_shutdown(dev);
 
-       pci_disable_device(pci_dev);
-
        /* unregister stuff */
        free_irq(pci_dev->irq, dev);
 
+       pci_disable_device(pci_dev);
+
        cx23885_dev_unregister(dev);
        vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
        v4l2_ctrl_handler_free(&dev->ctrl_handler);
index c47d18270cfc8899f262be3f338329e869bb4cb2..a9c450d4b54e4a7d52440b6af017d9068b27435c 100644 (file)
@@ -1710,6 +1710,17 @@ static int dvb_register(struct cx23885_tsport *port)
                        break;
                }
                break;
+       case CX23885_BOARD_HAUPPAUGE_STARBURST:
+               i2c_bus = &dev->i2c_bus[0];
+               fe0->dvb.frontend = dvb_attach(tda10071_attach,
+                                               &hauppauge_tda10071_config,
+                                               &i2c_bus->i2c_adap);
+               if (fe0->dvb.frontend != NULL) {
+                       dvb_attach(a8293_attach, fe0->dvb.frontend,
+                                  &i2c_bus->i2c_adap,
+                                  &hauppauge_a8293_config);
+               }
+               break;
        case CX23885_BOARD_DVBSKY_T9580:
        case CX23885_BOARD_DVBSKY_S950:
                i2c_bus = &dev->i2c_bus[0];
index f55cd12da0fde35b55ae5c3c75d56253f64fd9ac..36f2f96c40e4362713f7e2f06987af911d6472c2 100644 (file)
@@ -99,6 +99,7 @@
 #define CX23885_BOARD_DVBSKY_S950              49
 #define CX23885_BOARD_DVBSKY_S952              50
 #define CX23885_BOARD_DVBSKY_T982              51
+#define CX23885_BOARD_HAUPPAUGE_STARBURST      52
 
 #define GPIO_0 0x00000001
 #define GPIO_1 0x00000002
index b463fe172d164a0f14400c42f13f33aa9dbc82dd..3fe9047ef466faddcb822453e08282bf381c366b 100644 (file)
@@ -602,10 +602,13 @@ isp_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
        strlcpy(cap->card, video->video.name, sizeof(cap->card));
        strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
 
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+               | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
+
        if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
-               cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+               cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
        else
-               cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+               cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
 
        return 0;
 }
index 8efe40337608951db5b72137506dd61e13e20b06..6d885239b16abf0b01b721de4f27cf924f6b7f4a 100644 (file)
@@ -760,8 +760,9 @@ static int isi_camera_querycap(struct soc_camera_host *ici,
 {
        strcpy(cap->driver, "atmel-isi");
        strcpy(cap->card, "Atmel Image Sensor Interface");
-       cap->capabilities = (V4L2_CAP_VIDEO_CAPTURE |
-                               V4L2_CAP_STREAMING);
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
        return 0;
 }
 
index ce72bd26a6acaef29a740863eaae99232401ec6c..192377f55840b540e82ab26658830457b858f98f 100644 (file)
@@ -1256,7 +1256,8 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
index a60c3bb0e4ccdf952307142c2196333ee6842ab5..0b3299dee05d453c87a492cd610d66e507f8a7ba 100644 (file)
@@ -967,7 +967,8 @@ static int mx3_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the firendly caller:-> */
        strlcpy(cap->card, "i.MX3x Camera", sizeof(cap->card));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
index e6b93281f246c394eee1006deadb1bfac2a12be9..16f65ecb70a3e1fdf13d49cf002d2801559b83d5 100644 (file)
@@ -1427,7 +1427,8 @@ static int omap1_cam_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the friendly caller:-> */
        strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
index 951226af0ebacca484127cc7792802c9eeafa577..8d6e343fec0f28bf1dcc67d0ce96ff48dc6f7250 100644 (file)
@@ -1576,7 +1576,8 @@ static int pxa_camera_querycap(struct soc_camera_host *ici,
 {
        /* cap->name is set by the firendly caller:-> */
        strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
index 0c1f5564810627ec88242ac373600f03a854387d..9f1473c0a0cfa493227f50ac1920ae34818e670b 100644 (file)
@@ -1799,7 +1799,9 @@ static int rcar_vin_querycap(struct soc_camera_host *ici,
                             struct v4l2_capability *cap)
 {
        strlcpy(cap->card, "R_Car_VIN", sizeof(cap->card));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
        return 0;
 }
 
index 8b27b3eb2b2538d7e75451ffff0c06d27d2cafd6..71787702d4a26cce7ba7a1b02f2ab367ed388db5 100644 (file)
@@ -1652,7 +1652,9 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
                                  struct v4l2_capability *cap)
 {
        strlcpy(cap->card, "SuperH_Mobile_CEU", sizeof(cap->card));
-       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
        return 0;
 }
 
index 0f345b1f90145dd856c4830cecf82c710eeeaeeb..f327c49d7e0936baf1e529746e82166129423916 100644 (file)
@@ -2232,7 +2232,7 @@ static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
                {
                        "Mygica T230 DVB-T/T2/C",
                        { NULL },
-                       { &cxusb_table[22], NULL },
+                       { &cxusb_table[20], NULL },
                },
        }
 };
index 1b158f1167ed0722793a8b58b990a1fc378e4a34..536210b39428c98ce1f8385b48ab1a13ba2cf7d2 100644 (file)
@@ -89,16 +89,6 @@ static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
 module_param_array(vbi_nr, int, NULL, 0444);
 MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor");
 
-static struct v4l2_capability pvr_capability ={
-       .driver         = "pvrusb2",
-       .card           = "Hauppauge WinTV pvr-usb2",
-       .bus_info       = "usb",
-       .version        = LINUX_VERSION_CODE,
-       .capabilities   = (V4L2_CAP_VIDEO_CAPTURE |
-                          V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
-                          V4L2_CAP_READWRITE),
-};
-
 static struct v4l2_fmtdesc pvr_fmtdesc [] = {
        {
                .index          = 0,
@@ -160,10 +150,22 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability *
        struct pvr2_v4l2_fh *fh = file->private_data;
        struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
 
-       memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+       strlcpy(cap->driver, "pvrusb2", sizeof(cap->driver));
        strlcpy(cap->bus_info, pvr2_hdw_get_bus_info(hdw),
                        sizeof(cap->bus_info));
        strlcpy(cap->card, pvr2_hdw_get_desc(hdw), sizeof(cap->card));
+       cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
+                           V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
+                           V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS;
+       switch (fh->pdi->devbase.vfl_type) {
+       case VFL_TYPE_GRABBER:
+               cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO;
+               break;
+       case VFL_TYPE_RADIO:
+               cap->device_caps = V4L2_CAP_RADIO;
+               break;
+       }
+       cap->device_caps |= V4L2_CAP_TUNER | V4L2_CAP_READWRITE;
        return 0;
 }
 
index d09a8916e94005180f0f6beaf0ff53d7b2e932a4..bc08a829bc132068c0b51661f9459293ef30c142 100644 (file)
@@ -3146,27 +3146,26 @@ static int vb2_thread(void *data)
                        prequeue--;
                } else {
                        call_void_qop(q, wait_finish, q);
-                       ret = vb2_internal_dqbuf(q, &fileio->b, 0);
+                       if (!threadio->stop)
+                               ret = vb2_internal_dqbuf(q, &fileio->b, 0);
                        call_void_qop(q, wait_prepare, q);
                        dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
                }
-               if (threadio->stop)
-                       break;
-               if (ret)
+               if (ret || threadio->stop)
                        break;
                try_to_freeze();
 
                vb = q->bufs[fileio->b.index];
                if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR))
-                       ret = threadio->fnc(vb, threadio->priv);
-               if (ret)
-                       break;
+                       if (threadio->fnc(vb, threadio->priv))
+                               break;
                call_void_qop(q, wait_finish, q);
                if (set_timestamp)
                        v4l2_get_timestamp(&fileio->b.timestamp);
-               ret = vb2_internal_qbuf(q, &fileio->b);
+               if (!threadio->stop)
+                       ret = vb2_internal_qbuf(q, &fileio->b);
                call_void_qop(q, wait_prepare, q);
-               if (ret)
+               if (ret || threadio->stop)
                        break;
        }
 
@@ -3235,11 +3234,11 @@ int vb2_thread_stop(struct vb2_queue *q)
        threadio->stop = true;
        vb2_internal_streamoff(q, q->type);
        call_void_qop(q, wait_prepare, q);
+       err = kthread_stop(threadio->thread);
        q->fileio = NULL;
        fileio->req.count = 0;
        vb2_reqbufs(q, &fileio->req);
        kfree(fileio);
-       err = kthread_stop(threadio->thread);
        threadio->thread = NULL;
        kfree(threadio);
        q->fileio = NULL;
index 52a0c2f6264ff041f43a2fbcb2e187ada48e6d4b..ae498b53ee4042ef3e39e6f77a7272cffe4abe74 100644 (file)
@@ -554,7 +554,8 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id)
                return ret;
        }
 
-       ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
+       ret = mfd_add_devices(da9052->dev, PLATFORM_DEVID_AUTO,
+                             da9052_subdev_info,
                              ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL);
        if (ret) {
                dev_err(da9052->dev, "mfd_add_devices failed: %d\n", ret);
index dbdd0faeb6ce500678d9dc4f014504560693bded..210d1f85679e50dca4cbb034d4bd4ce91c1bb23f 100644 (file)
@@ -681,21 +681,9 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
 #ifdef CONFIG_PM
 static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
 {
-       struct rtsx_ucr *ucr =
-               (struct rtsx_ucr *)usb_get_intfdata(intf);
-
        dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n",
                        __func__, message.event);
 
-       /*
-        * Call to make sure LED is off during suspend to save more power.
-        * It is NOT a permanent state and could be turned on anytime later.
-        * Thus no need to call turn_on when resunming.
-        */
-       mutex_lock(&ucr->dev_mutex);
-       rtsx_usb_turn_off_led(ucr);
-       mutex_unlock(&ucr->dev_mutex);
-
        return 0;
 }
 
index e2f9df1c0c361f0d0e66bf782817af6170e49dc5..2d7fae94c861013c594463705e05ea413275e4d0 100644 (file)
@@ -519,6 +519,7 @@ static const u8 stmpe1601_regs[] = {
        [STMPE_IDX_GPDR_LSB]    = STMPE1601_REG_GPIO_SET_DIR_LSB,
        [STMPE_IDX_GPRER_LSB]   = STMPE1601_REG_GPIO_RE_LSB,
        [STMPE_IDX_GPFER_LSB]   = STMPE1601_REG_GPIO_FE_LSB,
+       [STMPE_IDX_GPPUR_LSB]   = STMPE1601_REG_GPIO_PU_LSB,
        [STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB,
        [STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB,
@@ -667,6 +668,7 @@ static const u8 stmpe1801_regs[] = {
        [STMPE_IDX_GPDR_LSB]    = STMPE1801_REG_GPIO_SET_DIR_LOW,
        [STMPE_IDX_GPRER_LSB]   = STMPE1801_REG_GPIO_RE_LOW,
        [STMPE_IDX_GPFER_LSB]   = STMPE1801_REG_GPIO_FE_LOW,
+       [STMPE_IDX_GPPUR_LSB]   = STMPE1801_REG_GPIO_PULL_UP_LOW,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW,
        [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW,
 };
@@ -750,6 +752,8 @@ static const u8 stmpe24xx_regs[] = {
        [STMPE_IDX_GPDR_LSB]    = STMPE24XX_REG_GPDR_LSB,
        [STMPE_IDX_GPRER_LSB]   = STMPE24XX_REG_GPRER_LSB,
        [STMPE_IDX_GPFER_LSB]   = STMPE24XX_REG_GPFER_LSB,
+       [STMPE_IDX_GPPUR_LSB]   = STMPE24XX_REG_GPPUR_LSB,
+       [STMPE_IDX_GPPDR_LSB]   = STMPE24XX_REG_GPPDR_LSB,
        [STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB,
        [STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB,
        [STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB,
index bee0abf82040001664c07e82c646e0e3e5afc259..84adb46b3e2fea599f069072f2f48190602092e9 100644 (file)
@@ -188,6 +188,7 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE1601_REG_GPIO_ED_MSB              0x8A
 #define STMPE1601_REG_GPIO_RE_LSB              0x8D
 #define STMPE1601_REG_GPIO_FE_LSB              0x8F
+#define STMPE1601_REG_GPIO_PU_LSB              0x91
 #define STMPE1601_REG_GPIO_AF_U_MSB            0x92
 
 #define STMPE1601_SYS_CTRL_ENABLE_GPIO         (1 << 3)
@@ -276,6 +277,8 @@ int stmpe_remove(struct stmpe *stmpe);
 #define STMPE24XX_REG_GPEDR_MSB                0x8C
 #define STMPE24XX_REG_GPRER_LSB                0x91
 #define STMPE24XX_REG_GPFER_LSB                0x94
+#define STMPE24XX_REG_GPPUR_LSB                0x97
+#define STMPE24XX_REG_GPPDR_LSB                0x9a
 #define STMPE24XX_REG_GPAFR_U_MSB      0x9B
 
 #define STMPE24XX_SYS_CTRL_ENABLE_GPIO         (1 << 3)
index 0d256cb002eb00480113435390fc19d5d92cb6cf..d6b764349f9d309956b36fd270ae1b6940e8167c 100644 (file)
@@ -125,10 +125,21 @@ int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg,
 }
 EXPORT_SYMBOL_GPL(tps65218_clear_bits);
 
+static const struct regmap_range tps65218_yes_ranges[] = {
+       regmap_reg_range(TPS65218_REG_INT1, TPS65218_REG_INT2),
+       regmap_reg_range(TPS65218_REG_STATUS, TPS65218_REG_STATUS),
+};
+
+static const struct regmap_access_table tps65218_volatile_table = {
+       .yes_ranges = tps65218_yes_ranges,
+       .n_yes_ranges = ARRAY_SIZE(tps65218_yes_ranges),
+};
+
 static struct regmap_config tps65218_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
        .cache_type = REGCACHE_RBTREE,
+       .volatile_table = &tps65218_volatile_table,
 };
 
 static const struct regmap_irq tps65218_irqs[] = {
@@ -193,6 +204,7 @@ static struct regmap_irq_chip tps65218_irq_chip = {
 
        .num_regs = 2,
        .mask_base = TPS65218_REG_INT_MASK1,
+       .status_base = TPS65218_REG_INT1,
 };
 
 static const struct of_device_id of_tps65218_match_table[] = {
index 51fd6b524371ecd9ae762716e4cf33692c36ce45..d1b55fe62817dcd0261ab926a704a37f590ca67c 100644 (file)
@@ -100,6 +100,46 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master,
        return 0;
 }
 
+static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct cxl_context *ctx = vma->vm_file->private_data;
+       unsigned long address = (unsigned long)vmf->virtual_address;
+       u64 area, offset;
+
+       offset = vmf->pgoff << PAGE_SHIFT;
+
+       pr_devel("%s: pe: %i address: 0x%lx offset: 0x%llx\n",
+                       __func__, ctx->pe, address, offset);
+
+       if (ctx->afu->current_mode == CXL_MODE_DEDICATED) {
+               area = ctx->afu->psn_phys;
+               if (offset > ctx->afu->adapter->ps_size)
+                       return VM_FAULT_SIGBUS;
+       } else {
+               area = ctx->psn_phys;
+               if (offset > ctx->psn_size)
+                       return VM_FAULT_SIGBUS;
+       }
+
+       mutex_lock(&ctx->status_mutex);
+
+       if (ctx->status != STARTED) {
+               mutex_unlock(&ctx->status_mutex);
+               pr_devel("%s: Context not started, failing problem state access\n", __func__);
+               return VM_FAULT_SIGBUS;
+       }
+
+       vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
+
+       mutex_unlock(&ctx->status_mutex);
+
+       return VM_FAULT_NOPAGE;
+}
+
+static const struct vm_operations_struct cxl_mmap_vmops = {
+       .fault = cxl_mmap_fault,
+};
+
 /*
  * Map a per-context mmio space into the given vma.
  */
@@ -108,26 +148,25 @@ int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma)
        u64 len = vma->vm_end - vma->vm_start;
        len = min(len, ctx->psn_size);
 
-       if (ctx->afu->current_mode == CXL_MODE_DEDICATED) {
-               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-               return vm_iomap_memory(vma, ctx->afu->psn_phys, ctx->afu->adapter->ps_size);
-       }
+       if (ctx->afu->current_mode != CXL_MODE_DEDICATED) {
+               /* make sure there is a valid per process space for this AFU */
+               if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) {
+                       pr_devel("AFU doesn't support mmio space\n");
+                       return -EINVAL;
+               }
 
-       /* make sure there is a valid per process space for this AFU */
-       if ((ctx->master && !ctx->afu->psa) || (!ctx->afu->pp_psa)) {
-               pr_devel("AFU doesn't support mmio space\n");
-               return -EINVAL;
+               /* Can't mmap until the AFU is enabled */
+               if (!ctx->afu->enabled)
+                       return -EBUSY;
        }
 
-       /* Can't mmap until the AFU is enabled */
-       if (!ctx->afu->enabled)
-               return -EBUSY;
-
        pr_devel("%s: mmio physical: %llx pe: %i master:%i\n", __func__,
                 ctx->psn_phys, ctx->pe , ctx->master);
 
+       vma->vm_flags |= VM_IO | VM_PFNMAP;
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       return vm_iomap_memory(vma, ctx->psn_phys, len);
+       vma->vm_ops = &cxl_mmap_vmops;
+       return 0;
 }
 
 /*
@@ -150,12 +189,6 @@ static void __detach_context(struct cxl_context *ctx)
        afu_release_irqs(ctx);
        flush_work(&ctx->fault_work); /* Only needed for dedicated process */
        wake_up_all(&ctx->wq);
-
-       /* Release Problem State Area mapping */
-       mutex_lock(&ctx->mapping_lock);
-       if (ctx->mapping)
-               unmap_mapping_range(ctx->mapping, 0, 0, 1);
-       mutex_unlock(&ctx->mapping_lock);
 }
 
 /*
@@ -184,6 +217,17 @@ void cxl_context_detach_all(struct cxl_afu *afu)
                 * created and torn down after the IDR removed
                 */
                __detach_context(ctx);
+
+               /*
+                * We are force detaching - remove any active PSA mappings so
+                * userspace cannot interfere with the card if it comes back.
+                * Easiest way to exercise this is to unbind and rebind the
+                * driver via sysfs while it is in use.
+                */
+               mutex_lock(&ctx->mapping_lock);
+               if (ctx->mapping)
+                       unmap_mapping_range(ctx->mapping, 0, 0, 1);
+               mutex_unlock(&ctx->mapping_lock);
        }
        mutex_unlock(&afu->contexts_lock);
 }
index e9f2f10dbb3734f3de4df60cdaed583415cfd831..b15d8113877c9f6ed5c45c58fb012fa6f50276aa 100644 (file)
@@ -140,18 +140,20 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
 
        pr_devel("%s: pe: %i\n", __func__, ctx->pe);
 
-       mutex_lock(&ctx->status_mutex);
-       if (ctx->status != OPENED) {
-               rc = -EIO;
-               goto out;
-       }
-
+       /* Do this outside the status_mutex to avoid a circular dependency with
+        * the locking in cxl_mmap_fault() */
        if (copy_from_user(&work, uwork,
                           sizeof(struct cxl_ioctl_start_work))) {
                rc = -EFAULT;
                goto out;
        }
 
+       mutex_lock(&ctx->status_mutex);
+       if (ctx->status != OPENED) {
+               rc = -EIO;
+               goto out;
+       }
+
        /*
         * if any of the reserved fields are set or any of the unused
         * flags are set it's invalid
index ff2755062b4420cf3239a80e0f767d6dc333b6a6..06ff0a2ec96071c5b2d1c2c5dffdff7a5c03d938 100644 (file)
@@ -234,6 +234,18 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
        struct mei_me_hw *hw = to_me_hw(dev);
        u32 hcsr = mei_hcsr_read(hw);
 
+       /* H_RST may be found lit before reset is started,
+        * for example if preceding reset flow hasn't completed.
+        * In that case asserting H_RST will be ignored, therefore
+        * we need to clean H_RST bit to start a successful reset sequence.
+        */
+       if ((hcsr & H_RST) == H_RST) {
+               dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr);
+               hcsr &= ~H_RST;
+               mei_me_reg_write(hw, H_CSR, hcsr);
+               hcsr = mei_hcsr_read(hw);
+       }
+
        hcsr |= H_RST | H_IG | H_IS;
 
        if (intr_enable)
index 02ad79229f65ecf0b50b9bf29a1f63c0d297910e..7466ce098e60a086e4f60c5111c19c1b85cd6d60 100644 (file)
@@ -886,7 +886,7 @@ static int mmc_select_bus_width(struct mmc_card *card)
        unsigned idx, bus_width = 0;
        int err = 0;
 
-       if (!mmc_can_ext_csd(card) &&
+       if (!mmc_can_ext_csd(card) ||
            !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
                return 0;
 
index e3e56d35f0eeee634a0930acce0500bb33cb3258..970314e0aac8f1f05e5b9ff199e28723b9d85a19 100644 (file)
@@ -247,6 +247,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
        { "INT33BB"  , "3" , &sdhci_acpi_slot_int_sd },
        { "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
        { "INT3436"  , NULL, &sdhci_acpi_slot_int_sdio },
+       { "INT344D"  , NULL, &sdhci_acpi_slot_int_sdio },
        { "PNP0D40"  },
        { },
 };
@@ -257,6 +258,7 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
        { "INT33BB"  },
        { "INT33C6"  },
        { "INT3436"  },
+       { "INT344D"  },
        { "PNP0D40"  },
        { },
 };
index 03427755b9029b297393d1d43851b4f678f2bbae..4f38554ce6797e0a461a3ddaf76261264229f107 100644 (file)
@@ -993,6 +993,31 @@ static const struct pci_device_id pci_ids[] = {
                .subdevice      = PCI_ANY_ID,
                .driver_data    = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
        },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_SPT_EMMC,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_SPT_SDIO,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_SPT_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_sd,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_O2,
                .device         = PCI_DEVICE_ID_O2_8120,
index d57c3d169914e94e716b64b90e8b8da2b86afa87..1ec684d06d54733b35b2427d4007bfd5cfd3d52b 100644 (file)
@@ -21,6 +21,9 @@
 #define PCI_DEVICE_ID_INTEL_CLV_EMMC0  0x08e5
 #define PCI_DEVICE_ID_INTEL_CLV_EMMC1  0x08e6
 #define PCI_DEVICE_ID_INTEL_QRK_SD     0x08A7
+#define PCI_DEVICE_ID_INTEL_SPT_EMMC   0x9d2b
+#define PCI_DEVICE_ID_INTEL_SPT_SDIO   0x9d2c
+#define PCI_DEVICE_ID_INTEL_SPT_SD     0x9d2d
 
 /*
  * PCI registers
index 45238871192da1d6553268d82659dce3cc600d68..ca3424e7ef717c59a82da1e13a8ca3cf939da7f2 100644 (file)
@@ -300,13 +300,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        if (IS_ERR(host))
                return PTR_ERR(host);
 
-       if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
-               ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
-               if (ret < 0)
-                       goto err_mbus_win;
-       }
-
-
        pltfm_host = sdhci_priv(host);
        pltfm_host->priv = pxa;
 
@@ -325,6 +318,12 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        if (!IS_ERR(pxa->clk_core))
                clk_prepare_enable(pxa->clk_core);
 
+       if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
+               ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
+               if (ret < 0)
+                       goto err_mbus_win;
+       }
+
        /* enable 1/8V DDR capable */
        host->mmc->caps |= MMC_CAP_1_8V_DDR;
 
@@ -396,11 +395,11 @@ err_add_host:
        pm_runtime_disable(&pdev->dev);
 err_of_parse:
 err_cd_req:
+err_mbus_win:
        clk_disable_unprepare(pxa->clk_io);
        if (!IS_ERR(pxa->clk_core))
                clk_disable_unprepare(pxa->clk_core);
 err_clk_get:
-err_mbus_win:
        sdhci_pltfm_free(pdev);
        return ret;
 }
index cbb245b5853873cbddc2f1a0967c8bcc989ea4e1..f1a488ee432f891971f79707d78ca91a631b6c51 100644 (file)
@@ -259,8 +259,6 @@ static void sdhci_reinit(struct sdhci_host *host)
 
                del_timer_sync(&host->tuning_timer);
                host->flags &= ~SDHCI_NEEDS_RETUNING;
-               host->mmc->max_blk_count =
-                       (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
        }
        sdhci_enable_card_detection(host);
 }
@@ -1273,6 +1271,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
                spin_unlock_irq(&host->lock);
                mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
                spin_lock_irq(&host->lock);
+
+               if (mode != MMC_POWER_OFF)
+                       sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
+               else
+                       sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+
                return;
        }
 
@@ -1353,6 +1357,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        sdhci_runtime_pm_get(host);
 
+       present = mmc_gpio_get_cd(host->mmc);
+
        spin_lock_irqsave(&host->lock, flags);
 
        WARN_ON(host->mrq != NULL);
@@ -1381,7 +1387,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
         *     zero: cd-gpio is used, and card is removed
         *     one: cd-gpio is used, and card is present
         */
-       present = mmc_gpio_get_cd(host->mmc);
        if (present < 0) {
                /* If polling, assume that the card is always present. */
                if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
@@ -1880,6 +1885,18 @@ static int sdhci_card_busy(struct mmc_host *mmc)
        return !(present_state & SDHCI_DATA_LVL_MASK);
 }
 
+static int sdhci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct sdhci_host *host = mmc_priv(mmc);
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       host->flags |= SDHCI_HS400_TUNING;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       return 0;
+}
+
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct sdhci_host *host = mmc_priv(mmc);
@@ -1887,10 +1904,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        int tuning_loop_counter = MAX_TUNING_LOOP;
        int err = 0;
        unsigned long flags;
+       unsigned int tuning_count = 0;
+       bool hs400_tuning;
 
        sdhci_runtime_pm_get(host);
        spin_lock_irqsave(&host->lock, flags);
 
+       hs400_tuning = host->flags & SDHCI_HS400_TUNING;
+       host->flags &= ~SDHCI_HS400_TUNING;
+
+       if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+               tuning_count = host->tuning_count;
+
        /*
         * The Host Controller needs tuning only in case of SDR104 mode
         * and for SDR50 mode when Use Tuning for SDR50 is set in the
@@ -1899,8 +1924,20 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * tuning function has to be executed.
         */
        switch (host->timing) {
+       /* HS400 tuning is done in HS200 mode */
        case MMC_TIMING_MMC_HS400:
+               err = -EINVAL;
+               goto out_unlock;
+
        case MMC_TIMING_MMC_HS200:
+               /*
+                * Periodic re-tuning for HS400 is not expected to be needed, so
+                * disable it here.
+                */
+               if (hs400_tuning)
+                       tuning_count = 0;
+               break;
+
        case MMC_TIMING_UHS_SDR104:
                break;
 
@@ -1911,9 +1948,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                /* FALLTHROUGH */
 
        default:
-               spin_unlock_irqrestore(&host->lock, flags);
-               sdhci_runtime_pm_put(host);
-               return 0;
+               goto out_unlock;
        }
 
        if (host->ops->platform_execute_tuning) {
@@ -2037,24 +2072,11 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        }
 
 out:
-       /*
-        * If this is the very first time we are here, we start the retuning
-        * timer. Since only during the first time, SDHCI_NEEDS_RETUNING
-        * flag won't be set, we check this condition before actually starting
-        * the timer.
-        */
-       if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
-           (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
+       host->flags &= ~SDHCI_NEEDS_RETUNING;
+
+       if (tuning_count) {
                host->flags |= SDHCI_USING_RETUNING_TIMER;
-               mod_timer(&host->tuning_timer, jiffies +
-                       host->tuning_count * HZ);
-               /* Tuning mode 1 limits the maximum data length to 4MB */
-               mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
-       } else if (host->flags & SDHCI_USING_RETUNING_TIMER) {
-               host->flags &= ~SDHCI_NEEDS_RETUNING;
-               /* Reload the new initial value for timer */
-               mod_timer(&host->tuning_timer, jiffies +
-                         host->tuning_count * HZ);
+               mod_timer(&host->tuning_timer, jiffies + tuning_count * HZ);
        }
 
        /*
@@ -2070,6 +2092,7 @@ out:
 
        sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
        sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+out_unlock:
        spin_unlock_irqrestore(&host->lock, flags);
        sdhci_runtime_pm_put(host);
 
@@ -2110,15 +2133,18 @@ static void sdhci_card_event(struct mmc_host *mmc)
 {
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
+       int present;
 
        /* First check if client has provided their own card event */
        if (host->ops->card_event)
                host->ops->card_event(host);
 
+       present = sdhci_do_get_cd(host);
+
        spin_lock_irqsave(&host->lock, flags);
 
        /* Check host->mrq first in case we are runtime suspended */
-       if (host->mrq && !sdhci_do_get_cd(host)) {
+       if (host->mrq && !present) {
                pr_err("%s: Card removed during transfer!\n",
                        mmc_hostname(host->mmc));
                pr_err("%s: Resetting controller.\n",
@@ -2142,6 +2168,7 @@ static const struct mmc_host_ops sdhci_ops = {
        .hw_reset       = sdhci_hw_reset,
        .enable_sdio_irq = sdhci_enable_sdio_irq,
        .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
+       .prepare_hs400_tuning           = sdhci_prepare_hs400_tuning,
        .execute_tuning                 = sdhci_execute_tuning,
        .card_event                     = sdhci_card_event,
        .card_busy      = sdhci_card_busy,
@@ -3260,8 +3287,9 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->max_segs = SDHCI_MAX_SEGS;
 
        /*
-        * Maximum number of sectors in one transfer. Limited by DMA boundary
-        * size (512KiB).
+        * Maximum number of sectors in one transfer. Limited by SDMA boundary
+        * size (512KiB). Note some tuning modes impose a 4MiB limit, but this
+        * is less anyway.
         */
        mmc->max_req_size = 524288;
 
index 184c434ae3055e4b8a586c116d1274ddbccec6c5..0dceba1a2ba15f4706922a5423f680e7cd17ef77 100644 (file)
@@ -1648,7 +1648,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        /* slave is not a slave or master is not master of this slave */
        if (!(slave_dev->flags & IFF_SLAVE) ||
            !netdev_has_upper_dev(slave_dev, bond_dev)) {
-               netdev_err(bond_dev, "cannot release %s\n",
+               netdev_dbg(bond_dev, "cannot release %s\n",
                           slave_dev->name);
                return -EINVAL;
        }
index a5fefb9059c592aa5134302ba79f411a2874d65a..b306210b02b7b40c717ae160e4116db8926418ce 100644 (file)
@@ -257,7 +257,6 @@ static int cfv_rx_poll(struct napi_struct *napi, int quota)
        struct vringh_kiov *riov = &cfv->ctx.riov;
        unsigned int skb_len;
 
-again:
        do {
                skb = NULL;
 
@@ -322,7 +321,6 @@ exit:
                    napi_schedule_prep(napi)) {
                        vringh_notify_disable_kern(cfv->vr_rx);
                        __napi_schedule(napi);
-                       goto again;
                }
                break;
 
index f94a9fa60488ed8e23523f5f8c3665133f039dbb..c672c4dcffac14349d20d362dd5b199dd9bcd95c 100644 (file)
@@ -615,6 +615,9 @@ static void c_can_stop(struct net_device *dev)
 
        c_can_irq_control(priv, false);
 
+       /* put ctrl to init on stop to end ongoing transmission */
+       priv->write_reg(priv, C_CAN_CTRL_REG, CONTROL_INIT);
+
        /* deactivate pins */
        pinctrl_pm_select_sleep_state(dev->dev.parent);
        priv->can.state = CAN_STATE_STOPPED;
index f363972cd77d9a5a44267811a5db48c8d40ed397..e36d10520e248cd2b4d67bee15b1876cccf994d3 100644 (file)
@@ -103,27 +103,34 @@ static void c_can_hw_raminit_syscon(const struct c_can_priv *priv, bool enable)
        mask = 1 << raminit->bits.start | 1 << raminit->bits.done;
        regmap_read(raminit->syscon, raminit->reg, &ctrl);
 
-       /* We clear the done and start bit first. The start bit is
+       /* We clear the start bit first. The start bit is
         * looking at the 0 -> transition, but is not self clearing;
-        * And we clear the init done bit as well.
         * NOTE: DONE must be written with 1 to clear it.
+        * We can't clear the DONE bit here using regmap_update_bits()
+        * as it will bypass the write if initial condition is START:0 DONE:1
+        * e.g. on DRA7 which needs START pulse.
         */
-       ctrl &= ~(1 << raminit->bits.start);
-       ctrl |= 1 << raminit->bits.done;
-       regmap_write(raminit->syscon, raminit->reg, ctrl);
+       ctrl &= ~mask;  /* START = 0, DONE = 0 */
+       regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl);
 
-       ctrl &= ~(1 << raminit->bits.done);
-       c_can_hw_raminit_wait_syscon(priv, mask, ctrl);
+       /* check if START bit is 0. Ignore DONE bit for now
+        * as it can be either 0 or 1.
+        */
+       c_can_hw_raminit_wait_syscon(priv, 1 << raminit->bits.start, ctrl);
 
        if (enable) {
-               /* Set start bit and wait for the done bit. */
+               /* Clear DONE bit & set START bit. */
                ctrl |= 1 << raminit->bits.start;
-               regmap_write(raminit->syscon, raminit->reg, ctrl);
-
+               /* DONE must be written with 1 to clear it */
+               ctrl |= 1 << raminit->bits.done;
+               regmap_update_bits(raminit->syscon, raminit->reg, mask, ctrl);
+               /* prevent further clearing of DONE bit */
+               ctrl &= ~(1 << raminit->bits.done);
                /* clear START bit if start pulse is needed */
                if (raminit->needs_pulse) {
                        ctrl &= ~(1 << raminit->bits.start);
-                       regmap_write(raminit->syscon, raminit->reg, ctrl);
+                       regmap_update_bits(raminit->syscon, raminit->reg,
+                                          mask, ctrl);
                }
 
                ctrl |= 1 << raminit->bits.done;
index 3ec8f6f25e5f979e16838930295fe4cd66b2841c..847c1f813261d92a9188983141a79e2fddfcb3e7 100644 (file)
@@ -807,10 +807,14 @@ static int can_changelink(struct net_device *dev,
                if (dev->flags & IFF_UP)
                        return -EBUSY;
                cm = nla_data(data[IFLA_CAN_CTRLMODE]);
-               if (cm->flags & ~priv->ctrlmode_supported)
+
+               /* check whether changed bits are allowed to be modified */
+               if (cm->mask & ~priv->ctrlmode_supported)
                        return -EOPNOTSUPP;
+
+               /* clear bits to be modified and copy the flag values */
                priv->ctrlmode &= ~cm->mask;
-               priv->ctrlmode |= cm->flags;
+               priv->ctrlmode |= (cm->flags & cm->mask);
 
                /* CAN_CTRLMODE_FD can only be set when driver supports FD */
                if (priv->ctrlmode & CAN_CTRLMODE_FD)
index d7bc462aafdc27a26774aa6cb6cadb0e0d8547a3..244529881be9d919850df2c522ffb95e616c1e6d 100644 (file)
@@ -955,6 +955,11 @@ static struct net_device *alloc_m_can_dev(void)
        priv->can.data_bittiming_const = &m_can_data_bittiming_const;
        priv->can.do_set_mode = m_can_set_mode;
        priv->can.do_get_berr_counter = m_can_get_berr_counter;
+
+       /* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.1 */
+       priv->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
+
+       /* CAN_CTRLMODE_FD_NON_ISO can not be changed with M_CAN IP v3.0.1 */
        priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
                                        CAN_CTRLMODE_LISTENONLY |
                                        CAN_CTRLMODE_BERR_REPORTING |
index 541fb7a05625aaf889089704ec155956629e77c8..7af379ca861b11a1631764071bb31c8a8d4b8916 100644 (file)
@@ -520,10 +520,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
                skb = alloc_can_err_skb(priv->netdev, &cf);
                if (skb) {
                        cf->can_id |= CAN_ERR_RESTARTED;
-                       netif_rx(skb);
 
                        stats->rx_packets++;
                        stats->rx_bytes += cf->can_dlc;
+                       netif_rx(skb);
                } else {
                        netdev_err(priv->netdev,
                                   "No memory left for err_skb\n");
@@ -587,7 +587,7 @@ static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
                          usb_sndbulkpipe(dev->udev,
                                          dev->bulk_out->bEndpointAddress),
                          buf, msg->len,
-                         kvaser_usb_simple_msg_callback, priv);
+                         kvaser_usb_simple_msg_callback, netdev);
        usb_anchor_urb(urb, &priv->tx_submitted);
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
@@ -662,11 +662,6 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
        priv = dev->nets[channel];
        stats = &priv->netdev->stats;
 
-       if (status & M16C_STATE_BUS_RESET) {
-               kvaser_usb_unlink_tx_urbs(priv);
-               return;
-       }
-
        skb = alloc_can_err_skb(priv->netdev, &cf);
        if (!skb) {
                stats->rx_dropped++;
@@ -677,7 +672,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
        netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
 
-       if (status & M16C_STATE_BUS_OFF) {
+       if (status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) {
                cf->can_id |= CAN_ERR_BUSOFF;
 
                priv->can.can_stats.bus_off++;
@@ -703,9 +698,7 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
                }
 
                new_state = CAN_STATE_ERROR_PASSIVE;
-       }
-
-       if (status == M16C_STATE_BUS_ERROR) {
+       } else if (status & M16C_STATE_BUS_ERROR) {
                if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
                    ((txerr >= 96) || (rxerr >= 96))) {
                        cf->can_id |= CAN_ERR_CRTL;
@@ -715,7 +708,8 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
                        priv->can.can_stats.error_warning++;
                        new_state = CAN_STATE_ERROR_WARNING;
-               } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) {
+               } else if ((priv->can.state > CAN_STATE_ERROR_ACTIVE) &&
+                          ((txerr < 96) && (rxerr < 96))) {
                        cf->can_id |= CAN_ERR_PROT;
                        cf->data[2] = CAN_ERR_PROT_ACTIVE;
 
@@ -770,10 +764,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
 
        priv->can.state = new_state;
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -805,10 +798,9 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
                stats->rx_over_errors++;
                stats->rx_errors++;
 
-               netif_rx(skb);
-
                stats->rx_packets++;
                stats->rx_bytes += cf->can_dlc;
+               netif_rx(skb);
        }
 }
 
@@ -887,10 +879,9 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
                               cf->can_dlc);
        }
 
-       netif_rx(skb);
-
        stats->rx_packets++;
        stats->rx_bytes += cf->can_dlc;
+       netif_rx(skb);
 }
 
 static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
@@ -1246,6 +1237,9 @@ static int kvaser_usb_close(struct net_device *netdev)
        if (err)
                netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
+       /* reset tx contexts */
+       kvaser_usb_unlink_tx_urbs(priv);
+
        priv->can.state = CAN_STATE_STOPPED;
        close_candev(priv->netdev);
 
@@ -1294,12 +1288,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (!urb) {
                netdev_err(netdev, "No memory left for URBs\n");
                stats->tx_dropped++;
-               goto nourbmem;
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
        }
 
        buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
        if (!buf) {
                stats->tx_dropped++;
+               dev_kfree_skb(skb);
                goto nobufmem;
        }
 
@@ -1334,6 +1330,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                }
        }
 
+       /* This should never happen; it implies a flow control bug */
        if (!context) {
                netdev_warn(netdev, "cannot find free context\n");
                ret =  NETDEV_TX_BUSY;
@@ -1364,9 +1361,6 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
        if (unlikely(err)) {
                can_free_echo_skb(netdev, context->echo_index);
 
-               skb = NULL; /* set to NULL to avoid double free in
-                            * dev_kfree_skb(skb) */
-
                atomic_dec(&priv->active_tx_urbs);
                usb_unanchor_urb(urb);
 
@@ -1388,8 +1382,6 @@ releasebuf:
        kfree(buf);
 nobufmem:
        usb_free_urb(urb);
-nourbmem:
-       dev_kfree_skb(skb);
        return ret;
 }
 
@@ -1502,6 +1494,10 @@ static int kvaser_usb_init_one(struct usb_interface *intf,
        struct kvaser_usb_net_priv *priv;
        int i, err;
 
+       err = kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, channel);
+       if (err)
+               return err;
+
        netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
        if (!netdev) {
                dev_err(&intf->dev, "Cannot alloc candev\n");
@@ -1588,7 +1584,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 {
        struct kvaser_usb *dev;
        int err = -ENOMEM;
-       int i;
+       int i, retry = 3;
 
        dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -1606,10 +1602,15 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        usb_set_intfdata(intf, dev);
 
-       for (i = 0; i < MAX_NET_DEVICES; i++)
-               kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
+       /* On some x86 laptops, plugging a Kvaser device again after
+        * an unplug makes the firmware always ignore the very first
+        * command. For such a case, provide some room for retries
+        * instead of completely exiting the driver.
+        */
+       do {
+               err = kvaser_usb_get_software_info(dev);
+       } while (--retry && err == -ETIMEDOUT);
 
-       err = kvaser_usb_get_software_info(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Cannot get software infos, error %d\n", err);
index 89c8d9fc97de9cbc85611de9b9f032b1641d41e7..57e97910c72811ac9e5c24428cd3e3500dd089dd 100644 (file)
@@ -246,13 +246,13 @@ static int ne2k_pci_init_one(struct pci_dev *pdev,
 
        if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
                dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
-               return -ENODEV;
+               goto err_out;
        }
 
        if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
                dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
                        NE_IO_EXTENT, ioaddr);
-               return -EBUSY;
+               goto err_out;
        }
 
        reg0 = inb(ioaddr);
@@ -392,6 +392,8 @@ err_out_free_netdev:
        free_netdev (dev);
 err_out_free_res:
        release_region (ioaddr, NE_IO_EXTENT);
+err_out:
+       pci_disable_device(pdev);
        return -ENODEV;
 }
 
index df76050d0a9d26dc5a5b106a0ac44a18d84441b9..eadcb053807e46e8ae1f5c8ebce984abf0166219 100644 (file)
@@ -156,18 +156,6 @@ source "drivers/net/ethernet/realtek/Kconfig"
 source "drivers/net/ethernet/renesas/Kconfig"
 source "drivers/net/ethernet/rdc/Kconfig"
 source "drivers/net/ethernet/rocker/Kconfig"
-
-config S6GMAC
-       tristate "S6105 GMAC ethernet support"
-       depends on XTENSA_VARIANT_S6000
-       select PHYLIB
-       ---help---
-         This driver supports the on chip ethernet device on the
-         S6105 xtensa processor.
-
-         To compile this driver as a module, choose M here. The module
-         will be called s6gmac.
-
 source "drivers/net/ethernet/samsung/Kconfig"
 source "drivers/net/ethernet/seeq/Kconfig"
 source "drivers/net/ethernet/silan/Kconfig"
index bf56f8b36e90cbb2fcef22627fadff0041fef897..1367afcd0a8b2cd29681fc1867e7f0af71889fe0 100644 (file)
@@ -66,7 +66,6 @@ obj-$(CONFIG_NET_VENDOR_REALTEK) += realtek/
 obj-$(CONFIG_SH_ETH) += renesas/
 obj-$(CONFIG_NET_VENDOR_RDC) += rdc/
 obj-$(CONFIG_NET_VENDOR_ROCKER) += rocker/
-obj-$(CONFIG_S6GMAC) += s6gmac.o
 obj-$(CONFIG_NET_VENDOR_SAMSUNG) += samsung/
 obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/
 obj-$(CONFIG_NET_VENDOR_SILAN) += silan/
index 1fcd5568a3520981fd6ac03b57a3a599c2876a6c..f3470d96837a7fb0e59307b000855fe18a882af5 100644 (file)
@@ -850,8 +850,10 @@ static int emac_probe(struct platform_device *pdev)
        }
 
        db->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(db->clk))
+       if (IS_ERR(db->clk)) {
+               ret = PTR_ERR(db->clk);
                goto out;
+       }
 
        clk_prepare_enable(db->clk);
 
index 3498760dc22a96c17419abbda9250cc959165a39..760c72c6e2acd50ba8472e4b4dd77170c2c381d6 100644 (file)
@@ -1170,10 +1170,6 @@ tx_request_irq_error:
 init_error:
        free_skbufs(dev);
 alloc_skbuf_error:
-       if (priv->phydev) {
-               phy_disconnect(priv->phydev);
-               priv->phydev = NULL;
-       }
 phy_error:
        return ret;
 }
@@ -1186,12 +1182,9 @@ static int tse_shutdown(struct net_device *dev)
        int ret;
        unsigned long int flags;
 
-       /* Stop and disconnect the PHY */
-       if (priv->phydev) {
+       /* Stop the PHY */
+       if (priv->phydev)
                phy_stop(priv->phydev);
-               phy_disconnect(priv->phydev);
-               priv->phydev = NULL;
-       }
 
        netif_stop_queue(dev);
        napi_disable(&priv->napi);
@@ -1525,6 +1518,10 @@ err_free_netdev:
 static int altera_tse_remove(struct platform_device *pdev)
 {
        struct net_device *ndev = platform_get_drvdata(pdev);
+       struct altera_tse_private *priv = netdev_priv(ndev);
+
+       if (priv->phydev)
+               phy_disconnect(priv->phydev);
 
        platform_set_drvdata(pdev, NULL);
        altera_tse_mdio_destroy(ndev);
index 75b08c63d39f4a469a389c0327e1f3071932596f..29a09271b64a39b71a46ac1d5beb5a6472160509 100644 (file)
 #define MTL_Q_RQOMR                    0x40
 #define MTL_Q_RQMPOCR                  0x44
 #define MTL_Q_RQDR                     0x4c
+#define MTL_Q_RQFCR                    0x50
 #define MTL_Q_IER                      0x70
 #define MTL_Q_ISR                      0x74
 
 /* MTL queue register entry bit positions and sizes */
+#define MTL_Q_RQFCR_RFA_INDEX          1
+#define MTL_Q_RQFCR_RFA_WIDTH          6
+#define MTL_Q_RQFCR_RFD_INDEX          17
+#define MTL_Q_RQFCR_RFD_WIDTH          6
 #define MTL_Q_RQOMR_EHFC_INDEX         7
 #define MTL_Q_RQOMR_EHFC_WIDTH         1
-#define MTL_Q_RQOMR_RFA_INDEX          8
-#define MTL_Q_RQOMR_RFA_WIDTH          3
-#define MTL_Q_RQOMR_RFD_INDEX          13
-#define MTL_Q_RQOMR_RFD_WIDTH          3
 #define MTL_Q_RQOMR_RQS_INDEX          16
 #define MTL_Q_RQOMR_RQS_WIDTH          9
 #define MTL_Q_RQOMR_RSF_INDEX          5
index 53f5f66ec2ee43fe5533697860f70d49a458b919..4c66cd1d1e604f19a36e65fc88b6392ecfa66d3b 100644 (file)
@@ -2079,10 +2079,10 @@ static void xgbe_config_flow_control_threshold(struct xgbe_prv_data *pdata)
 
        for (i = 0; i < pdata->rx_q_count; i++) {
                /* Activate flow control when less than 4k left in fifo */
-               XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFA, 2);
+               XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQFCR, RFA, 2);
 
                /* De-activate flow control when more than 6k left in fifo */
-               XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQOMR, RFD, 4);
+               XGMAC_MTL_IOWRITE_BITS(pdata, i, MTL_Q_RQFCR, RFD, 4);
        }
 }
 
index e398eda0729832671561490c6d18fce9db485f5e..c8af3ce3ea38d16d4c470ec5773b2d4f088b0f15 100644 (file)
@@ -184,15 +184,16 @@ static void alx_schedule_reset(struct alx_priv *alx)
        schedule_work(&alx->reset_wk);
 }
 
-static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
+static int alx_clean_rx_irq(struct alx_priv *alx, int budget)
 {
        struct alx_rx_queue *rxq = &alx->rxq;
        struct alx_rrd *rrd;
        struct alx_buffer *rxb;
        struct sk_buff *skb;
        u16 length, rfd_cleaned = 0;
+       int work = 0;
 
-       while (budget > 0) {
+       while (work < budget) {
                rrd = &rxq->rrd[rxq->rrd_read_idx];
                if (!(rrd->word3 & cpu_to_le32(1 << RRD_UPDATED_SHIFT)))
                        break;
@@ -203,7 +204,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
                    ALX_GET_FIELD(le32_to_cpu(rrd->word0),
                                  RRD_NOR) != 1) {
                        alx_schedule_reset(alx);
-                       return 0;
+                       return work;
                }
 
                rxb = &rxq->bufs[rxq->read_idx];
@@ -243,7 +244,7 @@ static bool alx_clean_rx_irq(struct alx_priv *alx, int budget)
                }
 
                napi_gro_receive(&alx->napi, skb);
-               budget--;
+               work++;
 
 next_pkt:
                if (++rxq->read_idx == alx->rx_ringsz)
@@ -258,21 +259,22 @@ next_pkt:
        if (rfd_cleaned)
                alx_refill_rx_ring(alx, GFP_ATOMIC);
 
-       return budget > 0;
+       return work;
 }
 
 static int alx_poll(struct napi_struct *napi, int budget)
 {
        struct alx_priv *alx = container_of(napi, struct alx_priv, napi);
        struct alx_hw *hw = &alx->hw;
-       bool complete = true;
        unsigned long flags;
+       bool tx_complete;
+       int work;
 
-       complete = alx_clean_tx_irq(alx) &&
-                  alx_clean_rx_irq(alx, budget);
+       tx_complete = alx_clean_tx_irq(alx);
+       work = alx_clean_rx_irq(alx, budget);
 
-       if (!complete)
-               return 1;
+       if (!tx_complete || work == budget)
+               return budget;
 
        napi_complete(&alx->napi);
 
@@ -284,7 +286,7 @@ static int alx_poll(struct napi_struct *napi, int budget)
 
        alx_post_write(hw);
 
-       return 0;
+       return work;
 }
 
 static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
index 05c6af6c418fa45690d085885b0cca330b58c210..3007d95fbb9f69c460a83d57bc66c7488421a627 100644 (file)
@@ -1167,10 +1167,10 @@ static int bgmac_poll(struct napi_struct *napi, int weight)
                bgmac->int_status = 0;
        }
 
-       if (handled < weight)
+       if (handled < weight) {
                napi_complete(napi);
-
-       bgmac_chip_intrs_on(bgmac);
+               bgmac_chip_intrs_on(bgmac);
+       }
 
        return handled;
 }
@@ -1515,6 +1515,8 @@ static int bgmac_probe(struct bcma_device *core)
        if (core->bus->sprom.boardflags_lo & BGMAC_BFL_ENETADM)
                bgmac_warn(bgmac, "Support for ADMtek ethernet switch not implemented\n");
 
+       netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
+
        err = bgmac_mii_register(bgmac);
        if (err) {
                bgmac_err(bgmac, "Cannot register MDIO\n");
@@ -1529,8 +1531,6 @@ static int bgmac_probe(struct bcma_device *core)
 
        netif_carrier_off(net_dev);
 
-       netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT);
-
        return 0;
 
 err_mii_unregister:
@@ -1549,9 +1549,9 @@ static void bgmac_remove(struct bcma_device *core)
 {
        struct bgmac *bgmac = bcma_get_drvdata(core);
 
-       netif_napi_del(&bgmac->napi);
        unregister_netdev(bgmac->net_dev);
        bgmac_mii_unregister(bgmac);
+       netif_napi_del(&bgmac->napi);
        bgmac_dma_free(bgmac);
        bcma_set_drvdata(core, NULL);
        free_netdev(bgmac->net_dev);
index 1d1147c93d5972147a9aa17650eeaadb0dda7066..e468ed3f210f8e1a121b3a47d6d7da1168063592 100644 (file)
@@ -3175,7 +3175,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget)
                }
 #endif
                if (!bnx2x_fp_lock_napi(fp))
-                       return work_done;
+                       return budget;
 
                for_each_cos_in_tx_queue(fp, cos)
                        if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos]))
index 9f5e38769a294a3d66d9562e12e2e0116bac925e..72eef9fc883e8983d7544abd685fbb36da19951d 100644 (file)
@@ -12553,9 +12553,11 @@ static int bnx2x_get_phys_port_id(struct net_device *netdev,
        return 0;
 }
 
-static bool bnx2x_gso_check(struct sk_buff *skb, struct net_device *dev)
+static netdev_features_t bnx2x_features_check(struct sk_buff *skb,
+                                             struct net_device *dev,
+                                             netdev_features_t features)
 {
-       return vxlan_gso_check(skb);
+       return vxlan_features_check(skb, features);
 }
 
 static const struct net_device_ops bnx2x_netdev_ops = {
@@ -12589,7 +12591,7 @@ static const struct net_device_ops bnx2x_netdev_ops = {
 #endif
        .ndo_get_phys_port_id   = bnx2x_get_phys_port_id,
        .ndo_set_vf_link_state  = bnx2x_set_vf_link_state,
-       .ndo_gso_check          = bnx2x_gso_check,
+       .ndo_features_check     = bnx2x_features_check,
 };
 
 static int bnx2x_set_coherency_mask(struct bnx2x *bp)
index bb48a610b72a8db6beb501e990c5d4f1365c9495..96bf01ba32dda179b15d2c36d6168581ee43c250 100644 (file)
@@ -7413,6 +7413,8 @@ static inline void tg3_netif_start(struct tg3 *tp)
 }
 
 static void tg3_irq_quiesce(struct tg3 *tp)
+       __releases(tp->lock)
+       __acquires(tp->lock)
 {
        int i;
 
@@ -7421,8 +7423,12 @@ static void tg3_irq_quiesce(struct tg3 *tp)
        tp->irq_sync = 1;
        smp_mb();
 
+       spin_unlock_bh(&tp->lock);
+
        for (i = 0; i < tp->irq_cnt; i++)
                synchronize_irq(tp->napi[i].irq_vec);
+
+       spin_lock_bh(&tp->lock);
 }
 
 /* Fully shutdown all tg3 driver activity elsewhere in the system.
@@ -9018,6 +9024,8 @@ static void tg3_restore_clk(struct tg3 *tp)
 
 /* tp->lock is held. */
 static int tg3_chip_reset(struct tg3 *tp)
+       __releases(tp->lock)
+       __acquires(tp->lock)
 {
        u32 val;
        void (*write_op)(struct tg3 *, u32, u32);
@@ -9073,9 +9081,13 @@ static int tg3_chip_reset(struct tg3 *tp)
        }
        smp_mb();
 
+       tg3_full_unlock(tp);
+
        for (i = 0; i < tp->irq_cnt; i++)
                synchronize_irq(tp->napi[i].irq_vec);
 
+       tg3_full_lock(tp, 0);
+
        if (tg3_asic_rev(tp) == ASIC_REV_57780) {
                val = tr32(TG3_PCIE_LNKCTL) & ~TG3_PCIE_LNKCTL_L1_PLL_PD_EN;
                tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
@@ -10903,11 +10915,13 @@ static void tg3_timer(unsigned long __opaque)
 {
        struct tg3 *tp = (struct tg3 *) __opaque;
 
-       if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING))
-               goto restart_timer;
-
        spin_lock(&tp->lock);
 
+       if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING)) {
+               spin_unlock(&tp->lock);
+               goto restart_timer;
+       }
+
        if (tg3_asic_rev(tp) == ASIC_REV_5717 ||
            tg3_flag(tp, 57765_CLASS))
                tg3_chk_missed_msi(tp);
@@ -11101,11 +11115,13 @@ static void tg3_reset_task(struct work_struct *work)
        struct tg3 *tp = container_of(work, struct tg3, reset_task);
        int err;
 
+       rtnl_lock();
        tg3_full_lock(tp, 0);
 
        if (!netif_running(tp->dev)) {
                tg3_flag_clear(tp, RESET_TASK_PENDING);
                tg3_full_unlock(tp);
+               rtnl_unlock();
                return;
        }
 
@@ -11138,6 +11154,7 @@ out:
                tg3_phy_start(tp);
 
        tg3_flag_clear(tp, RESET_TASK_PENDING);
+       rtnl_unlock();
 }
 
 static int tg3_request_irq(struct tg3 *tp, int irq_num)
@@ -17800,23 +17817,6 @@ static int tg3_init_one(struct pci_dev *pdev,
                goto err_out_apeunmap;
        }
 
-       /*
-        * Reset chip in case UNDI or EFI driver did not shutdown
-        * DMA self test will enable WDMAC and we'll see (spurious)
-        * pending DMA on the PCI bus at that point.
-        */
-       if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
-           (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-               tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
-               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
-       }
-
-       err = tg3_test_dma(tp);
-       if (err) {
-               dev_err(&pdev->dev, "DMA engine test failed, aborting\n");
-               goto err_out_apeunmap;
-       }
-
        intmbx = MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW;
        rcvmbx = MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW;
        sndmbx = MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW;
@@ -17861,6 +17861,23 @@ static int tg3_init_one(struct pci_dev *pdev,
                        sndmbx += 0xc;
        }
 
+       /*
+        * Reset chip in case UNDI or EFI driver did not shutdown
+        * DMA self test will enable WDMAC and we'll see (spurious)
+        * pending DMA on the PCI bus at that point.
+        */
+       if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
+           (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+               tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+               tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+       }
+
+       err = tg3_test_dma(tp);
+       if (err) {
+               dev_err(&pdev->dev, "DMA engine test failed, aborting\n");
+               goto err_out_apeunmap;
+       }
+
        tg3_init_coal(tp);
 
        pci_set_drvdata(pdev, dev);
index 7d6aa8c87df84747bea056019a89517846817b21..619083a860a4b4bfc64518619202aa515c415b71 100644 (file)
@@ -172,7 +172,7 @@ bnad_get_debug_drvinfo(struct bnad *bnad, void *buffer, u32 len)
 
        /* Retrieve flash partition info */
        fcomp.comp_status = 0;
-       init_completion(&fcomp.comp);
+       reinit_completion(&fcomp.comp);
        spin_lock_irqsave(&bnad->bna_lock, flags);
        ret = bfa_nw_flash_get_attr(&bnad->bna.flash, &drvinfo->flash_attr,
                                bnad_cb_completion, &fcomp);
index 55eb7f2af2b41ccf031f5018c12137daf752dc6c..7ef55f5fa664480ce052720bc55bd5ffb9ca8b57 100644 (file)
@@ -340,7 +340,7 @@ static int __init at91ether_probe(struct platform_device *pdev)
                res = PTR_ERR(lp->pclk);
                goto err_free_dev;
        }
-       clk_enable(lp->pclk);
+       clk_prepare_enable(lp->pclk);
 
        lp->hclk = ERR_PTR(-ENOENT);
        lp->tx_clk = ERR_PTR(-ENOENT);
@@ -406,7 +406,7 @@ static int __init at91ether_probe(struct platform_device *pdev)
 err_out_unregister_netdev:
        unregister_netdev(dev);
 err_disable_clock:
-       clk_disable(lp->pclk);
+       clk_disable_unprepare(lp->pclk);
 err_free_dev:
        free_netdev(dev);
        return res;
@@ -424,7 +424,7 @@ static int at91ether_remove(struct platform_device *pdev)
        kfree(lp->mii_bus->irq);
        mdiobus_free(lp->mii_bus);
        unregister_netdev(dev);
-       clk_disable(lp->pclk);
+       clk_disable_unprepare(lp->pclk);
        free_netdev(dev);
 
        return 0;
@@ -440,7 +440,7 @@ static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
                netif_stop_queue(net_dev);
                netif_device_detach(net_dev);
 
-               clk_disable(lp->pclk);
+               clk_disable_unprepare(lp->pclk);
        }
        return 0;
 }
@@ -451,7 +451,7 @@ static int at91ether_resume(struct platform_device *pdev)
        struct macb *lp = netdev_priv(net_dev);
 
        if (netif_running(net_dev)) {
-               clk_enable(lp->pclk);
+               clk_prepare_enable(lp->pclk);
 
                netif_device_attach(net_dev);
                netif_start_queue(net_dev);
index d00a751f0588d8c65d6060352af578895e5d9f6d..6049f70e110c5701d0a6cb8685b3dbf2a78ab38d 100644 (file)
@@ -96,6 +96,9 @@ struct port_info {
        s16 xact_addr_filt;             /* index of our MAC address filter */
        u16 rss_size;                   /* size of VI's RSS table slice */
        u8 pidx;                        /* index into adapter port[] */
+       s8 mdio_addr;
+       u8 port_type;                   /* firmware port type */
+       u8 mod_type;                    /* firmware module type */
        u8 port_id;                     /* physical port ID */
        u8 nqsets;                      /* # of "Queue Sets" */
        u8 first_qset;                  /* index of first "Queue Set" */
@@ -522,6 +525,7 @@ static inline struct adapter *netdev2adap(const struct net_device *dev)
  * is "contracted" to provide for the common code.
  */
 void t4vf_os_link_changed(struct adapter *, int, int);
+void t4vf_os_portmod_changed(struct adapter *, int);
 
 /*
  * SGE function prototype declarations.
index aa74ec34a4679cbff1905e2af7da5bfcdf71999f..a936ee8958c704fa90321a1934b2c7dacbf046a6 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/etherdevice.h>
 #include <linux/debugfs.h>
 #include <linux/ethtool.h>
+#include <linux/mdio.h>
 
 #include "t4vf_common.h"
 #include "t4vf_defs.h"
@@ -209,6 +210,38 @@ void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
        }
 }
 
+/*
+ * THe port module type has changed on the indicated "port" (Virtual
+ * Interface).
+ */
+void t4vf_os_portmod_changed(struct adapter *adapter, int pidx)
+{
+       static const char * const mod_str[] = {
+               NULL, "LR", "SR", "ER", "passive DA", "active DA", "LRM"
+       };
+       const struct net_device *dev = adapter->port[pidx];
+       const struct port_info *pi = netdev_priv(dev);
+
+       if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
+               dev_info(adapter->pdev_dev, "%s: port module unplugged\n",
+                        dev->name);
+       else if (pi->mod_type < ARRAY_SIZE(mod_str))
+               dev_info(adapter->pdev_dev, "%s: %s port module inserted\n",
+                        dev->name, mod_str[pi->mod_type]);
+       else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
+               dev_info(adapter->pdev_dev, "%s: unsupported optical port "
+                        "module inserted\n", dev->name);
+       else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
+               dev_info(adapter->pdev_dev, "%s: unknown port module inserted,"
+                        "forcing TWINAX\n", dev->name);
+       else if (pi->mod_type == FW_PORT_MOD_TYPE_ERROR)
+               dev_info(adapter->pdev_dev, "%s: transceiver module error\n",
+                        dev->name);
+       else
+               dev_info(adapter->pdev_dev, "%s: unknown module type %d "
+                        "inserted\n", dev->name, pi->mod_type);
+}
+
 /*
  * Net device operations.
  * ======================
@@ -1193,24 +1226,103 @@ static void cxgb4vf_poll_controller(struct net_device *dev)
  * state of the port to which we're linked.
  */
 
-/*
- * Return current port link settings.
- */
-static int cxgb4vf_get_settings(struct net_device *dev,
-                               struct ethtool_cmd *cmd)
-{
-       const struct port_info *pi = netdev_priv(dev);
+static unsigned int t4vf_from_fw_linkcaps(enum fw_port_type type,
+                                         unsigned int caps)
+{
+       unsigned int v = 0;
+
+       if (type == FW_PORT_TYPE_BT_SGMII || type == FW_PORT_TYPE_BT_XFI ||
+           type == FW_PORT_TYPE_BT_XAUI) {
+               v |= SUPPORTED_TP;
+               if (caps & FW_PORT_CAP_SPEED_100M)
+                       v |= SUPPORTED_100baseT_Full;
+               if (caps & FW_PORT_CAP_SPEED_1G)
+                       v |= SUPPORTED_1000baseT_Full;
+               if (caps & FW_PORT_CAP_SPEED_10G)
+                       v |= SUPPORTED_10000baseT_Full;
+       } else if (type == FW_PORT_TYPE_KX4 || type == FW_PORT_TYPE_KX) {
+               v |= SUPPORTED_Backplane;
+               if (caps & FW_PORT_CAP_SPEED_1G)
+                       v |= SUPPORTED_1000baseKX_Full;
+               if (caps & FW_PORT_CAP_SPEED_10G)
+                       v |= SUPPORTED_10000baseKX4_Full;
+       } else if (type == FW_PORT_TYPE_KR)
+               v |= SUPPORTED_Backplane | SUPPORTED_10000baseKR_Full;
+       else if (type == FW_PORT_TYPE_BP_AP)
+               v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC |
+                    SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full;
+       else if (type == FW_PORT_TYPE_BP4_AP)
+               v |= SUPPORTED_Backplane | SUPPORTED_10000baseR_FEC |
+                    SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full |
+                    SUPPORTED_10000baseKX4_Full;
+       else if (type == FW_PORT_TYPE_FIBER_XFI ||
+                type == FW_PORT_TYPE_FIBER_XAUI ||
+                type == FW_PORT_TYPE_SFP ||
+                type == FW_PORT_TYPE_QSFP_10G ||
+                type == FW_PORT_TYPE_QSA) {
+               v |= SUPPORTED_FIBRE;
+               if (caps & FW_PORT_CAP_SPEED_1G)
+                       v |= SUPPORTED_1000baseT_Full;
+               if (caps & FW_PORT_CAP_SPEED_10G)
+                       v |= SUPPORTED_10000baseT_Full;
+       } else if (type == FW_PORT_TYPE_BP40_BA ||
+                  type == FW_PORT_TYPE_QSFP) {
+               v |= SUPPORTED_40000baseSR4_Full;
+               v |= SUPPORTED_FIBRE;
+       }
+
+       if (caps & FW_PORT_CAP_ANEG)
+               v |= SUPPORTED_Autoneg;
+       return v;
+}
+
+static int cxgb4vf_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       const struct port_info *p = netdev_priv(dev);
+
+       if (p->port_type == FW_PORT_TYPE_BT_SGMII ||
+           p->port_type == FW_PORT_TYPE_BT_XFI ||
+           p->port_type == FW_PORT_TYPE_BT_XAUI)
+               cmd->port = PORT_TP;
+       else if (p->port_type == FW_PORT_TYPE_FIBER_XFI ||
+                p->port_type == FW_PORT_TYPE_FIBER_XAUI)
+               cmd->port = PORT_FIBRE;
+       else if (p->port_type == FW_PORT_TYPE_SFP ||
+                p->port_type == FW_PORT_TYPE_QSFP_10G ||
+                p->port_type == FW_PORT_TYPE_QSA ||
+                p->port_type == FW_PORT_TYPE_QSFP) {
+               if (p->mod_type == FW_PORT_MOD_TYPE_LR ||
+                   p->mod_type == FW_PORT_MOD_TYPE_SR ||
+                   p->mod_type == FW_PORT_MOD_TYPE_ER ||
+                   p->mod_type == FW_PORT_MOD_TYPE_LRM)
+                       cmd->port = PORT_FIBRE;
+               else if (p->mod_type == FW_PORT_MOD_TYPE_TWINAX_PASSIVE ||
+                        p->mod_type == FW_PORT_MOD_TYPE_TWINAX_ACTIVE)
+                       cmd->port = PORT_DA;
+               else
+                       cmd->port = PORT_OTHER;
+       } else
+               cmd->port = PORT_OTHER;
 
-       cmd->supported = pi->link_cfg.supported;
-       cmd->advertising = pi->link_cfg.advertising;
+       if (p->mdio_addr >= 0) {
+               cmd->phy_address = p->mdio_addr;
+               cmd->transceiver = XCVR_EXTERNAL;
+               cmd->mdio_support = p->port_type == FW_PORT_TYPE_BT_SGMII ?
+                       MDIO_SUPPORTS_C22 : MDIO_SUPPORTS_C45;
+       } else {
+               cmd->phy_address = 0;  /* not really, but no better option */
+               cmd->transceiver = XCVR_INTERNAL;
+               cmd->mdio_support = 0;
+       }
+
+       cmd->supported = t4vf_from_fw_linkcaps(p->port_type,
+                                              p->link_cfg.supported);
+       cmd->advertising = t4vf_from_fw_linkcaps(p->port_type,
+                                           p->link_cfg.advertising);
        ethtool_cmd_speed_set(cmd,
-                             netif_carrier_ok(dev) ? pi->link_cfg.speed : -1);
+                             netif_carrier_ok(dev) ? p->link_cfg.speed : 0);
        cmd->duplex = DUPLEX_FULL;
-
-       cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
-       cmd->phy_address = pi->port_id;
-       cmd->transceiver = XCVR_EXTERNAL;
-       cmd->autoneg = pi->link_cfg.autoneg;
+       cmd->autoneg = p->link_cfg.autoneg;
        cmd->maxtxpkt = 0;
        cmd->maxrxpkt = 0;
        return 0;
@@ -2318,7 +2430,7 @@ static void cfg_queues(struct adapter *adapter)
         */
        n10g = 0;
        for_each_port(adapter, pidx)
-               n10g += is_10g_port(&adap2pinfo(adapter, pidx)->link_cfg);
+               n10g += is_x_10g_port(&adap2pinfo(adapter, pidx)->link_cfg);
 
        /*
         * We default to 1 queue per non-10G port and up to # of cores queues
index 8d3237f5e36493aca04ba2fdb952ef4a148fee9c..b9debb4f29a355a54b6304ea39fa717a3b33cc14 100644 (file)
@@ -230,7 +230,7 @@ struct adapter_params {
 
 static inline bool is_10g_port(const struct link_config *lc)
 {
-       return (lc->supported & SUPPORTED_10000baseT_Full) != 0;
+       return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0;
 }
 
 static inline bool is_x_10g_port(const struct link_config *lc)
index 02e8833b7797af63e3c1d43f0ac5ce75450e3c76..60426cf890a774dd07ec939a622f88991c1044f6 100644 (file)
@@ -245,6 +245,10 @@ static int hash_mac_addr(const u8 *addr)
        return a & 0x3f;
 }
 
+#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
+                    FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
+                    FW_PORT_CAP_SPEED_100G | FW_PORT_CAP_ANEG)
+
 /**
  *     init_link_config - initialize a link's SW state
  *     @lc: structure holding the link state
@@ -259,8 +263,8 @@ static void init_link_config(struct link_config *lc, unsigned int caps)
        lc->requested_speed = 0;
        lc->speed = 0;
        lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
-       if (lc->supported & SUPPORTED_Autoneg) {
-               lc->advertising = lc->supported;
+       if (lc->supported & FW_PORT_CAP_ANEG) {
+               lc->advertising = lc->supported & ADVERT_MASK;
                lc->autoneg = AUTONEG_ENABLE;
                lc->requested_fc |= PAUSE_AUTONEG;
        } else {
@@ -280,7 +284,6 @@ int t4vf_port_init(struct adapter *adapter, int pidx)
        struct fw_vi_cmd vi_cmd, vi_rpl;
        struct fw_port_cmd port_cmd, port_rpl;
        int v;
-       u32 word;
 
        /*
         * Execute a VI Read command to get our Virtual Interface information
@@ -319,19 +322,13 @@ int t4vf_port_init(struct adapter *adapter, int pidx)
        if (v)
                return v;
 
-       v = 0;
-       word = be16_to_cpu(port_rpl.u.info.pcap);
-       if (word & FW_PORT_CAP_SPEED_100M)
-               v |= SUPPORTED_100baseT_Full;
-       if (word & FW_PORT_CAP_SPEED_1G)
-               v |= SUPPORTED_1000baseT_Full;
-       if (word & FW_PORT_CAP_SPEED_10G)
-               v |= SUPPORTED_10000baseT_Full;
-       if (word & FW_PORT_CAP_SPEED_40G)
-               v |= SUPPORTED_40000baseSR4_Full;
-       if (word & FW_PORT_CAP_ANEG)
-               v |= SUPPORTED_Autoneg;
-       init_link_config(&pi->link_cfg, v);
+       v = be32_to_cpu(port_rpl.u.info.lstatus_to_modtype);
+       pi->mdio_addr = (v & FW_PORT_CMD_MDIOCAP_F) ?
+                       FW_PORT_CMD_MDIOADDR_G(v) : -1;
+       pi->port_type = FW_PORT_CMD_PTYPE_G(v);
+       pi->mod_type = FW_PORT_MOD_TYPE_NA;
+
+       init_link_config(&pi->link_cfg, be16_to_cpu(port_rpl.u.info.pcap));
 
        return 0;
 }
@@ -1491,7 +1488,7 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
                 */
                const struct fw_port_cmd *port_cmd =
                        (const struct fw_port_cmd *)rpl;
-               u32 word;
+               u32 stat, mod;
                int action, port_id, link_ok, speed, fc, pidx;
 
                /*
@@ -1509,21 +1506,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
                port_id = FW_PORT_CMD_PORTID_G(
                        be32_to_cpu(port_cmd->op_to_portid));
 
-               word = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype);
-               link_ok = (word & FW_PORT_CMD_LSTATUS_F) != 0;
+               stat = be32_to_cpu(port_cmd->u.info.lstatus_to_modtype);
+               link_ok = (stat & FW_PORT_CMD_LSTATUS_F) != 0;
                speed = 0;
                fc = 0;
-               if (word & FW_PORT_CMD_RXPAUSE_F)
+               if (stat & FW_PORT_CMD_RXPAUSE_F)
                        fc |= PAUSE_RX;
-               if (word & FW_PORT_CMD_TXPAUSE_F)
+               if (stat & FW_PORT_CMD_TXPAUSE_F)
                        fc |= PAUSE_TX;
-               if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
+               if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_100M))
                        speed = 100;
-               else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
+               else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_1G))
                        speed = 1000;
-               else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
+               else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_10G))
                        speed = 10000;
-               else if (word & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
+               else if (stat & FW_PORT_CMD_LSPEED_V(FW_PORT_CAP_SPEED_40G))
                        speed = 40000;
 
                /*
@@ -1540,12 +1537,21 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
                                continue;
 
                        lc = &pi->link_cfg;
+
+                       mod = FW_PORT_CMD_MODTYPE_G(stat);
+                       if (mod != pi->mod_type) {
+                               pi->mod_type = mod;
+                               t4vf_os_portmod_changed(adapter, pidx);
+                       }
+
                        if (link_ok != lc->link_ok || speed != lc->speed ||
                            fc != lc->fc) {
                                /* something changed */
                                lc->link_ok = link_ok;
                                lc->speed = speed;
                                lc->fc = fc;
+                               lc->supported =
+                                       be16_to_cpu(port_cmd->u.info.pcap);
                                t4vf_os_link_changed(adapter, pidx, link_ok);
                        }
                }
index 868d0f605d60524053c46d87d010bf50e3341a1d..e356afa44e7d8400fdaa59c47dfa8294e1c0bb8c 100644 (file)
@@ -1060,10 +1060,14 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
                                     PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
                }
 
-               if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) {
-                       skb->csum = htons(checksum);
-                       skb->ip_summed = CHECKSUM_COMPLETE;
-               }
+               /* Hardware does not provide whole packet checksum. It only
+                * provides pseudo checksum. Since hw validates the packet
+                * checksum but not provide us the checksum value. use
+                * CHECSUM_UNNECESSARY.
+                */
+               if ((netdev->features & NETIF_F_RXCSUM) && tcp_udp_csum_ok &&
+                   ipv4_csum_ok)
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
 
                if (vlan_stripped)
                        __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tci);
@@ -1331,7 +1335,7 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget)
        int err;
 
        if (!enic_poll_lock_napi(&enic->rq[rq]))
-               return work_done;
+               return budget;
        /* Service RQ
         */
 
@@ -1612,7 +1616,7 @@ static int enic_open(struct net_device *netdev)
                if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
                        netdev_err(netdev, "Unable to alloc receive buffers\n");
                        err = -ENOMEM;
-                       goto err_out_notify_unset;
+                       goto err_out_free_rq;
                }
        }
 
@@ -1645,7 +1649,9 @@ static int enic_open(struct net_device *netdev)
 
        return 0;
 
-err_out_notify_unset:
+err_out_free_rq:
+       for (i = 0; i < enic->rq_count; i++)
+               vnic_rq_clean(&enic->rq[i], enic_free_rq_buf);
        enic_dev_notify_unset(enic);
 err_out_free_intr:
        enic_free_intr(enic);
index a379c3e4b57f73ef3fd133bd4bb5114e29f10cb4..13d00a38a5bd60ed1e7af054f3a22b617e64317d 100644 (file)
@@ -398,13 +398,8 @@ static int dnet_poll(struct napi_struct *napi, int budget)
                 * break out of while loop if there are no more
                 * packets waiting
                 */
-               if (!(dnet_readl(bp, RX_FIFO_WCNT) >> 16)) {
-                       napi_complete(napi);
-                       int_enable = dnet_readl(bp, INTR_ENB);
-                       int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF;
-                       dnet_writel(bp, int_enable, INTR_ENB);
-                       return 0;
-               }
+               if (!(dnet_readl(bp, RX_FIFO_WCNT) >> 16))
+                       break;
 
                cmd_word = dnet_readl(bp, RX_LEN_FIFO);
                pkt_len = cmd_word & 0xFFFF;
@@ -433,20 +428,17 @@ static int dnet_poll(struct napi_struct *napi, int budget)
                               "size %u.\n", dev->name, pkt_len);
        }
 
-       budget -= npackets;
-
        if (npackets < budget) {
                /* We processed all packets available.  Tell NAPI it can
-                * stop polling then re-enable rx interrupts */
+                * stop polling then re-enable rx interrupts.
+                */
                napi_complete(napi);
                int_enable = dnet_readl(bp, INTR_ENB);
                int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF;
                dnet_writel(bp, int_enable, INTR_ENB);
-               return 0;
        }
 
-       /* There are still packets waiting */
-       return 1;
+       return npackets;
 }
 
 static irqreturn_t dnet_interrupt(int irq, void *dev_id)
index 196073110e320b1bb05e8b38bf9a5e1c66b5e929..d48806b5cd8889457f28062336d7c4bf308af6a1 100644 (file)
@@ -4383,8 +4383,9 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
  * distinguish various types of transports (VxLAN, GRE, NVGRE ..). So, offload
  * is expected to work across all types of IP tunnels once exported. Skyhawk
  * supports offloads for either VxLAN or NVGRE, exclusively. So we export VxLAN
- * offloads in hw_enc_features only when a VxLAN port is added. Note this only
- * ensures that other tunnels work fine while VxLAN offloads are not enabled.
+ * offloads in hw_enc_features only when a VxLAN port is added. If other (non
+ * VxLAN) tunnels are configured while VxLAN offloads are enabled, offloads for
+ * those other tunnels are unexported on the fly through ndo_features_check().
  *
  * Skyhawk supports VxLAN offloads only for one UDP dport. So, if the stack
  * adds more than one port, disable offloads and don't re-enable them again
@@ -4459,9 +4460,45 @@ done:
        adapter->vxlan_port_count--;
 }
 
-static bool be_gso_check(struct sk_buff *skb, struct net_device *dev)
+static netdev_features_t be_features_check(struct sk_buff *skb,
+                                          struct net_device *dev,
+                                          netdev_features_t features)
 {
-       return vxlan_gso_check(skb);
+       struct be_adapter *adapter = netdev_priv(dev);
+       u8 l4_hdr = 0;
+
+       /* The code below restricts offload features for some tunneled packets.
+        * Offload features for normal (non tunnel) packets are unchanged.
+        */
+       if (!skb->encapsulation ||
+           !(adapter->flags & BE_FLAGS_VXLAN_OFFLOADS))
+               return features;
+
+       /* It's an encapsulated packet and VxLAN offloads are enabled. We
+        * should disable tunnel offload features if it's not a VxLAN packet,
+        * as tunnel offloads have been enabled only for VxLAN. This is done to
+        * allow other tunneled traffic like GRE work fine while VxLAN
+        * offloads are configured in Skyhawk-R.
+        */
+       switch (vlan_get_protocol(skb)) {
+       case htons(ETH_P_IP):
+               l4_hdr = ip_hdr(skb)->protocol;
+               break;
+       case htons(ETH_P_IPV6):
+               l4_hdr = ipv6_hdr(skb)->nexthdr;
+               break;
+       default:
+               return features;
+       }
+
+       if (l4_hdr != IPPROTO_UDP ||
+           skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
+           skb->inner_protocol != htons(ETH_P_TEB) ||
+           skb_inner_mac_header(skb) - skb_transport_header(skb) !=
+           sizeof(struct udphdr) + sizeof(struct vxlanhdr))
+               return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK);
+
+       return features;
 }
 #endif
 
@@ -4492,7 +4529,7 @@ static const struct net_device_ops be_netdev_ops = {
 #ifdef CONFIG_BE2NET_VXLAN
        .ndo_add_vxlan_port     = be_add_vxlan_port,
        .ndo_del_vxlan_port     = be_del_vxlan_port,
-       .ndo_gso_check          = be_gso_check,
+       .ndo_features_check     = be_features_check,
 #endif
 };
 
index 469691ad4a1ee25dda5ff9dbec0ef8735ae0f6bf..40132929daf7ac7713f2cd0f1f469656616fadfc 100644 (file)
@@ -424,6 +424,8 @@ struct bufdesc_ex {
  * (40ns * 6).
  */
 #define FEC_QUIRK_BUG_CAPTURE          (1 << 10)
+/* Controller has only one MDIO bus */
+#define FEC_QUIRK_SINGLE_MDIO          (1 << 11)
 
 struct fec_enet_priv_tx_q {
        int index;
index 5ebdf8dc8a31300f526fd98912080dc4850937f2..bba87775419dc9c0d5adadcdda8c1e634dc8e04d 100644 (file)
@@ -91,7 +91,8 @@ static struct platform_device_id fec_devtype[] = {
                .driver_data = 0,
        }, {
                .name = "imx28-fec",
-               .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME,
+               .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME |
+                               FEC_QUIRK_SINGLE_MDIO,
        }, {
                .name = "imx6q-fec",
                .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
@@ -1937,7 +1938,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        int err = -ENXIO, i;
 
        /*
-        * The dual fec interfaces are not equivalent with enet-mac.
+        * The i.MX28 dual fec interfaces are not equal.
         * Here are the differences:
         *
         *  - fec0 supports MII & RMII modes while fec1 only supports RMII
@@ -1952,7 +1953,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
         * mdio interface in board design, and need to be configured by
         * fec0 mii_bus.
         */
-       if ((fep->quirks & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) {
+       if ((fep->quirks & FEC_QUIRK_SINGLE_MDIO) && fep->dev_id > 0) {
                /* fec1 uses fec0 mii_bus */
                if (mii_cnt && fec0_mii_bus) {
                        fep->mii_bus = fec0_mii_bus;
@@ -2015,7 +2016,7 @@ static int fec_enet_mii_init(struct platform_device *pdev)
        mii_cnt++;
 
        /* save fec0 mii_bus */
-       if (fep->quirks & FEC_QUIRK_ENET_MAC)
+       if (fep->quirks & FEC_QUIRK_SINGLE_MDIO)
                fec0_mii_bus = fep->mii_bus;
 
        return 0;
@@ -3129,6 +3130,7 @@ fec_probe(struct platform_device *pdev)
                pdev->id_entry = of_id->data;
        fep->quirks = pdev->id_entry->driver_data;
 
+       fep->netdev = ndev;
        fep->num_rx_queues = num_rx_qs;
        fep->num_tx_queues = num_tx_qs;
 
index 5b8300a32bf5f5eb1df93d7262b22a00b7d77a9f..4d61ef50b465b73bd4bd87256a2ad47d83d4d666 100644 (file)
@@ -281,6 +281,17 @@ config I40E_DCB
 
          If unsure, say N.
 
+config I40E_FCOE
+       bool "Fibre Channel over Ethernet (FCoE)"
+       default n
+       depends on I40E && DCB && FCOE
+       ---help---
+         Say Y here if you want to use Fibre Channel over Ethernet (FCoE)
+         in the driver. This will create new netdev for exclusive FCoE
+         use with XL710 FCoE offloads enabled.
+
+         If unsure, say N.
+
 config I40EVF
        tristate "Intel(R) XL710 X710 Virtual Function Ethernet support"
        depends on PCI_MSI
index 781065eb5431c811f6fb37da81b6e6c12f495770..e9c3a87e5b115dc690ef2b81bbe16a5480dae5b1 100644 (file)
@@ -1543,7 +1543,7 @@ static int e100_phy_init(struct nic *nic)
                mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
        } else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
           (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
-               !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
+               (nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
                /* enable/disable MDI/MDI-X auto-switching. */
                mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
                                nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
index 4b94ddb29c248ed2571c4d90eb37d8c8ecbec935..c405819991214e21a25b5a670d0097482fd643ab 100644 (file)
@@ -44,4 +44,4 @@ i40e-objs := i40e_main.o \
        i40e_virtchnl_pf.o
 
 i40e-$(CONFIG_I40E_DCB) += i40e_dcb.o i40e_dcb_nl.o
-i40e-$(CONFIG_FCOE:m=y) += i40e_fcoe.o
+i40e-$(CONFIG_I40E_FCOE) += i40e_fcoe.o
index 433a55886ad29bfb1b357d47ad4953f9ddac6145..cb0de455683e452810c0a404d9b1bd138418fb88 100644 (file)
@@ -829,7 +829,7 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
                if (desc_n >= ring->count || desc_n < 0) {
                        dev_info(&pf->pdev->dev,
                                 "descriptor %d not found\n", desc_n);
-                       return;
+                       goto out;
                }
                if (!is_rx_ring) {
                        txd = I40E_TX_DESC(ring, desc_n);
@@ -855,6 +855,8 @@ static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
        } else {
                dev_info(&pf->pdev->dev, "dump desc rx/tx <vsi_seid> <ring_id> [<desc_n>]\n");
        }
+
+out:
        kfree(ring);
 }
 
index 045b5c4b98b38ba74ef68104828351f2a8fdc67c..ad802dd0f67a3d4fdcb6810ebdc8d66b67706d66 100644 (file)
@@ -78,7 +78,7 @@ do {                                                            \
 } while (0)
 
 typedef enum i40e_status_code i40e_status;
-#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
+#ifdef CONFIG_I40E_FCOE
 #define I40E_FCOE
-#endif /* CONFIG_FCOE or CONFIG_FCOE_MODULE */
+#endif
 #endif /* _I40E_OSDEP_H_ */
index 04b441460bbda6e36cb64731d24247a1b954e506..cecb340898fe2a881aac449c7377110ccc56793b 100644 (file)
@@ -658,6 +658,8 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
        return le32_to_cpu(*(volatile __le32 *)head);
 }
 
+#define WB_STRIDE 0x3
+
 /**
  * i40e_clean_tx_irq - Reclaim resources after transmit completes
  * @tx_ring:  tx ring to clean
@@ -759,6 +761,18 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
        tx_ring->q_vector->tx.total_bytes += total_bytes;
        tx_ring->q_vector->tx.total_packets += total_packets;
 
+       /* check to see if there are any non-cache aligned descriptors
+        * waiting to be written back, and kick the hardware to force
+        * them to be written back in case of napi polling
+        */
+       if (budget &&
+           !((i & WB_STRIDE) == WB_STRIDE) &&
+           !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
+           (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
+               tx_ring->arm_wb = true;
+       else
+               tx_ring->arm_wb = false;
+
        if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) {
                /* schedule immediate reset if we believe we hung */
                dev_info(tx_ring->dev, "Detected Tx Unit Hang\n"
@@ -777,13 +791,16 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
 
                dev_info(tx_ring->dev,
-                        "tx hang detected on queue %d, resetting adapter\n",
+                        "tx hang detected on queue %d, reset requested\n",
                         tx_ring->queue_index);
 
-               tx_ring->netdev->netdev_ops->ndo_tx_timeout(tx_ring->netdev);
+               /* do not fire the reset immediately, wait for the stack to
+                * decide we are truly stuck, also prevents every queue from
+                * simultaneously requesting a reset
+                */
 
-               /* the adapter is about to reset, no point in enabling stuff */
-               return true;
+               /* the adapter is about to reset, no point in enabling polling */
+               budget = 1;
        }
 
        netdev_tx_completed_queue(netdev_get_tx_queue(tx_ring->netdev,
@@ -806,7 +823,25 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                }
        }
 
-       return budget > 0;
+       return !!budget;
+}
+
+/**
+ * i40e_force_wb - Arm hardware to do a wb on noncache aligned descriptors
+ * @vsi: the VSI we care about
+ * @q_vector: the vector  on which to force writeback
+ *
+ **/
+static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+{
+       u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
+                 I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK |
+                 I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK
+                 /* allow 00 to be written to the index */;
+
+       wr32(&vsi->back->hw,
+            I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1),
+            val);
 }
 
 /**
@@ -1290,9 +1325,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
         * so the total length of IPv4 header is IHL*4 bytes
         * The UDP_0 bit *may* bet set if the *inner* header is UDP
         */
-       if (ipv4_tunnel &&
-           (decoded.inner_prot != I40E_RX_PTYPE_INNER_PROT_UDP) &&
-           !(rx_status & (1 << I40E_RX_DESC_STATUS_UDP_0_SHIFT))) {
+       if (ipv4_tunnel) {
                skb->transport_header = skb->mac_header +
                                        sizeof(struct ethhdr) +
                                        (ip_hdr(skb)->ihl * 4);
@@ -1302,15 +1335,19 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
                                          skb->protocol == htons(ETH_P_8021AD))
                                          ? VLAN_HLEN : 0;
 
-               rx_udp_csum = udp_csum(skb);
-               iph = ip_hdr(skb);
-               csum = csum_tcpudp_magic(
-                               iph->saddr, iph->daddr,
-                               (skb->len - skb_transport_offset(skb)),
-                               IPPROTO_UDP, rx_udp_csum);
+               if ((ip_hdr(skb)->protocol == IPPROTO_UDP) &&
+                   (udp_hdr(skb)->check != 0)) {
+                       rx_udp_csum = udp_csum(skb);
+                       iph = ip_hdr(skb);
+                       csum = csum_tcpudp_magic(
+                                       iph->saddr, iph->daddr,
+                                       (skb->len - skb_transport_offset(skb)),
+                                       IPPROTO_UDP, rx_udp_csum);
 
-               if (udp_hdr(skb)->check != csum)
-                       goto checksum_fail;
+                       if (udp_hdr(skb)->check != csum)
+                               goto checksum_fail;
+
+               } /* else its GRE and so no outer UDP header */
        }
 
        skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1581,6 +1618,7 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
        struct i40e_vsi *vsi = q_vector->vsi;
        struct i40e_ring *ring;
        bool clean_complete = true;
+       bool arm_wb = false;
        int budget_per_ring;
 
        if (test_bit(__I40E_DOWN, &vsi->state)) {
@@ -1591,8 +1629,10 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
        /* Since the actual Tx work is minimal, we can give the Tx a larger
         * budget and be more aggressive about cleaning up the Tx descriptors.
         */
-       i40e_for_each_ring(ring, q_vector->tx)
+       i40e_for_each_ring(ring, q_vector->tx) {
                clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
+               arm_wb |= ring->arm_wb;
+       }
 
        /* We attempt to distribute budget to each Rx queue fairly, but don't
         * allow the budget to go below 1 because that would exit polling early.
@@ -1603,8 +1643,11 @@ int i40e_napi_poll(struct napi_struct *napi, int budget)
                clean_complete &= i40e_clean_rx_irq(ring, budget_per_ring);
 
        /* If work not completed, return budget and polling will return */
-       if (!clean_complete)
+       if (!clean_complete) {
+               if (arm_wb)
+                       i40e_force_wb(vsi, q_vector);
                return budget;
+       }
 
        /* Work is done so exit the polling mode and re-enable the interrupt */
        napi_complete(napi);
@@ -1840,17 +1883,16 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
        if (err < 0)
                return err;
 
-       if (protocol == htons(ETH_P_IP)) {
-               iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+       ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
+
+       if (iph->version == 4) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                iph->tot_len = 0;
                iph->check = 0;
                tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
                                                 0, IPPROTO_TCP, 0);
-       } else if (skb_is_gso_v6(skb)) {
-
-               ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb)
-                                          : ipv6_hdr(skb);
+       } else if (ipv6h->version == 6) {
                tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
                ipv6h->payload_len = 0;
                tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
@@ -1946,13 +1988,9 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                         I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
                        }
                } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
-                       if (tx_flags & I40E_TX_FLAGS_TSO) {
-                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                       if (tx_flags & I40E_TX_FLAGS_TSO)
                                ip_hdr(skb)->check = 0;
-                       } else {
-                               *cd_tunneling |=
-                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
-                       }
                }
 
                /* Now set the ctx descriptor fields */
@@ -1962,7 +2000,10 @@ static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
                                   ((skb_inner_network_offset(skb) -
                                        skb_transport_offset(skb)) >> 1) <<
                                   I40E_TXD_CTX_QW0_NATLEN_SHIFT;
-
+               if (this_ip_hdr->version == 6) {
+                       tx_flags &= ~I40E_TX_FLAGS_IPV4;
+                       tx_flags |= I40E_TX_FLAGS_IPV6;
+               }
        } else {
                network_hdr_len = skb_network_header_len(skb);
                this_ip_hdr = ip_hdr(skb);
@@ -2198,7 +2239,6 @@ static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
        /* Place RS bit on last descriptor of any packet that spans across the
         * 4th descriptor (WB_STRIDE aka 0x3) in a 64B cacheline.
         */
-#define WB_STRIDE 0x3
        if (((i & WB_STRIDE) != WB_STRIDE) &&
            (first <= &tx_ring->tx_bi[i]) &&
            (first >= &tx_ring->tx_bi[i & ~WB_STRIDE])) {
index e60d3accb2e2ec3f2992b056da718d633b978157..18b00231d2f117d714e7e1399aecba0061ead41a 100644 (file)
@@ -241,6 +241,7 @@ struct i40e_ring {
        unsigned long last_rx_timestamp;
 
        bool ring_active;               /* is ring online or not */
+       bool arm_wb;            /* do something to arm write back */
 
        /* stats structs */
        struct i40e_queue_stats stats;
index 051ea94bdcd3e8046181b361d8985c51d15ea19c..0f69ef81751a3d8154db558cc8f3d11e882928a0 100644 (file)
@@ -1125,7 +1125,7 @@ static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask)
        u32 swmask = mask;
        u32 fwmask = mask << 16;
        s32 ret_val = 0;
-       s32 i = 0, timeout = 200; /* FIXME: find real value to use here */
+       s32 i = 0, timeout = 200;
 
        while (i < timeout) {
                if (igb_get_hw_semaphore(hw)) {
index a62fc38f045e1b802730c95484c0b60a340ec1c6..1c75829eb1668fe094af3a9049fb53bb0c8b4bb5 100644 (file)
@@ -192,6 +192,10 @@ static char mv643xx_eth_driver_version[] = "1.4";
 #define IS_TSO_HEADER(txq, addr) \
        ((addr >= txq->tso_hdrs_dma) && \
         (addr < txq->tso_hdrs_dma + txq->tx_ring_size * TSO_HEADER_SIZE))
+
+#define DESC_DMA_MAP_SINGLE 0
+#define DESC_DMA_MAP_PAGE 1
+
 /*
  * RX/TX descriptors.
  */
@@ -362,6 +366,7 @@ struct tx_queue {
        dma_addr_t tso_hdrs_dma;
 
        struct tx_desc *tx_desc_area;
+       char *tx_desc_mapping; /* array to track the type of the dma mapping */
        dma_addr_t tx_desc_dma;
        int tx_desc_area_size;
 
@@ -750,6 +755,7 @@ txq_put_data_tso(struct net_device *dev, struct tx_queue *txq,
        if (txq->tx_curr_desc == txq->tx_ring_size)
                txq->tx_curr_desc = 0;
        desc = &txq->tx_desc_area[tx_index];
+       txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE;
 
        desc->l4i_chk = 0;
        desc->byte_cnt = length;
@@ -879,14 +885,13 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
                skb_frag_t *this_frag;
                int tx_index;
                struct tx_desc *desc;
-               void *addr;
 
                this_frag = &skb_shinfo(skb)->frags[frag];
-               addr = page_address(this_frag->page.p) + this_frag->page_offset;
                tx_index = txq->tx_curr_desc++;
                if (txq->tx_curr_desc == txq->tx_ring_size)
                        txq->tx_curr_desc = 0;
                desc = &txq->tx_desc_area[tx_index];
+               txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_PAGE;
 
                /*
                 * The last fragment will generate an interrupt
@@ -902,8 +907,9 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb)
 
                desc->l4i_chk = 0;
                desc->byte_cnt = skb_frag_size(this_frag);
-               desc->buf_ptr = dma_map_single(mp->dev->dev.parent, addr,
-                                              desc->byte_cnt, DMA_TO_DEVICE);
+               desc->buf_ptr = skb_frag_dma_map(mp->dev->dev.parent,
+                                                this_frag, 0, desc->byte_cnt,
+                                                DMA_TO_DEVICE);
        }
 }
 
@@ -936,6 +942,7 @@ static int txq_submit_skb(struct tx_queue *txq, struct sk_buff *skb,
        if (txq->tx_curr_desc == txq->tx_ring_size)
                txq->tx_curr_desc = 0;
        desc = &txq->tx_desc_area[tx_index];
+       txq->tx_desc_mapping[tx_index] = DESC_DMA_MAP_SINGLE;
 
        if (nr_frags) {
                txq_submit_frag_skb(txq, skb);
@@ -1047,9 +1054,12 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
                int tx_index;
                struct tx_desc *desc;
                u32 cmd_sts;
+               char desc_dma_map;
 
                tx_index = txq->tx_used_desc;
                desc = &txq->tx_desc_area[tx_index];
+               desc_dma_map = txq->tx_desc_mapping[tx_index];
+
                cmd_sts = desc->cmd_sts;
 
                if (cmd_sts & BUFFER_OWNED_BY_DMA) {
@@ -1065,9 +1075,19 @@ static int txq_reclaim(struct tx_queue *txq, int budget, int force)
                reclaimed++;
                txq->tx_desc_count--;
 
-               if (!IS_TSO_HEADER(txq, desc->buf_ptr))
-                       dma_unmap_single(mp->dev->dev.parent, desc->buf_ptr,
-                                        desc->byte_cnt, DMA_TO_DEVICE);
+               if (!IS_TSO_HEADER(txq, desc->buf_ptr)) {
+
+                       if (desc_dma_map == DESC_DMA_MAP_PAGE)
+                               dma_unmap_page(mp->dev->dev.parent,
+                                              desc->buf_ptr,
+                                              desc->byte_cnt,
+                                              DMA_TO_DEVICE);
+                       else
+                               dma_unmap_single(mp->dev->dev.parent,
+                                                desc->buf_ptr,
+                                                desc->byte_cnt,
+                                                DMA_TO_DEVICE);
+               }
 
                if (cmd_sts & TX_ENABLE_INTERRUPT) {
                        struct sk_buff *skb = __skb_dequeue(&txq->tx_skb);
@@ -1996,6 +2016,7 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
        struct tx_queue *txq = mp->txq + index;
        struct tx_desc *tx_desc;
        int size;
+       int ret;
        int i;
 
        txq->index = index;
@@ -2048,18 +2069,34 @@ static int txq_init(struct mv643xx_eth_private *mp, int index)
                                        nexti * sizeof(struct tx_desc);
        }
 
+       txq->tx_desc_mapping = kcalloc(txq->tx_ring_size, sizeof(char),
+                                      GFP_KERNEL);
+       if (!txq->tx_desc_mapping) {
+               ret = -ENOMEM;
+               goto err_free_desc_area;
+       }
+
        /* Allocate DMA buffers for TSO MAC/IP/TCP headers */
        txq->tso_hdrs = dma_alloc_coherent(mp->dev->dev.parent,
                                           txq->tx_ring_size * TSO_HEADER_SIZE,
                                           &txq->tso_hdrs_dma, GFP_KERNEL);
        if (txq->tso_hdrs == NULL) {
-               dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,
-                                 txq->tx_desc_area, txq->tx_desc_dma);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err_free_desc_mapping;
        }
        skb_queue_head_init(&txq->tx_skb);
 
        return 0;
+
+err_free_desc_mapping:
+       kfree(txq->tx_desc_mapping);
+err_free_desc_area:
+       if (index == 0 && size <= mp->tx_desc_sram_size)
+               iounmap(txq->tx_desc_area);
+       else
+               dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,
+                                 txq->tx_desc_area, txq->tx_desc_dma);
+       return ret;
 }
 
 static void txq_deinit(struct tx_queue *txq)
@@ -2077,6 +2114,8 @@ static void txq_deinit(struct tx_queue *txq)
        else
                dma_free_coherent(mp->dev->dev.parent, txq->tx_desc_area_size,
                                  txq->tx_desc_area, txq->tx_desc_dma);
+       kfree(txq->tx_desc_mapping);
+
        if (txq->tso_hdrs)
                dma_free_coherent(mp->dev->dev.parent,
                                  txq->tx_ring_size * TSO_HEADER_SIZE,
index 190cbd931f6bc8527654d14d042dc85799883a81..ac6a8f1eea6ca2dbaa94cce76cde89b85eda32c5 100644 (file)
@@ -475,7 +475,8 @@ static int mlx4_en_tunnel_steer_add(struct mlx4_en_priv *priv, unsigned char *ad
 {
        int err;
 
-       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN)
+       if (priv->mdev->dev->caps.tunnel_offload_mode != MLX4_TUNNEL_OFFLOAD_MODE_VXLAN ||
+           priv->mdev->dev->caps.dmfs_high_steer_mode == MLX4_STEERING_DMFS_A0_STATIC)
                return 0; /* do nothing */
 
        err = mlx4_tunnel_steer_add(priv->mdev->dev, addr, priv->port, qpn,
@@ -2365,9 +2366,11 @@ static void mlx4_en_del_vxlan_port(struct  net_device *dev,
        queue_work(priv->mdev->workqueue, &priv->vxlan_del_task);
 }
 
-static bool mlx4_en_gso_check(struct sk_buff *skb, struct net_device *dev)
+static netdev_features_t mlx4_en_features_check(struct sk_buff *skb,
+                                               struct net_device *dev,
+                                               netdev_features_t features)
 {
-       return vxlan_gso_check(skb);
+       return vxlan_features_check(skb, features);
 }
 #endif
 
@@ -2400,7 +2403,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_MLX4_EN_VXLAN
        .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
        .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
-       .ndo_gso_check          = mlx4_en_gso_check,
+       .ndo_features_check     = mlx4_en_features_check,
 #endif
 };
 
@@ -2434,7 +2437,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
 #ifdef CONFIG_MLX4_EN_VXLAN
        .ndo_add_vxlan_port     = mlx4_en_add_vxlan_port,
        .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
-       .ndo_gso_check          = mlx4_en_gso_check,
+       .ndo_features_check     = mlx4_en_features_check,
 #endif
 };
 
index a308d41e4de08678107b185df2c7b8b7df3b39a7..e3357bf523df866222bdabdd0ec4c31cb24bb2a7 100644 (file)
@@ -962,7 +962,17 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                tx_desc->ctrl.owner_opcode = op_own;
                if (send_doorbell) {
                        wmb();
-                       iowrite32(ring->doorbell_qpn,
+                       /* Since there is no iowrite*_native() that writes the
+                        * value as is, without byteswapping - using the one
+                        * the doesn't do byteswapping in the relevant arch
+                        * endianness.
+                        */
+#if defined(__LITTLE_ENDIAN)
+                       iowrite32(
+#else
+                       iowrite32be(
+#endif
+                                 ring->doorbell_qpn,
                                  ring->bf.uar->map + MLX4_SEND_DOORBELL);
                } else {
                        ring->xmit_more++;
index 943cbd47d832bb98719e355a727e8451c68bfbbe..6e08352ec994df3d403b8a46699cb224aa9b6702 100644 (file)
@@ -1744,8 +1744,7 @@ static void choose_tunnel_offload_mode(struct mlx4_dev *dev,
                                       struct mlx4_dev_cap *dev_cap)
 {
        if (dev->caps.steering_mode == MLX4_STEERING_MODE_DEVICE_MANAGED &&
-           dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS &&
-           dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC)
+           dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_VXLAN_OFFLOADS)
                dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_VXLAN;
        else
                dev->caps.tunnel_offload_mode = MLX4_TUNNEL_OFFLOAD_MODE_NONE;
@@ -1829,7 +1828,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
                err = mlx4_dev_cap(dev, &dev_cap);
                if (err) {
                        mlx4_err(dev, "QUERY_DEV_CAP command failed, aborting\n");
-                       goto err_stop_fw;
+                       return err;
                }
 
                choose_steering_mode(dev, &dev_cap);
@@ -1860,7 +1859,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
                                             &init_hca);
                if ((long long) icm_size < 0) {
                        err = icm_size;
-                       goto err_stop_fw;
+                       return err;
                }
 
                dev->caps.max_fmr_maps = (1 << (32 - ilog2(dev->caps.num_mpts))) - 1;
@@ -1874,7 +1873,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
 
                err = mlx4_init_icm(dev, &dev_cap, &init_hca, icm_size);
                if (err)
-                       goto err_stop_fw;
+                       return err;
 
                err = mlx4_INIT_HCA(dev, &init_hca);
                if (err) {
@@ -1886,7 +1885,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
                        err = mlx4_query_func(dev, &dev_cap);
                        if (err < 0) {
                                mlx4_err(dev, "QUERY_FUNC command failed, aborting.\n");
-                               goto err_stop_fw;
+                               goto err_close;
                        } else if (err & MLX4_QUERY_FUNC_NUM_SYS_EQS) {
                                dev->caps.num_eqs = dev_cap.max_eqs;
                                dev->caps.reserved_eqs = dev_cap.reserved_eqs;
@@ -2006,11 +2005,6 @@ err_free_icm:
        if (!mlx4_is_slave(dev))
                mlx4_free_icms(dev);
 
-err_stop_fw:
-       if (!mlx4_is_slave(dev)) {
-               mlx4_UNMAP_FA(dev);
-               mlx4_free_icm(dev, priv->fw.fw_icm, 0);
-       }
        return err;
 }
 
index d6f549685c0fcd8a5cccf0c948536ed924024892..7094a9c70fd5f8be8cafc6e245d6297effe8c22a 100644 (file)
@@ -584,6 +584,7 @@ EXPORT_SYMBOL_GPL(mlx4_mr_free);
 void mlx4_mr_rereg_mem_cleanup(struct mlx4_dev *dev, struct mlx4_mr *mr)
 {
        mlx4_mtt_cleanup(dev, &mr->mtt);
+       mr->mtt.order = -1;
 }
 EXPORT_SYMBOL_GPL(mlx4_mr_rereg_mem_cleanup);
 
@@ -593,14 +594,14 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr,
 {
        int err;
 
-       mpt_entry->start       = cpu_to_be64(iova);
-       mpt_entry->length      = cpu_to_be64(size);
-       mpt_entry->entity_size = cpu_to_be32(page_shift);
-
        err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
        if (err)
                return err;
 
+       mpt_entry->start       = cpu_to_be64(mr->iova);
+       mpt_entry->length      = cpu_to_be64(mr->size);
+       mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift);
+
        mpt_entry->pd_flags &= cpu_to_be32(MLX4_MPT_PD_MASK |
                                           MLX4_MPT_PD_FLAG_EN_INV);
        mpt_entry->flags    &= cpu_to_be32(MLX4_MPT_FLAG_FREE |
index f1ebed6c63b1bfe8a912963413d3afba3cd0fa51..2fa6ae026e4f331341253cc898742592089b9283 100644 (file)
@@ -2303,12 +2303,6 @@ static inline int port_chk_force_flow_ctrl(struct ksz_hw *hw, int p)
 
 /* Spanning Tree */
 
-static inline void port_cfg_dis_learn(struct ksz_hw *hw, int p, int set)
-{
-       port_cfg(hw, p,
-               KS8842_PORT_CTRL_2_OFFSET, PORT_LEARN_DISABLE, set);
-}
-
 static inline void port_cfg_rx(struct ksz_hw *hw, int p, int set)
 {
        port_cfg(hw, p,
index af099057f0e9c263dc250924785a15cf75ea6edb..71af98bb72cbeb1cc2376013847835c4195ec805 100644 (file)
@@ -4033,8 +4033,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        (void)pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
        mgp->cmd = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->cmd),
                                      &mgp->cmd_bus, GFP_KERNEL);
-       if (mgp->cmd == NULL)
+       if (!mgp->cmd) {
+               status = -ENOMEM;
                goto abort_with_enabled;
+       }
 
        mgp->board_span = pci_resource_len(pdev, 0);
        mgp->iomem_base = pci_resource_start(pdev, 0);
index f5e4b820128ba8966e8a7d4ecdc9713e7982aa61..db0c7a9aee601d1241b0dcfcc267efa2469a4f0b 100644 (file)
@@ -6987,7 +6987,9 @@ static int s2io_add_isr(struct s2io_nic *sp)
                        if (sp->s2io_entries[i].in_use == MSIX_FLG) {
                                if (sp->s2io_entries[i].type ==
                                    MSIX_RING_TYPE) {
-                                       sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
+                                       snprintf(sp->desc[i],
+                                               sizeof(sp->desc[i]),
+                                               "%s:MSI-X-%d-RX",
                                                dev->name, i);
                                        err = request_irq(sp->entries[i].vector,
                                                          s2io_msix_ring_handle,
@@ -6996,7 +6998,9 @@ static int s2io_add_isr(struct s2io_nic *sp)
                                                          sp->s2io_entries[i].arg);
                                } else if (sp->s2io_entries[i].type ==
                                           MSIX_ALARM_TYPE) {
-                                       sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
+                                       snprintf(sp->desc[i],
+                                               sizeof(sp->desc[i]),
+                                               "%s:MSI-X-%d-TX",
                                                dev->name, i);
                                        err = request_irq(sp->entries[i].vector,
                                                          s2io_msix_fifo_handle,
@@ -8154,7 +8158,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                          "%s: UDP Fragmentation Offload(UFO) enabled\n",
                          dev->name);
        /* Initialize device name */
-       sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
+       snprintf(sp->name, sizeof(sp->name), "%s Neterion %s", dev->name,
+                sp->product_name);
 
        if (vlan_tag_strip)
                sp->vlan_strip_flag = 1;
index 613037584d08e785ef2700ca1d2221b50b256e9c..c531c8ae1be4e2ad3d509b9656369c3560f8ad78 100644 (file)
@@ -2388,7 +2388,10 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget)
 
        work_done = netxen_process_rcv_ring(sds_ring, budget);
 
-       if ((work_done < budget) && tx_complete) {
+       if (!tx_complete)
+               work_done = budget;
+
+       if (work_done < budget) {
                napi_complete(&sds_ring->napi);
                if (test_bit(__NX_DEV_UP, &adapter->state))
                        netxen_nic_enable_int(sds_ring);
index c2f09af5c25b9f389ce2eb0bbe85487d733d3e1e..4847713211cafa2258b9511cda89f4232a623ebe 100644 (file)
@@ -146,10 +146,7 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
 {
        int i = 0;
 
-       while (i < 10) {
-               if (i)
-                       ssleep(1);
-
+       do {
                if (ql_sem_lock(qdev,
                                QL_DRVR_SEM_MASK,
                                (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
@@ -158,7 +155,8 @@ static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
                                      "driver lock acquired\n");
                        return 1;
                }
-       }
+               ssleep(1);
+       } while (++i < 10);
 
        netdev_err(qdev->ndev, "Timed out waiting for driver lock...\n");
        return 0;
index 1aa25b13ace1d2ccce0d5cf10fb07fb3a3158038..2528c3fb6b90b6976017082867327ade23a3d70e 100644 (file)
@@ -505,9 +505,11 @@ static void qlcnic_del_vxlan_port(struct net_device *netdev,
        adapter->flags |= QLCNIC_DEL_VXLAN_PORT;
 }
 
-static bool qlcnic_gso_check(struct sk_buff *skb, struct net_device *dev)
+static netdev_features_t qlcnic_features_check(struct sk_buff *skb,
+                                              struct net_device *dev,
+                                              netdev_features_t features)
 {
-       return vxlan_gso_check(skb);
+       return vxlan_features_check(skb, features);
 }
 #endif
 
@@ -532,7 +534,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
 #ifdef CONFIG_QLCNIC_VXLAN
        .ndo_add_vxlan_port     = qlcnic_add_vxlan_port,
        .ndo_del_vxlan_port     = qlcnic_del_vxlan_port,
-       .ndo_gso_check          = qlcnic_gso_check,
+       .ndo_features_check     = qlcnic_features_check,
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = qlcnic_poll_controller,
@@ -2603,6 +2605,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        } else {
                dev_err(&pdev->dev,
                        "%s: failed. Please Reboot\n", __func__);
+               err = -ENODEV;
                goto err_out_free_hw;
        }
 
index 6d0b9dfac313ce8aa4891a665bf5cf3c394f48f0..78bb4ceb1cdd364f3d044f746ada0ff0aef954e3 100644 (file)
@@ -787,10 +787,10 @@ static struct net_device *rtl8139_init_board(struct pci_dev *pdev)
        if (rc)
                goto err_out;
 
+       disable_dev_on_err = 1;
        rc = pci_request_regions (pdev, DRV_NAME);
        if (rc)
                goto err_out;
-       disable_dev_on_err = 1;
 
        pci_set_master (pdev);
 
@@ -1110,6 +1110,7 @@ static int rtl8139_init_one(struct pci_dev *pdev,
        return 0;
 
 err_out:
+       netif_napi_del(&tp->napi);
        __rtl8139_cleanup_dev (dev);
        pci_disable_device (pdev);
        return i;
@@ -1124,6 +1125,7 @@ static void rtl8139_remove_one(struct pci_dev *pdev)
        assert (dev != NULL);
 
        cancel_delayed_work_sync(&tp->thread);
+       netif_napi_del(&tp->napi);
 
        unregister_netdev (dev);
 
index c29ba80ae02bfde60f41f4118c02bab642303b89..04283fe0e6a7248877e5dffc1de75e4dedf6748b 100644 (file)
@@ -396,6 +396,9 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
        [TSU_ADRL31]    = 0x01fc,
 };
 
+static void sh_eth_rcv_snd_disable(struct net_device *ndev);
+static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev);
+
 static bool sh_eth_is_gether(struct sh_eth_private *mdp)
 {
        return mdp->reg_offset == sh_eth_offset_gigabit;
@@ -473,6 +476,7 @@ static struct sh_eth_cpu_data r8a777x_data = {
        .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
                          EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |
                          EESR_ECI,
+       .fdr_value      = 0x00000f0f,
 
        .apr            = 1,
        .mpr            = 1,
@@ -495,6 +499,9 @@ static struct sh_eth_cpu_data r8a779x_data = {
        .eesr_err_check = EESR_TWB | EESR_TABT | EESR_RABT | EESR_RFE |
                          EESR_RDE | EESR_RFRMER | EESR_TFE | EESR_TDE |
                          EESR_ECI,
+       .fdr_value      = 0x00000f0f,
+
+       .trscer_err_mask = DESC_I_RINT8,
 
        .apr            = 1,
        .mpr            = 1,
@@ -856,6 +863,9 @@ static void sh_eth_set_default_cpu_data(struct sh_eth_cpu_data *cd)
 
        if (!cd->eesr_err_check)
                cd->eesr_err_check = DEFAULT_EESR_ERR_CHECK;
+
+       if (!cd->trscer_err_mask)
+               cd->trscer_err_mask = DEFAULT_TRSCER_ERR_MASK;
 }
 
 static int sh_eth_check_reset(struct net_device *ndev)
@@ -1113,6 +1123,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
        int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring;
        int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
        int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1;
+       dma_addr_t dma_addr;
 
        mdp->cur_rx = 0;
        mdp->cur_tx = 0;
@@ -1126,7 +1137,6 @@ static void sh_eth_ring_format(struct net_device *ndev)
                /* skb */
                mdp->rx_skbuff[i] = NULL;
                skb = netdev_alloc_skb(ndev, skbuff_size);
-               mdp->rx_skbuff[i] = skb;
                if (skb == NULL)
                        break;
                sh_eth_set_receive_align(skb);
@@ -1135,9 +1145,15 @@ static void sh_eth_ring_format(struct net_device *ndev)
                rxdesc = &mdp->rx_ring[i];
                /* The size of the buffer is a multiple of 16 bytes. */
                rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16);
-               dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length,
-                              DMA_FROM_DEVICE);
-               rxdesc->addr = virt_to_phys(skb->data);
+               dma_addr = dma_map_single(&ndev->dev, skb->data,
+                                         rxdesc->buffer_length,
+                                         DMA_FROM_DEVICE);
+               if (dma_mapping_error(&ndev->dev, dma_addr)) {
+                       kfree_skb(skb);
+                       break;
+               }
+               mdp->rx_skbuff[i] = skb;
+               rxdesc->addr = dma_addr;
                rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
 
                /* Rx descriptor address set */
@@ -1294,7 +1310,7 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
        /* Frame recv control (enable multiple-packets per rx irq) */
        sh_eth_write(ndev, RMCR_RNC, RMCR);
 
-       sh_eth_write(ndev, DESC_I_RINT8 | DESC_I_RINT5 | DESC_I_TINT2, TRSCER);
+       sh_eth_write(ndev, mdp->cd->trscer_err_mask, TRSCER);
 
        if (mdp->cd->bculr)
                sh_eth_write(ndev, 0x800, BCULR);       /* Burst sycle set */
@@ -1309,8 +1325,10 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
                     RFLR);
 
        sh_eth_write(ndev, sh_eth_read(ndev, EESR), EESR);
-       if (start)
+       if (start) {
+               mdp->irq_enabled = true;
                sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
+       }
 
        /* PAUSE Prohibition */
        val = (sh_eth_read(ndev, ECMR) & ECMR_DM) |
@@ -1349,6 +1367,33 @@ static int sh_eth_dev_init(struct net_device *ndev, bool start)
        return ret;
 }
 
+static void sh_eth_dev_exit(struct net_device *ndev)
+{
+       struct sh_eth_private *mdp = netdev_priv(ndev);
+       int i;
+
+       /* Deactivate all TX descriptors, so DMA should stop at next
+        * packet boundary if it's currently running
+        */
+       for (i = 0; i < mdp->num_tx_ring; i++)
+               mdp->tx_ring[i].status &= ~cpu_to_edmac(mdp, TD_TACT);
+
+       /* Disable TX FIFO egress to MAC */
+       sh_eth_rcv_snd_disable(ndev);
+
+       /* Stop RX DMA at next packet boundary */
+       sh_eth_write(ndev, 0, EDRRR);
+
+       /* Aside from TX DMA, we can't tell when the hardware is
+        * really stopped, so we need to reset to make sure.
+        * Before doing that, wait for long enough to *probably*
+        * finish transmitting the last packet and poll stats.
+        */
+       msleep(2); /* max frame time at 10 Mbps < 1250 us */
+       sh_eth_get_stats(ndev);
+       sh_eth_reset(ndev);
+}
+
 /* free Tx skb function */
 static int sh_eth_txfree(struct net_device *ndev)
 {
@@ -1393,6 +1438,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
        u16 pkt_len = 0;
        u32 desc_status;
        int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1;
+       dma_addr_t dma_addr;
 
        boguscnt = min(boguscnt, *quota);
        limit = boguscnt;
@@ -1440,9 +1486,9 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
                        mdp->rx_skbuff[entry] = NULL;
                        if (mdp->cd->rpadir)
                                skb_reserve(skb, NET_IP_ALIGN);
-                       dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr,
-                                               ALIGN(mdp->rx_buf_sz, 16),
-                                               DMA_FROM_DEVICE);
+                       dma_unmap_single(&ndev->dev, rxdesc->addr,
+                                        ALIGN(mdp->rx_buf_sz, 16),
+                                        DMA_FROM_DEVICE);
                        skb_put(skb, pkt_len);
                        skb->protocol = eth_type_trans(skb, ndev);
                        netif_receive_skb(skb);
@@ -1462,15 +1508,20 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
 
                if (mdp->rx_skbuff[entry] == NULL) {
                        skb = netdev_alloc_skb(ndev, skbuff_size);
-                       mdp->rx_skbuff[entry] = skb;
                        if (skb == NULL)
                                break;  /* Better luck next round. */
                        sh_eth_set_receive_align(skb);
-                       dma_map_single(&ndev->dev, skb->data,
-                                      rxdesc->buffer_length, DMA_FROM_DEVICE);
+                       dma_addr = dma_map_single(&ndev->dev, skb->data,
+                                                 rxdesc->buffer_length,
+                                                 DMA_FROM_DEVICE);
+                       if (dma_mapping_error(&ndev->dev, dma_addr)) {
+                               kfree_skb(skb);
+                               break;
+                       }
+                       mdp->rx_skbuff[entry] = skb;
 
                        skb_checksum_none_assert(skb);
-                       rxdesc->addr = virt_to_phys(skb->data);
+                       rxdesc->addr = dma_addr;
                }
                if (entry >= mdp->num_rx_ring - 1)
                        rxdesc->status |=
@@ -1566,7 +1617,6 @@ ignore_link:
                if (intr_status & EESR_RFRMER) {
                        /* Receive Frame Overflow int */
                        ndev->stats.rx_frame_errors++;
-                       netif_err(mdp, rx_err, ndev, "Receive Abort\n");
                }
        }
 
@@ -1585,13 +1635,11 @@ ignore_link:
        if (intr_status & EESR_RDE) {
                /* Receive Descriptor Empty int */
                ndev->stats.rx_over_errors++;
-               netif_err(mdp, rx_err, ndev, "Receive Descriptor Empty\n");
        }
 
        if (intr_status & EESR_RFE) {
                /* Receive FIFO Overflow int */
                ndev->stats.rx_fifo_errors++;
-               netif_err(mdp, rx_err, ndev, "Receive FIFO Overflow\n");
        }
 
        if (!mdp->cd->no_ade && (intr_status & EESR_ADE)) {
@@ -1646,7 +1694,12 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
        if (intr_status & (EESR_RX_CHECK | cd->tx_check | cd->eesr_err_check))
                ret = IRQ_HANDLED;
        else
-               goto other_irq;
+               goto out;
+
+       if (!likely(mdp->irq_enabled)) {
+               sh_eth_write(ndev, 0, EESIPR);
+               goto out;
+       }
 
        if (intr_status & EESR_RX_CHECK) {
                if (napi_schedule_prep(&mdp->napi)) {
@@ -1677,7 +1730,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
                sh_eth_error(ndev, intr_status);
        }
 
-other_irq:
+out:
        spin_unlock(&mdp->lock);
 
        return ret;
@@ -1705,7 +1758,8 @@ static int sh_eth_poll(struct napi_struct *napi, int budget)
        napi_complete(napi);
 
        /* Reenable Rx interrupts */
-       sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
+       if (mdp->irq_enabled)
+               sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
 out:
        return budget - quota;
 }
@@ -1820,6 +1874,9 @@ static int sh_eth_get_settings(struct net_device *ndev,
        unsigned long flags;
        int ret;
 
+       if (!mdp->phydev)
+               return -ENODEV;
+
        spin_lock_irqsave(&mdp->lock, flags);
        ret = phy_ethtool_gset(mdp->phydev, ecmd);
        spin_unlock_irqrestore(&mdp->lock, flags);
@@ -1834,6 +1891,9 @@ static int sh_eth_set_settings(struct net_device *ndev,
        unsigned long flags;
        int ret;
 
+       if (!mdp->phydev)
+               return -ENODEV;
+
        spin_lock_irqsave(&mdp->lock, flags);
 
        /* disable tx and rx */
@@ -1868,6 +1928,9 @@ static int sh_eth_nway_reset(struct net_device *ndev)
        unsigned long flags;
        int ret;
 
+       if (!mdp->phydev)
+               return -ENODEV;
+
        spin_lock_irqsave(&mdp->lock, flags);
        ret = phy_start_aneg(mdp->phydev);
        spin_unlock_irqrestore(&mdp->lock, flags);
@@ -1952,40 +2015,50 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
                return -EINVAL;
 
        if (netif_running(ndev)) {
+               netif_device_detach(ndev);
                netif_tx_disable(ndev);
-               /* Disable interrupts by clearing the interrupt mask. */
-               sh_eth_write(ndev, 0x0000, EESIPR);
-               /* Stop the chip's Tx and Rx processes. */
-               sh_eth_write(ndev, 0, EDTRR);
-               sh_eth_write(ndev, 0, EDRRR);
+
+               /* Serialise with the interrupt handler and NAPI, then
+                * disable interrupts.  We have to clear the
+                * irq_enabled flag first to ensure that interrupts
+                * won't be re-enabled.
+                */
+               mdp->irq_enabled = false;
                synchronize_irq(ndev->irq);
-       }
+               napi_synchronize(&mdp->napi);
+               sh_eth_write(ndev, 0x0000, EESIPR);
 
-       /* Free all the skbuffs in the Rx queue. */
-       sh_eth_ring_free(ndev);
-       /* Free DMA buffer */
-       sh_eth_free_dma_buffer(mdp);
+               sh_eth_dev_exit(ndev);
+
+               /* Free all the skbuffs in the Rx queue. */
+               sh_eth_ring_free(ndev);
+               /* Free DMA buffer */
+               sh_eth_free_dma_buffer(mdp);
+       }
 
        /* Set new parameters */
        mdp->num_rx_ring = ring->rx_pending;
        mdp->num_tx_ring = ring->tx_pending;
 
-       ret = sh_eth_ring_init(ndev);
-       if (ret < 0) {
-               netdev_err(ndev, "%s: sh_eth_ring_init failed.\n", __func__);
-               return ret;
-       }
-       ret = sh_eth_dev_init(ndev, false);
-       if (ret < 0) {
-               netdev_err(ndev, "%s: sh_eth_dev_init failed.\n", __func__);
-               return ret;
-       }
-
        if (netif_running(ndev)) {
+               ret = sh_eth_ring_init(ndev);
+               if (ret < 0) {
+                       netdev_err(ndev, "%s: sh_eth_ring_init failed.\n",
+                                  __func__);
+                       return ret;
+               }
+               ret = sh_eth_dev_init(ndev, false);
+               if (ret < 0) {
+                       netdev_err(ndev, "%s: sh_eth_dev_init failed.\n",
+                                  __func__);
+                       return ret;
+               }
+
+               mdp->irq_enabled = true;
                sh_eth_write(ndev, mdp->cd->eesipr_value, EESIPR);
                /* Setting the Rx mode will start the Rx process. */
                sh_eth_write(ndev, EDRRR_R, EDRRR);
-               netif_wake_queue(ndev);
+               netif_device_attach(ndev);
        }
 
        return 0;
@@ -2101,6 +2174,9 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
        }
        spin_unlock_irqrestore(&mdp->lock, flags);
 
+       if (skb_padto(skb, ETH_ZLEN))
+               return NETDEV_TX_OK;
+
        entry = mdp->cur_tx % mdp->num_tx_ring;
        mdp->tx_skbuff[entry] = skb;
        txdesc = &mdp->tx_ring[entry];
@@ -2110,10 +2186,11 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                                 skb->len + 2);
        txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
                                      DMA_TO_DEVICE);
-       if (skb->len < ETH_ZLEN)
-               txdesc->buffer_length = ETH_ZLEN;
-       else
-               txdesc->buffer_length = skb->len;
+       if (dma_mapping_error(&ndev->dev, txdesc->addr)) {
+               kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+       txdesc->buffer_length = skb->len;
 
        if (entry >= mdp->num_tx_ring - 1)
                txdesc->status |= cpu_to_edmac(mdp, TD_TACT | TD_TDLE);
@@ -2165,24 +2242,26 @@ static int sh_eth_close(struct net_device *ndev)
 
        netif_stop_queue(ndev);
 
-       /* Disable interrupts by clearing the interrupt mask. */
+       /* Serialise with the interrupt handler and NAPI, then disable
+        * interrupts.  We have to clear the irq_enabled flag first to
+        * ensure that interrupts won't be re-enabled.
+        */
+       mdp->irq_enabled = false;
+       synchronize_irq(ndev->irq);
+       napi_disable(&mdp->napi);
        sh_eth_write(ndev, 0x0000, EESIPR);
 
-       /* Stop the chip's Tx and Rx processes. */
-       sh_eth_write(ndev, 0, EDTRR);
-       sh_eth_write(ndev, 0, EDRRR);
+       sh_eth_dev_exit(ndev);
 
-       sh_eth_get_stats(ndev);
        /* PHY Disconnect */
        if (mdp->phydev) {
                phy_stop(mdp->phydev);
                phy_disconnect(mdp->phydev);
+               mdp->phydev = NULL;
        }
 
        free_irq(ndev->irq, ndev);
 
-       napi_disable(&mdp->napi);
-
        /* Free all the skbuffs in the Rx queue. */
        sh_eth_ring_free(ndev);
 
@@ -2410,7 +2489,7 @@ static int sh_eth_tsu_purge_all(struct net_device *ndev)
        struct sh_eth_private *mdp = netdev_priv(ndev);
        int i, ret;
 
-       if (unlikely(!mdp->cd->tsu))
+       if (!mdp->cd->tsu)
                return 0;
 
        for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++) {
@@ -2433,7 +2512,7 @@ static void sh_eth_tsu_purge_mcast(struct net_device *ndev)
        void *reg_offset = sh_eth_tsu_get_offset(mdp, TSU_ADRH0);
        int i;
 
-       if (unlikely(!mdp->cd->tsu))
+       if (!mdp->cd->tsu)
                return;
 
        for (i = 0; i < SH_ETH_TSU_CAM_ENTRIES; i++, reg_offset += 8) {
@@ -2443,8 +2522,8 @@ static void sh_eth_tsu_purge_mcast(struct net_device *ndev)
        }
 }
 
-/* Multicast reception directions set */
-static void sh_eth_set_multicast_list(struct net_device *ndev)
+/* Update promiscuous flag and multicast filter */
+static void sh_eth_set_rx_mode(struct net_device *ndev)
 {
        struct sh_eth_private *mdp = netdev_priv(ndev);
        u32 ecmr_bits;
@@ -2455,7 +2534,9 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)
        /* Initial condition is MCT = 1, PRM = 0.
         * Depending on ndev->flags, set PRM or clear MCT
         */
-       ecmr_bits = (sh_eth_read(ndev, ECMR) & ~ECMR_PRM) | ECMR_MCT;
+       ecmr_bits = sh_eth_read(ndev, ECMR) & ~ECMR_PRM;
+       if (mdp->cd->tsu)
+               ecmr_bits |= ECMR_MCT;
 
        if (!(ndev->flags & IFF_MULTICAST)) {
                sh_eth_tsu_purge_mcast(ndev);
@@ -2484,9 +2565,6 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)
                                }
                        }
                }
-       } else {
-               /* Normal, unicast/broadcast-only mode. */
-               ecmr_bits = (ecmr_bits & ~ECMR_PRM) | ECMR_MCT;
        }
 
        /* update the ethernet mode */
@@ -2694,6 +2772,7 @@ static const struct net_device_ops sh_eth_netdev_ops = {
        .ndo_stop               = sh_eth_close,
        .ndo_start_xmit         = sh_eth_start_xmit,
        .ndo_get_stats          = sh_eth_get_stats,
+       .ndo_set_rx_mode        = sh_eth_set_rx_mode,
        .ndo_tx_timeout         = sh_eth_tx_timeout,
        .ndo_do_ioctl           = sh_eth_do_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
@@ -2706,7 +2785,7 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = {
        .ndo_stop               = sh_eth_close,
        .ndo_start_xmit         = sh_eth_start_xmit,
        .ndo_get_stats          = sh_eth_get_stats,
-       .ndo_set_rx_mode        = sh_eth_set_multicast_list,
+       .ndo_set_rx_mode        = sh_eth_set_rx_mode,
        .ndo_vlan_rx_add_vid    = sh_eth_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = sh_eth_vlan_rx_kill_vid,
        .ndo_tx_timeout         = sh_eth_tx_timeout,
index 22301bf9c21daeb925d75aa7ce5c7a588d977e11..332d3c16d48388ec9ae9281ec07f8310dcbce671 100644 (file)
@@ -369,6 +369,8 @@ enum DESC_I_BIT {
        DESC_I_RINT1 = 0x0001,
 };
 
+#define DEFAULT_TRSCER_ERR_MASK (DESC_I_RINT8 | DESC_I_RINT5 | DESC_I_TINT2)
+
 /* RPADIR */
 enum RPADIR_BIT {
        RPADIR_PADS1 = 0x20000, RPADIR_PADS0 = 0x10000,
@@ -470,6 +472,9 @@ struct sh_eth_cpu_data {
        unsigned long tx_check;
        unsigned long eesr_err_check;
 
+       /* Error mask */
+       unsigned long trscer_err_mask;
+
        /* hardware features */
        unsigned long irq_flags; /* IRQ configuration flags */
        unsigned no_psr:1;      /* EtherC DO NOT have PSR */
@@ -508,6 +513,7 @@ struct sh_eth_private {
        u32 rx_buf_sz;                  /* Based on MTU+slack. */
        int edmac_endian;
        struct napi_struct napi;
+       bool irq_enabled;
        /* MII transceiver section. */
        u32 phy_id;                     /* PHY ID */
        struct mii_bus *mii_bus;        /* MDIO bus control */
diff --git a/drivers/net/ethernet/s6gmac.c b/drivers/net/ethernet/s6gmac.c
deleted file mode 100644 (file)
index f537cbe..0000000
+++ /dev/null
@@ -1,1058 +0,0 @@
-/*
- * Ethernet driver for S6105 on chip network device
- * (c)2008 emlix GmbH http://www.emlix.com
- * Authors:    Oskar Schirmer <oskar@scara.com>
- *             Daniel Gloeckner <dg@emlix.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/if.h>
-#include <linux/stddef.h>
-#include <linux/mii.h>
-#include <linux/phy.h>
-#include <linux/platform_device.h>
-#include <variant/hardware.h>
-#include <variant/dmac.h>
-
-#define DRV_NAME "s6gmac"
-#define DRV_PRMT DRV_NAME ": "
-
-
-/* register declarations */
-
-#define S6_GMAC_MACCONF1       0x000
-#define S6_GMAC_MACCONF1_TXENA         0
-#define S6_GMAC_MACCONF1_SYNCTX                1
-#define S6_GMAC_MACCONF1_RXENA         2
-#define S6_GMAC_MACCONF1_SYNCRX                3
-#define S6_GMAC_MACCONF1_TXFLOWCTRL    4
-#define S6_GMAC_MACCONF1_RXFLOWCTRL    5
-#define S6_GMAC_MACCONF1_LOOPBACK      8
-#define S6_GMAC_MACCONF1_RESTXFUNC     16
-#define S6_GMAC_MACCONF1_RESRXFUNC     17
-#define S6_GMAC_MACCONF1_RESTXMACCTRL  18
-#define S6_GMAC_MACCONF1_RESRXMACCTRL  19
-#define S6_GMAC_MACCONF1_SIMULRES      30
-#define S6_GMAC_MACCONF1_SOFTRES       31
-#define S6_GMAC_MACCONF2       0x004
-#define S6_GMAC_MACCONF2_FULL          0
-#define S6_GMAC_MACCONF2_CRCENA                1
-#define S6_GMAC_MACCONF2_PADCRCENA     2
-#define S6_GMAC_MACCONF2_LENGTHFCHK    4
-#define S6_GMAC_MACCONF2_HUGEFRAMENA   5
-#define S6_GMAC_MACCONF2_IFMODE                8
-#define S6_GMAC_MACCONF2_IFMODE_NIBBLE         1
-#define S6_GMAC_MACCONF2_IFMODE_BYTE           2
-#define S6_GMAC_MACCONF2_IFMODE_MASK           3
-#define S6_GMAC_MACCONF2_PREAMBLELEN   12
-#define S6_GMAC_MACCONF2_PREAMBLELEN_MASK      0x0F
-#define S6_GMAC_MACIPGIFG      0x008
-#define S6_GMAC_MACIPGIFG_B2BINTERPGAP 0
-#define S6_GMAC_MACIPGIFG_B2BINTERPGAP_MASK    0x7F
-#define S6_GMAC_MACIPGIFG_MINIFGENFORCE        8
-#define S6_GMAC_MACIPGIFG_B2BINTERPGAP2        16
-#define S6_GMAC_MACIPGIFG_B2BINTERPGAP1        24
-#define S6_GMAC_MACHALFDUPLEX  0x00C
-#define S6_GMAC_MACHALFDUPLEX_COLLISWIN        0
-#define S6_GMAC_MACHALFDUPLEX_COLLISWIN_MASK   0x3F
-#define S6_GMAC_MACHALFDUPLEX_RETXMAX  12
-#define S6_GMAC_MACHALFDUPLEX_RETXMAX_MASK     0x0F
-#define S6_GMAC_MACHALFDUPLEX_EXCESSDEF        16
-#define S6_GMAC_MACHALFDUPLEX_NOBACKOFF        17
-#define S6_GMAC_MACHALFDUPLEX_BPNOBCKOF        18
-#define S6_GMAC_MACHALFDUPLEX_ALTBEBENA        19
-#define S6_GMAC_MACHALFDUPLEX_ALTBEBTRN        20
-#define S6_GMAC_MACHALFDUPLEX_ALTBEBTR_MASK    0x0F
-#define S6_GMAC_MACMAXFRAMELEN 0x010
-#define S6_GMAC_MACMIICONF     0x020
-#define S6_GMAC_MACMIICONF_CSEL                0
-#define S6_GMAC_MACMIICONF_CSEL_DIV10          0
-#define S6_GMAC_MACMIICONF_CSEL_DIV12          1
-#define S6_GMAC_MACMIICONF_CSEL_DIV14          2
-#define S6_GMAC_MACMIICONF_CSEL_DIV18          3
-#define S6_GMAC_MACMIICONF_CSEL_DIV24          4
-#define S6_GMAC_MACMIICONF_CSEL_DIV34          5
-#define S6_GMAC_MACMIICONF_CSEL_DIV68          6
-#define S6_GMAC_MACMIICONF_CSEL_DIV168         7
-#define S6_GMAC_MACMIICONF_CSEL_MASK           7
-#define S6_GMAC_MACMIICONF_PREAMBLESUPR        4
-#define S6_GMAC_MACMIICONF_SCANAUTOINCR        5
-#define S6_GMAC_MACMIICMD      0x024
-#define S6_GMAC_MACMIICMD_READ         0
-#define S6_GMAC_MACMIICMD_SCAN         1
-#define S6_GMAC_MACMIIADDR     0x028
-#define S6_GMAC_MACMIIADDR_REG         0
-#define S6_GMAC_MACMIIADDR_REG_MASK            0x1F
-#define S6_GMAC_MACMIIADDR_PHY         8
-#define S6_GMAC_MACMIIADDR_PHY_MASK            0x1F
-#define S6_GMAC_MACMIICTRL     0x02C
-#define S6_GMAC_MACMIISTAT     0x030
-#define S6_GMAC_MACMIIINDI     0x034
-#define S6_GMAC_MACMIIINDI_BUSY                0
-#define S6_GMAC_MACMIIINDI_SCAN                1
-#define S6_GMAC_MACMIIINDI_INVAL       2
-#define S6_GMAC_MACINTERFSTAT  0x03C
-#define S6_GMAC_MACINTERFSTAT_LINKFAIL 3
-#define S6_GMAC_MACINTERFSTAT_EXCESSDEF        9
-#define S6_GMAC_MACSTATADDR1   0x040
-#define S6_GMAC_MACSTATADDR2   0x044
-
-#define S6_GMAC_FIFOCONF0      0x048
-#define S6_GMAC_FIFOCONF0_HSTRSTWT     0
-#define S6_GMAC_FIFOCONF0_HSTRSTSR     1
-#define S6_GMAC_FIFOCONF0_HSTRSTFR     2
-#define S6_GMAC_FIFOCONF0_HSTRSTST     3
-#define S6_GMAC_FIFOCONF0_HSTRSTFT     4
-#define S6_GMAC_FIFOCONF0_WTMENREQ     8
-#define S6_GMAC_FIFOCONF0_SRFENREQ     9
-#define S6_GMAC_FIFOCONF0_FRFENREQ     10
-#define S6_GMAC_FIFOCONF0_STFENREQ     11
-#define S6_GMAC_FIFOCONF0_FTFENREQ     12
-#define S6_GMAC_FIFOCONF0_WTMENRPLY    16
-#define S6_GMAC_FIFOCONF0_SRFENRPLY    17
-#define S6_GMAC_FIFOCONF0_FRFENRPLY    18
-#define S6_GMAC_FIFOCONF0_STFENRPLY    19
-#define S6_GMAC_FIFOCONF0_FTFENRPLY    20
-#define S6_GMAC_FIFOCONF1      0x04C
-#define S6_GMAC_FIFOCONF2      0x050
-#define S6_GMAC_FIFOCONF2_CFGLWM       0
-#define S6_GMAC_FIFOCONF2_CFGHWM       16
-#define S6_GMAC_FIFOCONF3      0x054
-#define S6_GMAC_FIFOCONF3_CFGFTTH      0
-#define S6_GMAC_FIFOCONF3_CFGHWMFT     16
-#define S6_GMAC_FIFOCONF4      0x058
-#define S6_GMAC_FIFOCONF_RSV_PREVDROP  0
-#define S6_GMAC_FIFOCONF_RSV_RUNT      1
-#define S6_GMAC_FIFOCONF_RSV_FALSECAR  2
-#define S6_GMAC_FIFOCONF_RSV_CODEERR   3
-#define S6_GMAC_FIFOCONF_RSV_CRCERR    4
-#define S6_GMAC_FIFOCONF_RSV_LENGTHERR 5
-#define S6_GMAC_FIFOCONF_RSV_LENRANGE  6
-#define S6_GMAC_FIFOCONF_RSV_OK                7
-#define S6_GMAC_FIFOCONF_RSV_MULTICAST 8
-#define S6_GMAC_FIFOCONF_RSV_BROADCAST 9
-#define S6_GMAC_FIFOCONF_RSV_DRIBBLE   10
-#define S6_GMAC_FIFOCONF_RSV_CTRLFRAME 11
-#define S6_GMAC_FIFOCONF_RSV_PAUSECTRL 12
-#define S6_GMAC_FIFOCONF_RSV_UNOPCODE  13
-#define S6_GMAC_FIFOCONF_RSV_VLANTAG   14
-#define S6_GMAC_FIFOCONF_RSV_LONGEVENT 15
-#define S6_GMAC_FIFOCONF_RSV_TRUNCATED 16
-#define S6_GMAC_FIFOCONF_RSV_MASK              0x3FFFF
-#define S6_GMAC_FIFOCONF5      0x05C
-#define S6_GMAC_FIFOCONF5_DROPLT64     18
-#define S6_GMAC_FIFOCONF5_CFGBYTM      19
-#define S6_GMAC_FIFOCONF5_RXDROPSIZE   20
-#define S6_GMAC_FIFOCONF5_RXDROPSIZE_MASK      0xF
-
-#define S6_GMAC_STAT_REGS      0x080
-#define S6_GMAC_STAT_SIZE_MIN          12
-#define S6_GMAC_STATTR64       0x080
-#define S6_GMAC_STATTR64_SIZE          18
-#define S6_GMAC_STATTR127      0x084
-#define S6_GMAC_STATTR127_SIZE         18
-#define S6_GMAC_STATTR255      0x088
-#define S6_GMAC_STATTR255_SIZE         18
-#define S6_GMAC_STATTR511      0x08C
-#define S6_GMAC_STATTR511_SIZE         18
-#define S6_GMAC_STATTR1K       0x090
-#define S6_GMAC_STATTR1K_SIZE          18
-#define S6_GMAC_STATTRMAX      0x094
-#define S6_GMAC_STATTRMAX_SIZE         18
-#define S6_GMAC_STATTRMGV      0x098
-#define S6_GMAC_STATTRMGV_SIZE         18
-#define S6_GMAC_STATRBYT       0x09C
-#define S6_GMAC_STATRBYT_SIZE          24
-#define S6_GMAC_STATRPKT       0x0A0
-#define S6_GMAC_STATRPKT_SIZE          18
-#define S6_GMAC_STATRFCS       0x0A4
-#define S6_GMAC_STATRFCS_SIZE          12
-#define S6_GMAC_STATRMCA       0x0A8
-#define S6_GMAC_STATRMCA_SIZE          18
-#define S6_GMAC_STATRBCA       0x0AC
-#define S6_GMAC_STATRBCA_SIZE          22
-#define S6_GMAC_STATRXCF       0x0B0
-#define S6_GMAC_STATRXCF_SIZE          18
-#define S6_GMAC_STATRXPF       0x0B4
-#define S6_GMAC_STATRXPF_SIZE          12
-#define S6_GMAC_STATRXUO       0x0B8
-#define S6_GMAC_STATRXUO_SIZE          12
-#define S6_GMAC_STATRALN       0x0BC
-#define S6_GMAC_STATRALN_SIZE          12
-#define S6_GMAC_STATRFLR       0x0C0
-#define S6_GMAC_STATRFLR_SIZE          16
-#define S6_GMAC_STATRCDE       0x0C4
-#define S6_GMAC_STATRCDE_SIZE          12
-#define S6_GMAC_STATRCSE       0x0C8
-#define S6_GMAC_STATRCSE_SIZE          12
-#define S6_GMAC_STATRUND       0x0CC
-#define S6_GMAC_STATRUND_SIZE          12
-#define S6_GMAC_STATROVR       0x0D0
-#define S6_GMAC_STATROVR_SIZE          12
-#define S6_GMAC_STATRFRG       0x0D4
-#define S6_GMAC_STATRFRG_SIZE          12
-#define S6_GMAC_STATRJBR       0x0D8
-#define S6_GMAC_STATRJBR_SIZE          12
-#define S6_GMAC_STATRDRP       0x0DC
-#define S6_GMAC_STATRDRP_SIZE          12
-#define S6_GMAC_STATTBYT       0x0E0
-#define S6_GMAC_STATTBYT_SIZE          24
-#define S6_GMAC_STATTPKT       0x0E4
-#define S6_GMAC_STATTPKT_SIZE          18
-#define S6_GMAC_STATTMCA       0x0E8
-#define S6_GMAC_STATTMCA_SIZE          18
-#define S6_GMAC_STATTBCA       0x0EC
-#define S6_GMAC_STATTBCA_SIZE          18
-#define S6_GMAC_STATTXPF       0x0F0
-#define S6_GMAC_STATTXPF_SIZE          12
-#define S6_GMAC_STATTDFR       0x0F4
-#define S6_GMAC_STATTDFR_SIZE          12
-#define S6_GMAC_STATTEDF       0x0F8
-#define S6_GMAC_STATTEDF_SIZE          12
-#define S6_GMAC_STATTSCL       0x0FC
-#define S6_GMAC_STATTSCL_SIZE          12
-#define S6_GMAC_STATTMCL       0x100
-#define S6_GMAC_STATTMCL_SIZE          12
-#define S6_GMAC_STATTLCL       0x104
-#define S6_GMAC_STATTLCL_SIZE          12
-#define S6_GMAC_STATTXCL       0x108
-#define S6_GMAC_STATTXCL_SIZE          12
-#define S6_GMAC_STATTNCL       0x10C
-#define S6_GMAC_STATTNCL_SIZE          13
-#define S6_GMAC_STATTPFH       0x110
-#define S6_GMAC_STATTPFH_SIZE          12
-#define S6_GMAC_STATTDRP       0x114
-#define S6_GMAC_STATTDRP_SIZE          12
-#define S6_GMAC_STATTJBR       0x118
-#define S6_GMAC_STATTJBR_SIZE          12
-#define S6_GMAC_STATTFCS       0x11C
-#define S6_GMAC_STATTFCS_SIZE          12
-#define S6_GMAC_STATTXCF       0x120
-#define S6_GMAC_STATTXCF_SIZE          12
-#define S6_GMAC_STATTOVR       0x124
-#define S6_GMAC_STATTOVR_SIZE          12
-#define S6_GMAC_STATTUND       0x128
-#define S6_GMAC_STATTUND_SIZE          12
-#define S6_GMAC_STATTFRG       0x12C
-#define S6_GMAC_STATTFRG_SIZE          12
-#define S6_GMAC_STATCARRY(n)   (0x130 + 4*(n))
-#define S6_GMAC_STATCARRYMSK(n)        (0x138 + 4*(n))
-#define S6_GMAC_STATCARRY1_RDRP                0
-#define S6_GMAC_STATCARRY1_RJBR                1
-#define S6_GMAC_STATCARRY1_RFRG                2
-#define S6_GMAC_STATCARRY1_ROVR                3
-#define S6_GMAC_STATCARRY1_RUND                4
-#define S6_GMAC_STATCARRY1_RCSE                5
-#define S6_GMAC_STATCARRY1_RCDE                6
-#define S6_GMAC_STATCARRY1_RFLR                7
-#define S6_GMAC_STATCARRY1_RALN                8
-#define S6_GMAC_STATCARRY1_RXUO                9
-#define S6_GMAC_STATCARRY1_RXPF                10
-#define S6_GMAC_STATCARRY1_RXCF                11
-#define S6_GMAC_STATCARRY1_RBCA                12
-#define S6_GMAC_STATCARRY1_RMCA                13
-#define S6_GMAC_STATCARRY1_RFCS                14
-#define S6_GMAC_STATCARRY1_RPKT                15
-#define S6_GMAC_STATCARRY1_RBYT                16
-#define S6_GMAC_STATCARRY1_TRMGV       25
-#define S6_GMAC_STATCARRY1_TRMAX       26
-#define S6_GMAC_STATCARRY1_TR1K                27
-#define S6_GMAC_STATCARRY1_TR511       28
-#define S6_GMAC_STATCARRY1_TR255       29
-#define S6_GMAC_STATCARRY1_TR127       30
-#define S6_GMAC_STATCARRY1_TR64                31
-#define S6_GMAC_STATCARRY2_TDRP                0
-#define S6_GMAC_STATCARRY2_TPFH                1
-#define S6_GMAC_STATCARRY2_TNCL                2
-#define S6_GMAC_STATCARRY2_TXCL                3
-#define S6_GMAC_STATCARRY2_TLCL                4
-#define S6_GMAC_STATCARRY2_TMCL                5
-#define S6_GMAC_STATCARRY2_TSCL                6
-#define S6_GMAC_STATCARRY2_TEDF                7
-#define S6_GMAC_STATCARRY2_TDFR                8
-#define S6_GMAC_STATCARRY2_TXPF                9
-#define S6_GMAC_STATCARRY2_TBCA                10
-#define S6_GMAC_STATCARRY2_TMCA                11
-#define S6_GMAC_STATCARRY2_TPKT                12
-#define S6_GMAC_STATCARRY2_TBYT                13
-#define S6_GMAC_STATCARRY2_TFRG                14
-#define S6_GMAC_STATCARRY2_TUND                15
-#define S6_GMAC_STATCARRY2_TOVR                16
-#define S6_GMAC_STATCARRY2_TXCF                17
-#define S6_GMAC_STATCARRY2_TFCS                18
-#define S6_GMAC_STATCARRY2_TJBR                19
-
-#define S6_GMAC_HOST_PBLKCTRL  0x140
-#define S6_GMAC_HOST_PBLKCTRL_TXENA    0
-#define S6_GMAC_HOST_PBLKCTRL_RXENA    1
-#define S6_GMAC_HOST_PBLKCTRL_TXSRES   2
-#define S6_GMAC_HOST_PBLKCTRL_RXSRES   3
-#define S6_GMAC_HOST_PBLKCTRL_TXBSIZ   8
-#define S6_GMAC_HOST_PBLKCTRL_RXBSIZ   12
-#define S6_GMAC_HOST_PBLKCTRL_SIZ_16           4
-#define S6_GMAC_HOST_PBLKCTRL_SIZ_32           5
-#define S6_GMAC_HOST_PBLKCTRL_SIZ_64           6
-#define S6_GMAC_HOST_PBLKCTRL_SIZ_128          7
-#define S6_GMAC_HOST_PBLKCTRL_SIZ_MASK         0xF
-#define S6_GMAC_HOST_PBLKCTRL_STATENA  16
-#define S6_GMAC_HOST_PBLKCTRL_STATAUTOZ        17
-#define S6_GMAC_HOST_PBLKCTRL_STATCLEAR        18
-#define S6_GMAC_HOST_PBLKCTRL_RGMII    19
-#define S6_GMAC_HOST_INTMASK   0x144
-#define S6_GMAC_HOST_INTSTAT   0x148
-#define S6_GMAC_HOST_INT_TXBURSTOVER   3
-#define S6_GMAC_HOST_INT_TXPREWOVER    4
-#define S6_GMAC_HOST_INT_RXBURSTUNDER  5
-#define S6_GMAC_HOST_INT_RXPOSTRFULL   6
-#define S6_GMAC_HOST_INT_RXPOSTRUNDER  7
-#define S6_GMAC_HOST_RXFIFOHWM 0x14C
-#define S6_GMAC_HOST_CTRLFRAMXP        0x150
-#define S6_GMAC_HOST_DSTADDRLO(n) (0x160 + 8*(n))
-#define S6_GMAC_HOST_DSTADDRHI(n) (0x164 + 8*(n))
-#define S6_GMAC_HOST_DSTMASKLO(n) (0x180 + 8*(n))
-#define S6_GMAC_HOST_DSTMASKHI(n) (0x184 + 8*(n))
-
-#define S6_GMAC_BURST_PREWR    0x1B0
-#define S6_GMAC_BURST_PREWR_LEN                0
-#define S6_GMAC_BURST_PREWR_LEN_MASK           ((1 << 20) - 1)
-#define S6_GMAC_BURST_PREWR_CFE                20
-#define S6_GMAC_BURST_PREWR_PPE                21
-#define S6_GMAC_BURST_PREWR_FCS                22
-#define S6_GMAC_BURST_PREWR_PAD                23
-#define S6_GMAC_BURST_POSTRD   0x1D0
-#define S6_GMAC_BURST_POSTRD_LEN       0
-#define S6_GMAC_BURST_POSTRD_LEN_MASK          ((1 << 20) - 1)
-#define S6_GMAC_BURST_POSTRD_DROP      20
-
-
-/* data handling */
-
-#define S6_NUM_TX_SKB  8       /* must be larger than TX fifo size */
-#define S6_NUM_RX_SKB  16
-#define S6_MAX_FRLEN   1536
-
-struct s6gmac {
-       u32 reg;
-       u32 tx_dma;
-       u32 rx_dma;
-       u32 io;
-       u8 tx_chan;
-       u8 rx_chan;
-       spinlock_t lock;
-       u8 tx_skb_i, tx_skb_o;
-       u8 rx_skb_i, rx_skb_o;
-       struct sk_buff *tx_skb[S6_NUM_TX_SKB];
-       struct sk_buff *rx_skb[S6_NUM_RX_SKB];
-       unsigned long carry[sizeof(struct net_device_stats) / sizeof(long)];
-       unsigned long stats[sizeof(struct net_device_stats) / sizeof(long)];
-       struct phy_device *phydev;
-       struct {
-               struct mii_bus *bus;
-               int irq[PHY_MAX_ADDR];
-       } mii;
-       struct {
-               unsigned int mbit;
-               u8 giga;
-               u8 isup;
-               u8 full;
-       } link;
-};
-
-static void s6gmac_rx_fillfifo(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       struct sk_buff *skb;
-       while ((((u8)(pd->rx_skb_i - pd->rx_skb_o)) < S6_NUM_RX_SKB) &&
-              (!s6dmac_fifo_full(pd->rx_dma, pd->rx_chan)) &&
-              (skb = netdev_alloc_skb(dev, S6_MAX_FRLEN + 2))) {
-               pd->rx_skb[(pd->rx_skb_i++) % S6_NUM_RX_SKB] = skb;
-               s6dmac_put_fifo_cache(pd->rx_dma, pd->rx_chan,
-                       pd->io, (u32)skb->data, S6_MAX_FRLEN);
-       }
-}
-
-static void s6gmac_rx_interrupt(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       u32 pfx;
-       struct sk_buff *skb;
-       while (((u8)(pd->rx_skb_i - pd->rx_skb_o)) >
-                       s6dmac_pending_count(pd->rx_dma, pd->rx_chan)) {
-               skb = pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB];
-               pfx = readl(pd->reg + S6_GMAC_BURST_POSTRD);
-               if (pfx & (1 << S6_GMAC_BURST_POSTRD_DROP)) {
-                       dev_kfree_skb_irq(skb);
-               } else {
-                       skb_put(skb, (pfx >> S6_GMAC_BURST_POSTRD_LEN)
-                               & S6_GMAC_BURST_POSTRD_LEN_MASK);
-                       skb->protocol = eth_type_trans(skb, dev);
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       netif_rx(skb);
-               }
-       }
-}
-
-static void s6gmac_tx_interrupt(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       while (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >
-                       s6dmac_pending_count(pd->tx_dma, pd->tx_chan)) {
-               dev_kfree_skb_irq(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]);
-       }
-       if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan))
-               netif_wake_queue(dev);
-}
-
-struct s6gmac_statinf {
-       unsigned reg_size : 4; /* 0: unused */
-       unsigned reg_off : 6;
-       unsigned net_index : 6;
-};
-
-#define S6_STATS_B (8 * sizeof(u32))
-#define S6_STATS_C(b, r, f) [b] = { \
-       BUILD_BUG_ON_ZERO(r##_SIZE < S6_GMAC_STAT_SIZE_MIN) + \
-       BUILD_BUG_ON_ZERO((r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1)) \
-                       >= (1<<4)) + \
-       r##_SIZE - (S6_GMAC_STAT_SIZE_MIN - 1), \
-       BUILD_BUG_ON_ZERO(((unsigned)((r - S6_GMAC_STAT_REGS) / sizeof(u32))) \
-                       >= ((1<<6)-1)) + \
-       (r - S6_GMAC_STAT_REGS) / sizeof(u32), \
-       BUILD_BUG_ON_ZERO((offsetof(struct net_device_stats, f)) \
-                       % sizeof(unsigned long)) + \
-       BUILD_BUG_ON_ZERO((((unsigned)(offsetof(struct net_device_stats, f)) \
-                       / sizeof(unsigned long)) >= (1<<6))) + \
-       BUILD_BUG_ON_ZERO((sizeof(((struct net_device_stats *)0)->f) \
-                       != sizeof(unsigned long))) + \
-       (offsetof(struct net_device_stats, f)) / sizeof(unsigned long)},
-
-static const struct s6gmac_statinf statinf[2][S6_STATS_B] = { {
-       S6_STATS_C(S6_GMAC_STATCARRY1_RBYT, S6_GMAC_STATRBYT, rx_bytes)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RPKT, S6_GMAC_STATRPKT, rx_packets)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RFCS, S6_GMAC_STATRFCS, rx_crc_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RMCA, S6_GMAC_STATRMCA, multicast)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RALN, S6_GMAC_STATRALN, rx_frame_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RFLR, S6_GMAC_STATRFLR, rx_length_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RCDE, S6_GMAC_STATRCDE, rx_missed_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RUND, S6_GMAC_STATRUND, rx_length_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_ROVR, S6_GMAC_STATROVR, rx_length_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RFRG, S6_GMAC_STATRFRG, rx_crc_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RJBR, S6_GMAC_STATRJBR, rx_crc_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY1_RDRP, S6_GMAC_STATRDRP, rx_dropped)
-}, {
-       S6_STATS_C(S6_GMAC_STATCARRY2_TBYT, S6_GMAC_STATTBYT, tx_bytes)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TPKT, S6_GMAC_STATTPKT, tx_packets)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TEDF, S6_GMAC_STATTEDF, tx_aborted_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TXCL, S6_GMAC_STATTXCL, tx_aborted_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TNCL, S6_GMAC_STATTNCL, collisions)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TDRP, S6_GMAC_STATTDRP, tx_dropped)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TJBR, S6_GMAC_STATTJBR, tx_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TFCS, S6_GMAC_STATTFCS, tx_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TOVR, S6_GMAC_STATTOVR, tx_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TUND, S6_GMAC_STATTUND, tx_errors)
-       S6_STATS_C(S6_GMAC_STATCARRY2_TFRG, S6_GMAC_STATTFRG, tx_errors)
-} };
-
-static void s6gmac_stats_collect(struct s6gmac *pd,
-               const struct s6gmac_statinf *inf)
-{
-       int b;
-       for (b = 0; b < S6_STATS_B; b++) {
-               if (inf[b].reg_size) {
-                       pd->stats[inf[b].net_index] +=
-                               readl(pd->reg + S6_GMAC_STAT_REGS
-                                       + sizeof(u32) * inf[b].reg_off);
-               }
-       }
-}
-
-static void s6gmac_stats_carry(struct s6gmac *pd,
-               const struct s6gmac_statinf *inf, u32 mask)
-{
-       int b;
-       while (mask) {
-               b = fls(mask) - 1;
-               mask &= ~(1 << b);
-               pd->carry[inf[b].net_index] += (1 << inf[b].reg_size);
-       }
-}
-
-static inline u32 s6gmac_stats_pending(struct s6gmac *pd, int carry)
-{
-       int r = readl(pd->reg + S6_GMAC_STATCARRY(carry)) &
-               ~readl(pd->reg + S6_GMAC_STATCARRYMSK(carry));
-       return r;
-}
-
-static inline void s6gmac_stats_interrupt(struct s6gmac *pd, int carry)
-{
-       u32 mask;
-       mask = s6gmac_stats_pending(pd, carry);
-       if (mask) {
-               writel(mask, pd->reg + S6_GMAC_STATCARRY(carry));
-               s6gmac_stats_carry(pd, &statinf[carry][0], mask);
-       }
-}
-
-static irqreturn_t s6gmac_interrupt(int irq, void *dev_id)
-{
-       struct net_device *dev = (struct net_device *)dev_id;
-       struct s6gmac *pd = netdev_priv(dev);
-       if (!dev)
-               return IRQ_NONE;
-       spin_lock(&pd->lock);
-       if (s6dmac_termcnt_irq(pd->rx_dma, pd->rx_chan))
-               s6gmac_rx_interrupt(dev);
-       s6gmac_rx_fillfifo(dev);
-       if (s6dmac_termcnt_irq(pd->tx_dma, pd->tx_chan))
-               s6gmac_tx_interrupt(dev);
-       s6gmac_stats_interrupt(pd, 0);
-       s6gmac_stats_interrupt(pd, 1);
-       spin_unlock(&pd->lock);
-       return IRQ_HANDLED;
-}
-
-static inline void s6gmac_set_dstaddr(struct s6gmac *pd, int n,
-       u32 addrlo, u32 addrhi, u32 masklo, u32 maskhi)
-{
-       writel(addrlo, pd->reg + S6_GMAC_HOST_DSTADDRLO(n));
-       writel(addrhi, pd->reg + S6_GMAC_HOST_DSTADDRHI(n));
-       writel(masklo, pd->reg + S6_GMAC_HOST_DSTMASKLO(n));
-       writel(maskhi, pd->reg + S6_GMAC_HOST_DSTMASKHI(n));
-}
-
-static inline void s6gmac_stop_device(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       writel(0, pd->reg + S6_GMAC_MACCONF1);
-}
-
-static inline void s6gmac_init_device(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       int is_rgmii = !!(pd->phydev->supported
-               & (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half));
-#if 0
-       writel(1 << S6_GMAC_MACCONF1_SYNCTX |
-               1 << S6_GMAC_MACCONF1_SYNCRX |
-               1 << S6_GMAC_MACCONF1_TXFLOWCTRL |
-               1 << S6_GMAC_MACCONF1_RXFLOWCTRL |
-               1 << S6_GMAC_MACCONF1_RESTXFUNC |
-               1 << S6_GMAC_MACCONF1_RESRXFUNC |
-               1 << S6_GMAC_MACCONF1_RESTXMACCTRL |
-               1 << S6_GMAC_MACCONF1_RESRXMACCTRL,
-               pd->reg + S6_GMAC_MACCONF1);
-#endif
-       writel(1 << S6_GMAC_MACCONF1_SOFTRES, pd->reg + S6_GMAC_MACCONF1);
-       udelay(1000);
-       writel(1 << S6_GMAC_MACCONF1_TXENA | 1 << S6_GMAC_MACCONF1_RXENA,
-               pd->reg + S6_GMAC_MACCONF1);
-       writel(1 << S6_GMAC_HOST_PBLKCTRL_TXSRES |
-               1 << S6_GMAC_HOST_PBLKCTRL_RXSRES,
-               pd->reg + S6_GMAC_HOST_PBLKCTRL);
-       writel(S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ |
-               S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ |
-               1 << S6_GMAC_HOST_PBLKCTRL_STATENA |
-               1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR |
-               is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII,
-               pd->reg + S6_GMAC_HOST_PBLKCTRL);
-       writel(1 << S6_GMAC_MACCONF1_TXENA |
-               1 << S6_GMAC_MACCONF1_RXENA |
-               (dev->flags & IFF_LOOPBACK ? 1 : 0)
-                       << S6_GMAC_MACCONF1_LOOPBACK,
-               pd->reg + S6_GMAC_MACCONF1);
-       writel(dev->mtu && (dev->mtu < (S6_MAX_FRLEN - ETH_HLEN-ETH_FCS_LEN)) ?
-                       dev->mtu+ETH_HLEN+ETH_FCS_LEN : S6_MAX_FRLEN,
-               pd->reg + S6_GMAC_MACMAXFRAMELEN);
-       writel((pd->link.full ? 1 : 0) << S6_GMAC_MACCONF2_FULL |
-               1 << S6_GMAC_MACCONF2_PADCRCENA |
-               1 << S6_GMAC_MACCONF2_LENGTHFCHK |
-               (pd->link.giga ?
-                       S6_GMAC_MACCONF2_IFMODE_BYTE :
-                       S6_GMAC_MACCONF2_IFMODE_NIBBLE)
-                       << S6_GMAC_MACCONF2_IFMODE |
-               7 << S6_GMAC_MACCONF2_PREAMBLELEN,
-               pd->reg + S6_GMAC_MACCONF2);
-       writel(0, pd->reg + S6_GMAC_MACSTATADDR1);
-       writel(0, pd->reg + S6_GMAC_MACSTATADDR2);
-       writel(1 << S6_GMAC_FIFOCONF0_WTMENREQ |
-               1 << S6_GMAC_FIFOCONF0_SRFENREQ |
-               1 << S6_GMAC_FIFOCONF0_FRFENREQ |
-               1 << S6_GMAC_FIFOCONF0_STFENREQ |
-               1 << S6_GMAC_FIFOCONF0_FTFENREQ,
-               pd->reg + S6_GMAC_FIFOCONF0);
-       writel(128 << S6_GMAC_FIFOCONF3_CFGFTTH |
-               128 << S6_GMAC_FIFOCONF3_CFGHWMFT,
-               pd->reg + S6_GMAC_FIFOCONF3);
-       writel((S6_GMAC_FIFOCONF_RSV_MASK & ~(
-                       1 << S6_GMAC_FIFOCONF_RSV_RUNT |
-                       1 << S6_GMAC_FIFOCONF_RSV_CRCERR |
-                       1 << S6_GMAC_FIFOCONF_RSV_OK |
-                       1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE |
-                       1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME |
-                       1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL |
-                       1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE |
-                       1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED)) |
-               1 << S6_GMAC_FIFOCONF5_DROPLT64 |
-               pd->link.giga << S6_GMAC_FIFOCONF5_CFGBYTM |
-               1 << S6_GMAC_FIFOCONF5_RXDROPSIZE,
-               pd->reg + S6_GMAC_FIFOCONF5);
-       writel(1 << S6_GMAC_FIFOCONF_RSV_RUNT |
-               1 << S6_GMAC_FIFOCONF_RSV_CRCERR |
-               1 << S6_GMAC_FIFOCONF_RSV_DRIBBLE |
-               1 << S6_GMAC_FIFOCONF_RSV_CTRLFRAME |
-               1 << S6_GMAC_FIFOCONF_RSV_PAUSECTRL |
-               1 << S6_GMAC_FIFOCONF_RSV_UNOPCODE |
-               1 << S6_GMAC_FIFOCONF_RSV_TRUNCATED,
-               pd->reg + S6_GMAC_FIFOCONF4);
-       s6gmac_set_dstaddr(pd, 0,
-               0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF);
-       s6gmac_set_dstaddr(pd, 1,
-               dev->dev_addr[5] |
-               dev->dev_addr[4] << 8 |
-               dev->dev_addr[3] << 16 |
-               dev->dev_addr[2] << 24,
-               dev->dev_addr[1] |
-               dev->dev_addr[0] << 8,
-               0xFFFFFFFF, 0x0000FFFF);
-       s6gmac_set_dstaddr(pd, 2,
-               0x00000000, 0x00000100, 0x00000000, 0x00000100);
-       s6gmac_set_dstaddr(pd, 3,
-               0x00000000, 0x00000000, 0x00000000, 0x00000000);
-       writel(1 << S6_GMAC_HOST_PBLKCTRL_TXENA |
-               1 << S6_GMAC_HOST_PBLKCTRL_RXENA |
-               S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_TXBSIZ |
-               S6_GMAC_HOST_PBLKCTRL_SIZ_128 << S6_GMAC_HOST_PBLKCTRL_RXBSIZ |
-               1 << S6_GMAC_HOST_PBLKCTRL_STATENA |
-               1 << S6_GMAC_HOST_PBLKCTRL_STATCLEAR |
-               is_rgmii << S6_GMAC_HOST_PBLKCTRL_RGMII,
-               pd->reg + S6_GMAC_HOST_PBLKCTRL);
-}
-
-static void s6mii_enable(struct s6gmac *pd)
-{
-       writel(readl(pd->reg + S6_GMAC_MACCONF1) &
-               ~(1 << S6_GMAC_MACCONF1_SOFTRES),
-               pd->reg + S6_GMAC_MACCONF1);
-       writel((readl(pd->reg + S6_GMAC_MACMIICONF)
-               & ~(S6_GMAC_MACMIICONF_CSEL_MASK << S6_GMAC_MACMIICONF_CSEL))
-               | (S6_GMAC_MACMIICONF_CSEL_DIV168 << S6_GMAC_MACMIICONF_CSEL),
-               pd->reg + S6_GMAC_MACMIICONF);
-}
-
-static int s6mii_busy(struct s6gmac *pd, int tmo)
-{
-       while (readl(pd->reg + S6_GMAC_MACMIIINDI)) {
-               if (--tmo == 0)
-                       return -ETIME;
-               udelay(64);
-       }
-       return 0;
-}
-
-static int s6mii_read(struct mii_bus *bus, int phy_addr, int regnum)
-{
-       struct s6gmac *pd = bus->priv;
-       s6mii_enable(pd);
-       if (s6mii_busy(pd, 256))
-               return -ETIME;
-       writel(phy_addr << S6_GMAC_MACMIIADDR_PHY |
-               regnum << S6_GMAC_MACMIIADDR_REG,
-               pd->reg + S6_GMAC_MACMIIADDR);
-       writel(1 << S6_GMAC_MACMIICMD_READ, pd->reg + S6_GMAC_MACMIICMD);
-       writel(0, pd->reg + S6_GMAC_MACMIICMD);
-       if (s6mii_busy(pd, 256))
-               return -ETIME;
-       return (u16)readl(pd->reg + S6_GMAC_MACMIISTAT);
-}
-
-static int s6mii_write(struct mii_bus *bus, int phy_addr, int regnum, u16 value)
-{
-       struct s6gmac *pd = bus->priv;
-       s6mii_enable(pd);
-       if (s6mii_busy(pd, 256))
-               return -ETIME;
-       writel(phy_addr << S6_GMAC_MACMIIADDR_PHY |
-               regnum << S6_GMAC_MACMIIADDR_REG,
-               pd->reg + S6_GMAC_MACMIIADDR);
-       writel(value, pd->reg + S6_GMAC_MACMIICTRL);
-       if (s6mii_busy(pd, 256))
-               return -ETIME;
-       return 0;
-}
-
-static int s6mii_reset(struct mii_bus *bus)
-{
-       struct s6gmac *pd = bus->priv;
-       s6mii_enable(pd);
-       if (s6mii_busy(pd, PHY_INIT_TIMEOUT))
-               return -ETIME;
-       return 0;
-}
-
-static void s6gmac_set_rgmii_txclock(struct s6gmac *pd)
-{
-       u32 pllsel = readl(S6_REG_GREG1 + S6_GREG1_PLLSEL);
-       pllsel &= ~(S6_GREG1_PLLSEL_GMAC_MASK << S6_GREG1_PLLSEL_GMAC);
-       switch (pd->link.mbit) {
-       case 10:
-               pllsel |= S6_GREG1_PLLSEL_GMAC_2500KHZ << S6_GREG1_PLLSEL_GMAC;
-               break;
-       case 100:
-               pllsel |= S6_GREG1_PLLSEL_GMAC_25MHZ << S6_GREG1_PLLSEL_GMAC;
-               break;
-       case 1000:
-               pllsel |= S6_GREG1_PLLSEL_GMAC_125MHZ << S6_GREG1_PLLSEL_GMAC;
-               break;
-       default:
-               return;
-       }
-       writel(pllsel, S6_REG_GREG1 + S6_GREG1_PLLSEL);
-}
-
-static inline void s6gmac_linkisup(struct net_device *dev, int isup)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       struct phy_device *phydev = pd->phydev;
-
-       pd->link.full = phydev->duplex;
-       pd->link.giga = (phydev->speed == 1000);
-       if (pd->link.mbit != phydev->speed) {
-               pd->link.mbit = phydev->speed;
-               s6gmac_set_rgmii_txclock(pd);
-       }
-       pd->link.isup = isup;
-       if (isup)
-               netif_carrier_on(dev);
-       phy_print_status(phydev);
-}
-
-static void s6gmac_adjust_link(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       struct phy_device *phydev = pd->phydev;
-       if (pd->link.isup &&
-                       (!phydev->link ||
-                       (pd->link.mbit != phydev->speed) ||
-                       (pd->link.full != phydev->duplex))) {
-               pd->link.isup = 0;
-               netif_tx_disable(dev);
-               if (!phydev->link) {
-                       netif_carrier_off(dev);
-                       phy_print_status(phydev);
-               }
-       }
-       if (!pd->link.isup && phydev->link) {
-               if (pd->link.full != phydev->duplex) {
-                       u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2);
-                       if (phydev->duplex)
-                               maccfg |= 1 << S6_GMAC_MACCONF2_FULL;
-                       else
-                               maccfg &= ~(1 << S6_GMAC_MACCONF2_FULL);
-                       writel(maccfg, pd->reg + S6_GMAC_MACCONF2);
-               }
-
-               if (pd->link.giga != (phydev->speed == 1000)) {
-                       u32 fifocfg = readl(pd->reg + S6_GMAC_FIFOCONF5);
-                       u32 maccfg = readl(pd->reg + S6_GMAC_MACCONF2);
-                       maccfg &= ~(S6_GMAC_MACCONF2_IFMODE_MASK
-                                    << S6_GMAC_MACCONF2_IFMODE);
-                       if (phydev->speed == 1000) {
-                               fifocfg |= 1 << S6_GMAC_FIFOCONF5_CFGBYTM;
-                               maccfg |= S6_GMAC_MACCONF2_IFMODE_BYTE
-                                          << S6_GMAC_MACCONF2_IFMODE;
-                       } else {
-                               fifocfg &= ~(1 << S6_GMAC_FIFOCONF5_CFGBYTM);
-                               maccfg |= S6_GMAC_MACCONF2_IFMODE_NIBBLE
-                                          << S6_GMAC_MACCONF2_IFMODE;
-                       }
-                       writel(fifocfg, pd->reg + S6_GMAC_FIFOCONF5);
-                       writel(maccfg, pd->reg + S6_GMAC_MACCONF2);
-               }
-
-               if (!s6dmac_fifo_full(pd->tx_dma, pd->tx_chan))
-                       netif_wake_queue(dev);
-               s6gmac_linkisup(dev, 1);
-       }
-}
-
-static inline int s6gmac_phy_start(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       int i = 0;
-       struct phy_device *p = NULL;
-       while ((i < PHY_MAX_ADDR) && (!(p = pd->mii.bus->phy_map[i])))
-               i++;
-       p = phy_connect(dev, dev_name(&p->dev), &s6gmac_adjust_link,
-                       PHY_INTERFACE_MODE_RGMII);
-       if (IS_ERR(p)) {
-               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
-               return PTR_ERR(p);
-       }
-       p->supported &= PHY_GBIT_FEATURES;
-       p->advertising = p->supported;
-       pd->phydev = p;
-       return 0;
-}
-
-static inline void s6gmac_init_stats(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       u32 mask;
-       mask =  1 << S6_GMAC_STATCARRY1_RDRP |
-               1 << S6_GMAC_STATCARRY1_RJBR |
-               1 << S6_GMAC_STATCARRY1_RFRG |
-               1 << S6_GMAC_STATCARRY1_ROVR |
-               1 << S6_GMAC_STATCARRY1_RUND |
-               1 << S6_GMAC_STATCARRY1_RCDE |
-               1 << S6_GMAC_STATCARRY1_RFLR |
-               1 << S6_GMAC_STATCARRY1_RALN |
-               1 << S6_GMAC_STATCARRY1_RMCA |
-               1 << S6_GMAC_STATCARRY1_RFCS |
-               1 << S6_GMAC_STATCARRY1_RPKT |
-               1 << S6_GMAC_STATCARRY1_RBYT;
-       writel(mask, pd->reg + S6_GMAC_STATCARRY(0));
-       writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(0));
-       mask =  1 << S6_GMAC_STATCARRY2_TDRP |
-               1 << S6_GMAC_STATCARRY2_TNCL |
-               1 << S6_GMAC_STATCARRY2_TXCL |
-               1 << S6_GMAC_STATCARRY2_TEDF |
-               1 << S6_GMAC_STATCARRY2_TPKT |
-               1 << S6_GMAC_STATCARRY2_TBYT |
-               1 << S6_GMAC_STATCARRY2_TFRG |
-               1 << S6_GMAC_STATCARRY2_TUND |
-               1 << S6_GMAC_STATCARRY2_TOVR |
-               1 << S6_GMAC_STATCARRY2_TFCS |
-               1 << S6_GMAC_STATCARRY2_TJBR;
-       writel(mask, pd->reg + S6_GMAC_STATCARRY(1));
-       writel(~mask, pd->reg + S6_GMAC_STATCARRYMSK(1));
-}
-
-static inline void s6gmac_init_dmac(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       s6dmac_disable_chan(pd->tx_dma, pd->tx_chan);
-       s6dmac_disable_chan(pd->rx_dma, pd->rx_chan);
-       s6dmac_disable_error_irqs(pd->tx_dma, 1 << S6_HIFDMA_GMACTX);
-       s6dmac_disable_error_irqs(pd->rx_dma, 1 << S6_HIFDMA_GMACRX);
-}
-
-static int s6gmac_tx(struct sk_buff *skb, struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&pd->lock, flags);
-       writel(skb->len << S6_GMAC_BURST_PREWR_LEN |
-               0 << S6_GMAC_BURST_PREWR_CFE |
-               1 << S6_GMAC_BURST_PREWR_PPE |
-               1 << S6_GMAC_BURST_PREWR_FCS |
-               ((skb->len < ETH_ZLEN) ? 1 : 0) << S6_GMAC_BURST_PREWR_PAD,
-               pd->reg + S6_GMAC_BURST_PREWR);
-       s6dmac_put_fifo_cache(pd->tx_dma, pd->tx_chan,
-               (u32)skb->data, pd->io, skb->len);
-       if (s6dmac_fifo_full(pd->tx_dma, pd->tx_chan))
-               netif_stop_queue(dev);
-       if (((u8)(pd->tx_skb_i - pd->tx_skb_o)) >= S6_NUM_TX_SKB) {
-               printk(KERN_ERR "GMAC BUG: skb tx ring overflow [%x, %x]\n",
-                       pd->tx_skb_o, pd->tx_skb_i);
-               BUG();
-       }
-       pd->tx_skb[(pd->tx_skb_i++) % S6_NUM_TX_SKB] = skb;
-       spin_unlock_irqrestore(&pd->lock, flags);
-       return 0;
-}
-
-static void s6gmac_tx_timeout(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       unsigned long flags;
-       spin_lock_irqsave(&pd->lock, flags);
-       s6gmac_tx_interrupt(dev);
-       spin_unlock_irqrestore(&pd->lock, flags);
-}
-
-static int s6gmac_open(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       unsigned long flags;
-       phy_read_status(pd->phydev);
-       spin_lock_irqsave(&pd->lock, flags);
-       pd->link.mbit = 0;
-       s6gmac_linkisup(dev, pd->phydev->link);
-       s6gmac_init_device(dev);
-       s6gmac_init_stats(dev);
-       s6gmac_init_dmac(dev);
-       s6gmac_rx_fillfifo(dev);
-       s6dmac_enable_chan(pd->rx_dma, pd->rx_chan,
-               2, 1, 0, 1, 0, 0, 0, 7, -1, 2, 0, 1);
-       s6dmac_enable_chan(pd->tx_dma, pd->tx_chan,
-               2, 0, 1, 0, 0, 0, 0, 7, -1, 2, 0, 1);
-       writel(0 << S6_GMAC_HOST_INT_TXBURSTOVER |
-               0 << S6_GMAC_HOST_INT_TXPREWOVER |
-               0 << S6_GMAC_HOST_INT_RXBURSTUNDER |
-               0 << S6_GMAC_HOST_INT_RXPOSTRFULL |
-               0 << S6_GMAC_HOST_INT_RXPOSTRUNDER,
-               pd->reg + S6_GMAC_HOST_INTMASK);
-       spin_unlock_irqrestore(&pd->lock, flags);
-       phy_start(pd->phydev);
-       netif_start_queue(dev);
-       return 0;
-}
-
-static int s6gmac_stop(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       unsigned long flags;
-       netif_stop_queue(dev);
-       phy_stop(pd->phydev);
-       spin_lock_irqsave(&pd->lock, flags);
-       s6gmac_init_dmac(dev);
-       s6gmac_stop_device(dev);
-       while (pd->tx_skb_i != pd->tx_skb_o)
-               dev_kfree_skb(pd->tx_skb[(pd->tx_skb_o++) % S6_NUM_TX_SKB]);
-       while (pd->rx_skb_i != pd->rx_skb_o)
-               dev_kfree_skb(pd->rx_skb[(pd->rx_skb_o++) % S6_NUM_RX_SKB]);
-       spin_unlock_irqrestore(&pd->lock, flags);
-       return 0;
-}
-
-static struct net_device_stats *s6gmac_stats(struct net_device *dev)
-{
-       struct s6gmac *pd = netdev_priv(dev);
-       struct net_device_stats *st = (struct net_device_stats *)&pd->stats;
-       int i;
-       do {
-               unsigned long flags;
-               spin_lock_irqsave(&pd->lock, flags);
-               for (i = 0; i < ARRAY_SIZE(pd->stats); i++)
-                       pd->stats[i] =
-                               pd->carry[i] << (S6_GMAC_STAT_SIZE_MIN - 1);
-               s6gmac_stats_collect(pd, &statinf[0][0]);
-               s6gmac_stats_collect(pd, &statinf[1][0]);
-               i = s6gmac_stats_pending(pd, 0) |
-                       s6gmac_stats_pending(pd, 1);
-               spin_unlock_irqrestore(&pd->lock, flags);
-       } while (i);
-       st->rx_errors = st->rx_crc_errors +
-                       st->rx_frame_errors +
-                       st->rx_length_errors +
-                       st->rx_missed_errors;
-       st->tx_errors += st->tx_aborted_errors;
-       return st;
-}
-
-static int s6gmac_probe(struct platform_device *pdev)
-{
-       struct net_device *dev;
-       struct s6gmac *pd;
-       int res;
-       unsigned long i;
-       struct mii_bus *mb;
-
-       dev = alloc_etherdev(sizeof(*pd));
-       if (!dev)
-               return -ENOMEM;
-
-       dev->open = s6gmac_open;
-       dev->stop = s6gmac_stop;
-       dev->hard_start_xmit = s6gmac_tx;
-       dev->tx_timeout = s6gmac_tx_timeout;
-       dev->watchdog_timeo = HZ;
-       dev->get_stats = s6gmac_stats;
-       dev->irq = platform_get_irq(pdev, 0);
-       pd = netdev_priv(dev);
-       memset(pd, 0, sizeof(*pd));
-       spin_lock_init(&pd->lock);
-       pd->reg = platform_get_resource(pdev, IORESOURCE_MEM, 0)->start;
-       i = platform_get_resource(pdev, IORESOURCE_DMA, 0)->start;
-       pd->tx_dma = DMA_MASK_DMAC(i);
-       pd->tx_chan = DMA_INDEX_CHNL(i);
-       i = platform_get_resource(pdev, IORESOURCE_DMA, 1)->start;
-       pd->rx_dma = DMA_MASK_DMAC(i);
-       pd->rx_chan = DMA_INDEX_CHNL(i);
-       pd->io = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
-       res = request_irq(dev->irq, s6gmac_interrupt, 0, dev->name, dev);
-       if (res) {
-               printk(KERN_ERR DRV_PRMT "irq request failed: %d\n", dev->irq);
-               goto errirq;
-       }
-       res = register_netdev(dev);
-       if (res) {
-               printk(KERN_ERR DRV_PRMT "error registering device %s\n",
-                       dev->name);
-               goto errdev;
-       }
-       mb = mdiobus_alloc();
-       if (!mb) {
-               printk(KERN_ERR DRV_PRMT "error allocating mii bus\n");
-               res = -ENOMEM;
-               goto errmii;
-       }
-       mb->name = "s6gmac_mii";
-       mb->read = s6mii_read;
-       mb->write = s6mii_write;
-       mb->reset = s6mii_reset;
-       mb->priv = pd;
-       snprintf(mb->id, MII_BUS_ID_SIZE, "%s-%x", pdev->name, pdev->id);
-       mb->phy_mask = ~(1 << 0);
-       mb->irq = &pd->mii.irq[0];
-       for (i = 0; i < PHY_MAX_ADDR; i++) {
-               int n = platform_get_irq(pdev, i + 1);
-               if (n < 0)
-                       n = PHY_POLL;
-               pd->mii.irq[i] = n;
-       }
-       mdiobus_register(mb);
-       pd->mii.bus = mb;
-       res = s6gmac_phy_start(dev);
-       if (res)
-               return res;
-       platform_set_drvdata(pdev, dev);
-       return 0;
-errmii:
-       unregister_netdev(dev);
-errdev:
-       free_irq(dev->irq, dev);
-errirq:
-       free_netdev(dev);
-       return res;
-}
-
-static int s6gmac_remove(struct platform_device *pdev)
-{
-       struct net_device *dev = platform_get_drvdata(pdev);
-       if (dev) {
-               struct s6gmac *pd = netdev_priv(dev);
-               mdiobus_unregister(pd->mii.bus);
-               unregister_netdev(dev);
-               free_irq(dev->irq, dev);
-               free_netdev(dev);
-       }
-       return 0;
-}
-
-static struct platform_driver s6gmac_driver = {
-       .probe = s6gmac_probe,
-       .remove = s6gmac_remove,
-       .driver = {
-               .name = "s6gmac",
-       },
-};
-
-module_platform_driver(s6gmac_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("S6105 on chip Ethernet driver");
-MODULE_AUTHOR("Oskar Schirmer <oskar@scara.com>");
index 698494481d18072ca00ddecb825ea92bd4e86c56..b1a271853d8556a08592e2a89e8b5a5f7cb8ba67 100644 (file)
@@ -474,13 +474,19 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,
        /* allocate memory for RX skbuff array */
        rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize,
                                               sizeof(dma_addr_t), GFP_KERNEL);
-       if (rx_ring->rx_skbuff_dma == NULL)
-               goto dmamem_err;
+       if (!rx_ring->rx_skbuff_dma) {
+               dma_free_coherent(priv->device,
+                                 rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+                                 rx_ring->dma_rx, rx_ring->dma_rx_phy);
+               goto error;
+       }
 
        rx_ring->rx_skbuff = kmalloc_array(rx_rsize,
                                           sizeof(struct sk_buff *), GFP_KERNEL);
-       if (rx_ring->rx_skbuff == NULL)
-               goto rxbuff_err;
+       if (!rx_ring->rx_skbuff) {
+               kfree(rx_ring->rx_skbuff_dma);
+               goto error;
+       }
 
        /* initialise the buffers */
        for (desc_index = 0; desc_index < rx_rsize; desc_index++) {
@@ -502,13 +508,6 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,
 err_init_rx_buffers:
        while (--desc_index >= 0)
                free_rx_ring(priv->device, rx_ring, desc_index);
-       kfree(rx_ring->rx_skbuff);
-rxbuff_err:
-       kfree(rx_ring->rx_skbuff_dma);
-dmamem_err:
-       dma_free_coherent(priv->device,
-                         rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
-                         rx_ring->dma_rx, rx_ring->dma_rx_phy);
 error:
        return -ENOMEM;
 }
index 866560ea9e180d115513eead6d5b2a3bc1754f7b..b02eed12bfc5743117285216db1b4fe6ba19536e 100644 (file)
@@ -108,10 +108,6 @@ static int sxgbe_platform_probe(struct platform_device *pdev)
                }
        }
 
-       /* Get MAC address if available (DT) */
-       if (mac)
-               ether_addr_copy(priv->dev->dev_addr, mac);
-
        priv = sxgbe_drv_probe(&(pdev->dev), plat_dat, addr);
        if (!priv) {
                pr_err("%s: main driver probe failed\n", __func__);
@@ -125,6 +121,10 @@ static int sxgbe_platform_probe(struct platform_device *pdev)
                goto err_drv_remove;
        }
 
+       /* Get MAC address if available (DT) */
+       if (mac)
+               ether_addr_copy(priv->dev->dev_addr, mac);
+
        /* Get the TX/RX IRQ numbers */
        for (i = 0, chan = 1; i < SXGBE_TX_QUEUES; i++) {
                priv->txq[i]->irq_no = irq_of_parse_and_map(node, chan++);
index 118a427d1942068f7cf37e8a384676bcbd21089e..cf62ff4c8c56c6d3f4d8e8421cbd1b71e86e192b 100644 (file)
@@ -1671,7 +1671,7 @@ static void stmmac_init_tx_coalesce(struct stmmac_priv *priv)
  *  0 on success and an appropriate (-)ve integer as defined in errno.h
  *  file on failure.
  */
-static int stmmac_hw_setup(struct net_device *dev)
+static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
        int ret;
@@ -1708,9 +1708,11 @@ static int stmmac_hw_setup(struct net_device *dev)
 
        stmmac_mmc_setup(priv);
 
-       ret = stmmac_init_ptp(priv);
-       if (ret && ret != -EOPNOTSUPP)
-               pr_warn("%s: failed PTP initialisation\n", __func__);
+       if (init_ptp) {
+               ret = stmmac_init_ptp(priv);
+               if (ret && ret != -EOPNOTSUPP)
+                       pr_warn("%s: failed PTP initialisation\n", __func__);
+       }
 
 #ifdef CONFIG_DEBUG_FS
        ret = stmmac_init_fs(dev);
@@ -1787,7 +1789,7 @@ static int stmmac_open(struct net_device *dev)
                goto init_error;
        }
 
-       ret = stmmac_hw_setup(dev);
+       ret = stmmac_hw_setup(dev, true);
        if (ret < 0) {
                pr_err("%s: Hw setup failed\n", __func__);
                goto init_error;
@@ -2776,6 +2778,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
  * @addr: iobase memory address
  * Description: this is the main probe function used to
  * call the alloc_etherdev, allocate the priv structure.
+ * Return:
+ * on success the new private structure is returned, otherwise the error
+ * pointer.
  */
 struct stmmac_priv *stmmac_dvr_probe(struct device *device,
                                     struct plat_stmmacenet_data *plat_dat,
@@ -2787,7 +2792,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
 
        ndev = alloc_etherdev(sizeof(struct stmmac_priv));
        if (!ndev)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        SET_NETDEV_DEV(ndev, device);
 
@@ -3036,7 +3041,7 @@ int stmmac_resume(struct net_device *ndev)
        netif_device_attach(ndev);
 
        init_dma_desc_rings(ndev, GFP_ATOMIC);
-       stmmac_hw_setup(ndev);
+       stmmac_hw_setup(ndev, false);
        stmmac_init_tx_coalesce(priv);
 
        napi_enable(&priv->napi);
index 4032b170fe243e230b117c49a420c7e11db21459..3039de2465bac825049e99e2130f49be13291e18 100644 (file)
@@ -430,7 +430,6 @@ static struct platform_driver stmmac_pltfr_driver = {
        .remove = stmmac_pltfr_remove,
        .driver = {
                   .name = STMMAC_RESOURCE_NAME,
-                  .owner = THIS_MODULE,
                   .pm = &stmmac_pltfr_pm_ops,
                   .of_match_table = of_match_ptr(stmmac_dt_ids),
        },
index 45c408ef67d0d904e08732c6c2b4f119a8b98ddd..d2835bf7b4fbef1744bf2bd6d840acfe47863a39 100644 (file)
@@ -1201,6 +1201,7 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb)
                segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
        if (IS_ERR(segs)) {
                dev->stats.tx_dropped++;
+               dev_kfree_skb_any(skb);
                return NETDEV_TX_OK;
        }
 
index c560f9aeb55d691f23c65dae362c18defa1e9e44..a39131f494ec1f87cf5c4cd794945f68cd8e180d 100644 (file)
@@ -610,7 +610,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
 
                        /* Clear all mcast from ALE */
                        cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS <<
-                                                priv->host_port);
+                                                priv->host_port, -1);
 
                        /* Flood All Unicast Packets to Host port */
                        cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1);
@@ -634,6 +634,12 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
 static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
 {
        struct cpsw_priv *priv = netdev_priv(ndev);
+       int vid;
+
+       if (priv->data.dual_emac)
+               vid = priv->slaves[priv->emac_port].port_vlan;
+       else
+               vid = priv->data.default_vlan;
 
        if (ndev->flags & IFF_PROMISC) {
                /* Enable promiscuous mode */
@@ -649,7 +655,8 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
        cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI);
 
        /* Clear all mcast from ALE */
-       cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port);
+       cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port,
+                                vid);
 
        if (!netdev_mc_empty(ndev)) {
                struct netdev_hw_addr *ha;
@@ -757,6 +764,14 @@ requeue:
 static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
 {
        struct cpsw_priv *priv = dev_id;
+       int value = irq - priv->irqs_table[0];
+
+       /* NOTICE: Ending IRQ here. The trick with the 'value' variable above
+        * is to make sure we will always write the correct value to the EOI
+        * register. Namely 0 for RX_THRESH Interrupt, 1 for RX Interrupt, 2
+        * for TX Interrupt and 3 for MISC Interrupt.
+        */
+       cpdma_ctlr_eoi(priv->dma, value);
 
        cpsw_intr_disable(priv);
        if (priv->irq_enabled == true) {
@@ -786,8 +801,6 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
        int                     num_tx, num_rx;
 
        num_tx = cpdma_chan_process(priv->txch, 128);
-       if (num_tx)
-               cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
 
        num_rx = cpdma_chan_process(priv->rxch, budget);
        if (num_rx < budget) {
@@ -795,7 +808,6 @@ static int cpsw_poll(struct napi_struct *napi, int budget)
 
                napi_complete(napi);
                cpsw_intr_enable(priv);
-               cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
                prim_cpsw = cpsw_get_slave_priv(priv, 0);
                if (prim_cpsw->irq_enabled == false) {
                        prim_cpsw->irq_enabled = true;
@@ -1310,8 +1322,6 @@ static int cpsw_ndo_open(struct net_device *ndev)
        napi_enable(&priv->napi);
        cpdma_ctlr_start(priv->dma);
        cpsw_intr_enable(priv);
-       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
-       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
 
        prim_cpsw = cpsw_get_slave_priv(priv, 0);
        if (prim_cpsw->irq_enabled == false) {
@@ -1578,9 +1588,6 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev)
        cpdma_chan_start(priv->txch);
        cpdma_ctlr_int_ctrl(priv->dma, true);
        cpsw_intr_enable(priv);
-       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
-       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
-
 }
 
 static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
@@ -1620,9 +1627,6 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
        cpsw_interrupt(ndev->irq, priv);
        cpdma_ctlr_int_ctrl(priv->dma, true);
        cpsw_intr_enable(priv);
-       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
-       cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
-
 }
 #endif
 
@@ -1630,16 +1634,24 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
                                unsigned short vid)
 {
        int ret;
-       int unreg_mcast_mask;
+       int unreg_mcast_mask = 0;
+       u32 port_mask;
 
-       if (priv->ndev->flags & IFF_ALLMULTI)
-               unreg_mcast_mask = ALE_ALL_PORTS;
-       else
-               unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
+       if (priv->data.dual_emac) {
+               port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST;
+
+               if (priv->ndev->flags & IFF_ALLMULTI)
+                       unreg_mcast_mask = port_mask;
+       } else {
+               port_mask = ALE_ALL_PORTS;
 
-       ret = cpsw_ale_add_vlan(priv->ale, vid,
-                               ALE_ALL_PORTS << priv->host_port,
-                               0, ALE_ALL_PORTS << priv->host_port,
+               if (priv->ndev->flags & IFF_ALLMULTI)
+                       unreg_mcast_mask = ALE_ALL_PORTS;
+               else
+                       unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
+       }
+
+       ret = cpsw_ale_add_vlan(priv->ale, vid, port_mask, 0, port_mask,
                                unreg_mcast_mask << priv->host_port);
        if (ret != 0)
                return ret;
@@ -1650,8 +1662,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
                goto clean_vid;
 
        ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-                                ALE_ALL_PORTS << priv->host_port,
-                                ALE_VLAN, vid, 0);
+                                port_mask, ALE_VLAN, vid, 0);
        if (ret != 0)
                goto clean_vlan_ucast;
        return 0;
@@ -1672,6 +1683,19 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
        if (vid == priv->data.default_vlan)
                return 0;
 
+       if (priv->data.dual_emac) {
+               /* In dual EMAC, reserved VLAN id should not be used for
+                * creating VLAN interfaces as this can break the dual
+                * EMAC port separation
+                */
+               int i;
+
+               for (i = 0; i < priv->data.slaves; i++) {
+                       if (vid == priv->slaves[i].port_vlan)
+                               return -EINVAL;
+               }
+       }
+
        dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
        return cpsw_add_vlan_ale_entry(priv, vid);
 }
@@ -1685,6 +1709,15 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
        if (vid == priv->data.default_vlan)
                return 0;
 
+       if (priv->data.dual_emac) {
+               int i;
+
+               for (i = 0; i < priv->data.slaves; i++) {
+                       if (vid == priv->slaves[i].port_vlan)
+                               return -EINVAL;
+               }
+       }
+
        dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid);
        ret = cpsw_ale_del_vlan(priv->ale, vid, 0);
        if (ret != 0)
index 097ebe7077ac0c8de51e3eb7e8da5809f5e6bcea..5246b3a18ff86e8494d30db90c6154ba9f7ed25f 100644 (file)
@@ -234,7 +234,7 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
                cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
 }
 
-int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask)
+int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
 {
        u32 ale_entry[ALE_ENTRY_WORDS];
        int ret, idx;
@@ -245,6 +245,14 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask)
                if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
                        continue;
 
+               /* if vid passed is -1 then remove all multicast entry from
+                * the table irrespective of vlan id, if a valid vlan id is
+                * passed then remove only multicast added to that vlan id.
+                * if vlan id doesn't match then move on to next entry.
+                */
+               if (vid != -1 && cpsw_ale_get_vlan_id(ale_entry) != vid)
+                       continue;
+
                if (cpsw_ale_get_mcast(ale_entry)) {
                        u8 addr[6];
 
index c0d4127aa549285c7e50e47214c1579e17478210..af1e7ecd87c6fbd24b80954c7977e96aa3676a0c 100644 (file)
@@ -92,7 +92,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
 
 int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
 int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
-int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask);
+int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid);
 int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
                       int flags, u16 vid);
 int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
index ea712512c7d1f5e155129bf073cac1d7381d38bb..5fae4354722c040308190d4ca9c3664cfbdd7113 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
+#include <linux/of_mdio.h>
 #include <linux/of_irq.h>
 #include <linux/of_net.h>
 
@@ -343,9 +344,7 @@ struct emac_priv {
        u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS];
        u32 rx_addr_type;
        const char *phy_id;
-#ifdef CONFIG_OF
        struct device_node *phy_node;
-#endif
        struct phy_device *phydev;
        spinlock_t lock;
        /*platform specific members*/
@@ -922,6 +921,16 @@ static void emac_int_disable(struct emac_priv *priv)
                if (priv->int_disable)
                        priv->int_disable();
 
+               /* NOTE: Rx Threshold and Misc interrupts are not enabled */
+
+               /* ack rxen only then a new pulse will be generated */
+               emac_write(EMAC_DM646X_MACEOIVECTOR,
+                       EMAC_DM646X_MAC_EOI_C0_RXEN);
+
+               /* ack txen- only then a new pulse will be generated */
+               emac_write(EMAC_DM646X_MACEOIVECTOR,
+                       EMAC_DM646X_MAC_EOI_C0_TXEN);
+
                local_irq_restore(flags);
 
        } else {
@@ -951,15 +960,6 @@ static void emac_int_enable(struct emac_priv *priv)
                 * register */
 
                /* NOTE: Rx Threshold and Misc interrupts are not enabled */
-
-               /* ack rxen only then a new pulse will be generated */
-               emac_write(EMAC_DM646X_MACEOIVECTOR,
-                       EMAC_DM646X_MAC_EOI_C0_RXEN);
-
-               /* ack txen- only then a new pulse will be generated */
-               emac_write(EMAC_DM646X_MACEOIVECTOR,
-                       EMAC_DM646X_MAC_EOI_C0_TXEN);
-
        } else {
                /* Set DM644x control registers for interrupt control */
                emac_ctrl_write(EMAC_CTRL_EWCTL, 0x1);
@@ -1537,7 +1537,13 @@ static int emac_dev_open(struct net_device *ndev)
        int i = 0;
        struct emac_priv *priv = netdev_priv(ndev);
 
-       pm_runtime_get(&priv->pdev->dev);
+       ret = pm_runtime_get_sync(&priv->pdev->dev);
+       if (ret < 0) {
+               pm_runtime_put_noidle(&priv->pdev->dev);
+               dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n",
+                       __func__, ret);
+               return ret;
+       }
 
        netif_carrier_off(ndev);
        for (cnt = 0; cnt < ETH_ALEN; cnt++)
@@ -1596,8 +1602,20 @@ static int emac_dev_open(struct net_device *ndev)
        cpdma_ctlr_start(priv->dma);
 
        priv->phydev = NULL;
+
+       if (priv->phy_node) {
+               priv->phydev = of_phy_connect(ndev, priv->phy_node,
+                                             &emac_adjust_link, 0, 0);
+               if (!priv->phydev) {
+                       dev_err(emac_dev, "could not connect to phy %s\n",
+                               priv->phy_node->full_name);
+                       ret = -ENODEV;
+                       goto err;
+               }
+       }
+
        /* use the first phy on the bus if pdata did not give us a phy id */
-       if (!priv->phy_id) {
+       if (!priv->phydev && !priv->phy_id) {
                struct device *phy;
 
                phy = bus_find_device(&mdio_bus_type, NULL, NULL,
@@ -1606,7 +1624,7 @@ static int emac_dev_open(struct net_device *ndev)
                        priv->phy_id = dev_name(phy);
        }
 
-       if (priv->phy_id && *priv->phy_id) {
+       if (!priv->phydev && priv->phy_id && *priv->phy_id) {
                priv->phydev = phy_connect(ndev, priv->phy_id,
                                           &emac_adjust_link,
                                           PHY_INTERFACE_MODE_MII);
@@ -1627,7 +1645,9 @@ static int emac_dev_open(struct net_device *ndev)
                        "(mii_bus:phy_addr=%s, id=%x)\n",
                        priv->phydev->drv->name, dev_name(&priv->phydev->dev),
                        priv->phydev->phy_id);
-       } else {
+       }
+
+       if (!priv->phydev) {
                /* No PHY , fix the link, speed and duplex settings */
                dev_notice(emac_dev, "no phy, defaulting to 100/full\n");
                priv->link = 1;
@@ -1724,6 +1744,15 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)
        struct emac_priv *priv = netdev_priv(ndev);
        u32 mac_control;
        u32 stats_clear_mask;
+       int err;
+
+       err = pm_runtime_get_sync(&priv->pdev->dev);
+       if (err < 0) {
+               pm_runtime_put_noidle(&priv->pdev->dev);
+               dev_err(&priv->pdev->dev, "%s: failed to get_sync(%d)\n",
+                       __func__, err);
+               return &ndev->stats;
+       }
 
        /* update emac hardware stats and reset the registers*/
 
@@ -1766,6 +1795,8 @@ static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)
        ndev->stats.tx_fifo_errors += emac_read(EMAC_TXUNDERRUN);
        emac_write(EMAC_TXUNDERRUN, stats_clear_mask);
 
+       pm_runtime_put(&priv->pdev->dev);
+
        return &ndev->stats;
 }
 
@@ -1859,7 +1890,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)
 static int davinci_emac_probe(struct platform_device *pdev)
 {
        int rc = 0;
-       struct resource *res;
+       struct resource *res, *res_ctrl;
        struct net_device *ndev;
        struct emac_priv *priv;
        unsigned long hw_ram_addr;
@@ -1876,6 +1907,7 @@ static int davinci_emac_probe(struct platform_device *pdev)
                return -EBUSY;
        }
        emac_bus_frequency = clk_get_rate(emac_clk);
+       devm_clk_put(&pdev->dev, emac_clk);
 
        /* TODO: Probe PHY here if possible */
 
@@ -1917,11 +1949,20 @@ static int davinci_emac_probe(struct platform_device *pdev)
                rc = PTR_ERR(priv->remap_addr);
                goto no_pdata;
        }
+
+       res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res_ctrl) {
+               priv->ctrl_base =
+                       devm_ioremap_resource(&pdev->dev, res_ctrl);
+               if (IS_ERR(priv->ctrl_base))
+                       goto no_pdata;
+       } else {
+               priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset;
+       }
+
        priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset;
        ndev->base_addr = (unsigned long)priv->remap_addr;
 
-       priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset;
-
        hw_ram_addr = pdata->hw_ram_addr;
        if (!hw_ram_addr)
                hw_ram_addr = (u32 __force)res->start + pdata->ctrl_ram_offset;
@@ -1980,12 +2021,22 @@ static int davinci_emac_probe(struct platform_device *pdev)
        ndev->ethtool_ops = &ethtool_ops;
        netif_napi_add(ndev, &priv->napi, emac_poll, EMAC_POLL_WEIGHT);
 
+       pm_runtime_enable(&pdev->dev);
+       rc = pm_runtime_get_sync(&pdev->dev);
+       if (rc < 0) {
+               pm_runtime_put_noidle(&pdev->dev);
+               dev_err(&pdev->dev, "%s: failed to get_sync(%d)\n",
+                       __func__, rc);
+               goto no_cpdma_chan;
+       }
+
        /* register the network device */
        SET_NETDEV_DEV(ndev, &pdev->dev);
        rc = register_netdev(ndev);
        if (rc) {
                dev_err(&pdev->dev, "error in register_netdev\n");
                rc = -ENODEV;
+               pm_runtime_put(&pdev->dev);
                goto no_cpdma_chan;
        }
 
@@ -1995,9 +2046,7 @@ static int davinci_emac_probe(struct platform_device *pdev)
                           "(regs: %p, irq: %d)\n",
                           (void *)priv->emac_base_phys, ndev->irq);
        }
-
-       pm_runtime_enable(&pdev->dev);
-       pm_runtime_resume(&pdev->dev);
+       pm_runtime_put(&pdev->dev);
 
        return 0;
 
@@ -2071,9 +2120,14 @@ static const struct emac_platform_data am3517_emac_data = {
        .hw_ram_addr            = 0x01e20000,
 };
 
+static const struct emac_platform_data dm816_emac_data = {
+       .version                = EMAC_VERSION_2,
+};
+
 static const struct of_device_id davinci_emac_of_match[] = {
        {.compatible = "ti,davinci-dm6467-emac", },
        {.compatible = "ti,am3517-emac", .data = &am3517_emac_data, },
+       {.compatible = "ti,dm816-emac", .data = &dm816_emac_data, },
        {},
 };
 MODULE_DEVICE_TABLE(of, davinci_emac_of_match);
index 9c2d91ea0af48e35020594b73221f4354fc6dc5e..dbcbf0c5bcfa910c49ec81037892a45487aa081e 100644 (file)
@@ -1043,6 +1043,7 @@ static int temac_of_probe(struct platform_device *op)
        lp->regs = of_iomap(op->dev.of_node, 0);
        if (!lp->regs) {
                dev_err(&op->dev, "could not map temac regs.\n");
+               rc = -ENOMEM;
                goto nodev;
        }
 
@@ -1062,6 +1063,7 @@ static int temac_of_probe(struct platform_device *op)
        np = of_parse_phandle(op->dev.of_node, "llink-connected", 0);
        if (!np) {
                dev_err(&op->dev, "could not find DMA node\n");
+               rc = -ENODEV;
                goto err_iounmap;
        }
 
index 44b8d2bad8c3efd09a1d572d2ef7cf36f8d4a227..4c9b4fa1d3c1cbed1fc223634adca0a2cb7b5807 100644 (file)
@@ -388,7 +388,6 @@ struct axidma_bd {
  * @dma_err_tasklet: Tasklet structure to process Axi DMA errors
  * @tx_irq:    Axidma TX IRQ number
  * @rx_irq:    Axidma RX IRQ number
- * @temac_type:        axienet type to identify between soft and hard temac
  * @phy_type:  Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X
  * @options:   AxiEthernet option word
  * @last_link: Phy link state in which the PHY was negotiated earlier
@@ -431,7 +430,6 @@ struct axienet_local {
 
        int tx_irq;
        int rx_irq;
-       u32 temac_type;
        u32 phy_type;
 
        u32 options;                    /* Current options word */
index 4ea2d4e6f1d1894f22362e9a2b422392e959331d..a6d2860b712c732c5459bea14647da9825ff1042 100644 (file)
@@ -1501,6 +1501,7 @@ static int axienet_of_probe(struct platform_device *op)
        lp->regs = of_iomap(op->dev.of_node, 0);
        if (!lp->regs) {
                dev_err(&op->dev, "could not map Axi Ethernet regs.\n");
+               ret = -ENOMEM;
                goto nodev;
        }
        /* Setup checksum offload, but default to off if not specified */
@@ -1555,10 +1556,6 @@ static int axienet_of_probe(struct platform_device *op)
                if ((be32_to_cpup(p)) >= 0x4000)
                        lp->jumbo_support = 1;
        }
-       p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,temac-type",
-                                      NULL);
-       if (p)
-               lp->temac_type = be32_to_cpup(p);
        p = (__be32 *) of_get_property(op->dev.of_node, "xlnx,phy-type", NULL);
        if (p)
                lp->phy_type = be32_to_cpup(p);
@@ -1567,6 +1564,7 @@ static int axienet_of_probe(struct platform_device *op)
        np = of_parse_phandle(op->dev.of_node, "axistream-connected", 0);
        if (!np) {
                dev_err(&op->dev, "could not find DMA node\n");
+               ret = -ENODEV;
                goto err_iounmap;
        }
        lp->dma_regs = of_iomap(np, 0);
index 24858799c204fbe2640ad375b5ea75154b6aa795..9d4ce388510a5034b2f29d890645afdda73b23f0 100644 (file)
@@ -1109,6 +1109,7 @@ static int xemaclite_of_probe(struct platform_device *ofdev)
        res = platform_get_resource(ofdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(dev, "no IRQ found\n");
+               rc = -ENXIO;
                goto error;
        }
 
index 2f48f790c9b43e983f44107a97f42f2268262099..384ca4f4de4a0e6ee6b053440937d96a272c4850 100644 (file)
@@ -590,6 +590,7 @@ struct nvsp_message {
 
 
 #define NETVSC_RECEIVE_BUFFER_ID               0xcafe
+#define NETVSC_SEND_BUFFER_ID                  0
 
 #define NETVSC_PACKET_SIZE                      4096
 
index dd867e6cabd6167342b7a3875c427b94321650bf..9f49c0129a78a63f9a473012162ab74260f9449a 100644 (file)
@@ -161,8 +161,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)
 
        /* Deal with the send buffer we may have setup.
         * If we got a  send section size, it means we received a
-        * SendsendBufferComplete msg (ie sent
-        * NvspMessage1TypeSendReceiveBuffer msg) therefore, we need
+        * NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE msg (ie sent
+        * NVSP_MSG1_TYPE_SEND_SEND_BUF msg) therefore, we need
         * to send a revoke msg here
         */
        if (net_device->send_section_size) {
@@ -172,7 +172,8 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)
 
                revoke_packet->hdr.msg_type =
                        NVSP_MSG1_TYPE_REVOKE_SEND_BUF;
-               revoke_packet->msg.v1_msg.revoke_recv_buf.id = 0;
+               revoke_packet->msg.v1_msg.revoke_send_buf.id =
+                       NETVSC_SEND_BUFFER_ID;
 
                ret = vmbus_sendpacket(net_device->dev->channel,
                                       revoke_packet,
@@ -204,7 +205,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)
                net_device->send_buf_gpadl_handle = 0;
        }
        if (net_device->send_buf) {
-               /* Free up the receive buffer */
+               /* Free up the send buffer */
                vfree(net_device->send_buf);
                net_device->send_buf = NULL;
        }
@@ -339,9 +340,9 @@ static int netvsc_init_buf(struct hv_device *device)
        init_packet = &net_device->channel_init_pkt;
        memset(init_packet, 0, sizeof(struct nvsp_message));
        init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_SEND_BUF;
-       init_packet->msg.v1_msg.send_recv_buf.gpadl_handle =
+       init_packet->msg.v1_msg.send_send_buf.gpadl_handle =
                net_device->send_buf_gpadl_handle;
-       init_packet->msg.v1_msg.send_recv_buf.id = 0;
+       init_packet->msg.v1_msg.send_send_buf.id = NETVSC_SEND_BUFFER_ID;
 
        /* Send the gpadl notification request */
        ret = vmbus_sendpacket(device->channel, init_packet,
@@ -364,7 +365,7 @@ static int netvsc_init_buf(struct hv_device *device)
                netdev_err(ndev, "Unable to complete send buffer "
                           "initialization with NetVsp - status %d\n",
                           init_packet->msg.v1_msg.
-                          send_recv_buf_complete.status);
+                          send_send_buf_complete.status);
                ret = -EINVAL;
                goto cleanup;
        }
index a14d87783245a94986232fbbe20b64a57194359d..2e195289ddf4cf4ae4bab1c6fd0068789a60f8ed 100644 (file)
@@ -377,9 +377,11 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb)
        };
 
        dst = ip6_route_output(dev_net(dev), NULL, &fl6);
-       if (IS_ERR(dst))
+       if (dst->error) {
+               ret = dst->error;
+               dst_release(dst);
                goto err;
-
+       }
        skb_dst_drop(skb);
        skb_dst_set(skb, dst);
        err = ip6_local_out(skb);
index c530de1e63f5d5eb5bf0ee6e12a7cb25cded50bb..3ad8ca76196d8254afd41359a437a7716defeecb 100644 (file)
@@ -88,6 +88,7 @@ struct kszphy_priv {
 
 static const struct kszphy_type ksz8021_type = {
        .led_mode_reg           = MII_KSZPHY_CTRL_2,
+       .has_broadcast_disable  = true,
        .has_rmii_ref_clk_sel   = true,
 };
 
@@ -258,19 +259,6 @@ static int kszphy_config_init(struct phy_device *phydev)
        return 0;
 }
 
-static int ksz8021_config_init(struct phy_device *phydev)
-{
-       int rc;
-
-       rc = kszphy_config_init(phydev);
-       if (rc)
-               return rc;
-
-       rc = kszphy_broadcast_disable(phydev);
-
-       return rc < 0 ? rc : 0;
-}
-
 static int ksz9021_load_values_from_of(struct phy_device *phydev,
                                       struct device_node *of_node, u16 reg,
                                       char *field1, char *field2,
@@ -584,7 +572,7 @@ static struct phy_driver ksphy_driver[] = {
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8021_type,
        .probe          = kszphy_probe,
-       .config_init    = ksz8021_config_init,
+       .config_init    = kszphy_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
@@ -601,7 +589,7 @@ static struct phy_driver ksphy_driver[] = {
        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
        .driver_data    = &ksz8021_type,
        .probe          = kszphy_probe,
-       .config_init    = ksz8021_config_init,
+       .config_init    = kszphy_config_init,
        .config_aneg    = genphy_config_aneg,
        .read_status    = genphy_read_status,
        .ack_interrupt  = kszphy_ack_interrupt,
index 93e224217e24b36b089102be11ada5921f62d83b..f7ff493f1e73dfa129dbb10ed68c6436c52a4b1b 100644 (file)
@@ -629,6 +629,7 @@ static int team_change_mode(struct team *team, const char *kind)
 static void team_notify_peers_work(struct work_struct *work)
 {
        struct team *team;
+       int val;
 
        team = container_of(work, struct team, notify_peers.dw.work);
 
@@ -636,9 +637,14 @@ static void team_notify_peers_work(struct work_struct *work)
                schedule_delayed_work(&team->notify_peers.dw, 0);
                return;
        }
+       val = atomic_dec_if_positive(&team->notify_peers.count_pending);
+       if (val < 0) {
+               rtnl_unlock();
+               return;
+       }
        call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, team->dev);
        rtnl_unlock();
-       if (!atomic_dec_and_test(&team->notify_peers.count_pending))
+       if (val)
                schedule_delayed_work(&team->notify_peers.dw,
                                      msecs_to_jiffies(team->notify_peers.interval));
 }
@@ -669,6 +675,7 @@ static void team_notify_peers_fini(struct team *team)
 static void team_mcast_rejoin_work(struct work_struct *work)
 {
        struct team *team;
+       int val;
 
        team = container_of(work, struct team, mcast_rejoin.dw.work);
 
@@ -676,9 +683,14 @@ static void team_mcast_rejoin_work(struct work_struct *work)
                schedule_delayed_work(&team->mcast_rejoin.dw, 0);
                return;
        }
+       val = atomic_dec_if_positive(&team->mcast_rejoin.count_pending);
+       if (val < 0) {
+               rtnl_unlock();
+               return;
+       }
        call_netdevice_notifiers(NETDEV_RESEND_IGMP, team->dev);
        rtnl_unlock();
-       if (!atomic_dec_and_test(&team->mcast_rejoin.count_pending))
+       if (val)
                schedule_delayed_work(&team->mcast_rejoin.dw,
                                      msecs_to_jiffies(team->mcast_rejoin.interval));
 }
index dcb6d33141e0640f545555848434d8efd7822878..1e9cdca370144cffb22141e4c03aa3ff800aefdd 100644 (file)
@@ -1276,7 +1276,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
         awd.done = 0;
 
         urb->context = &awd;
-        status = usb_submit_urb(urb, GFP_NOIO);
+        status = usb_submit_urb(urb, GFP_ATOMIC);
         if (status) {
                 // something went wrong
                 usb_free_urb(urb);
index b8a82b86f909095632c7d5747b9bf25cb81c970e..602dc6668c3af7ce9f6cc4ddd61437ba2f6adf29 100644 (file)
@@ -56,6 +56,8 @@ struct qmi_wwan_state {
 /* default ethernet address used by the modem */
 static const u8 default_modem_addr[ETH_ALEN] = {0x02, 0x50, 0xf3};
 
+static const u8 buggy_fw_addr[ETH_ALEN] = {0x00, 0xa0, 0xc6, 0x00, 0x00, 0x00};
+
 /* Make up an ethernet header if the packet doesn't have one.
  *
  * A firmware bug common among several devices cause them to send raw
@@ -332,10 +334,12 @@ next_desc:
                usb_driver_release_interface(driver, info->data);
        }
 
-       /* Never use the same address on both ends of the link, even
-        * if the buggy firmware told us to.
+       /* Never use the same address on both ends of the link, even if the
+        * buggy firmware told us to. Or, if device is assigned the well-known
+        * buggy firmware MAC address, replace it with a random address,
         */
-       if (ether_addr_equal(dev->net->dev_addr, default_modem_addr))
+       if (ether_addr_equal(dev->net->dev_addr, default_modem_addr) ||
+           ether_addr_equal(dev->net->dev_addr, buggy_fw_addr))
                eth_hw_addr_random(dev->net);
 
        /* make MAC addr easily distinguishable from an IP header */
index 2d1c77e81836c617364d668eecf064d0256063f5..bf405f134d3aa69c60006536da0419f4a2b1f06b 100644 (file)
@@ -833,9 +833,6 @@ static void ocp_write_word(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
-
-       data |= __le32_to_cpu(tmp) & ~mask;
        tmp = __cpu_to_le32(data);
 
        generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
@@ -874,9 +871,6 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data)
                index &= ~3;
        }
 
-       generic_ocp_read(tp, index, sizeof(tmp), &tmp, type);
-
-       data |= __le32_to_cpu(tmp) & ~mask;
        tmp = __cpu_to_le32(data);
 
        generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type);
@@ -926,12 +920,6 @@ static void sram_write(struct r8152 *tp, u16 addr, u16 data)
        ocp_reg_write(tp, OCP_SRAM_DATA, data);
 }
 
-static u16 sram_read(struct r8152 *tp, u16 addr)
-{
-       ocp_reg_write(tp, OCP_SRAM_ADDR, addr);
-       return ocp_reg_read(tp, OCP_SRAM_DATA);
-}
-
 static int read_mii_word(struct net_device *netdev, int phy_id, int reg)
 {
        struct r8152 *tp = netdev_priv(netdev);
@@ -1897,6 +1885,22 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev)
        netif_wake_queue(netdev);
 }
 
+static netdev_features_t
+rtl8152_features_check(struct sk_buff *skb, struct net_device *dev,
+                      netdev_features_t features)
+{
+       u32 mss = skb_shinfo(skb)->gso_size;
+       int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX;
+       int offset = skb_transport_offset(skb);
+
+       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset)
+               features &= ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK);
+       else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz)
+               features &= ~NETIF_F_GSO_MASK;
+
+       return features;
+}
+
 static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
                                      struct net_device *netdev)
 {
@@ -2502,24 +2506,18 @@ static void r8153_hw_phy_cfg(struct r8152 *tp)
        data = ocp_reg_read(tp, OCP_POWER_CFG);
        data |= EN_10M_PLLOFF;
        ocp_reg_write(tp, OCP_POWER_CFG, data);
-       data = sram_read(tp, SRAM_IMPEDANCE);
-       data &= ~RX_DRIVING_MASK;
-       sram_write(tp, SRAM_IMPEDANCE, data);
+       sram_write(tp, SRAM_IMPEDANCE, 0x0b13);
 
        ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR);
        ocp_data |= PFM_PWM_SWITCH;
        ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
 
-       data = sram_read(tp, SRAM_LPF_CFG);
-       data |= LPF_AUTO_TUNE;
-       sram_write(tp, SRAM_LPF_CFG, data);
+       /* Enable LPF corner auto tune */
+       sram_write(tp, SRAM_LPF_CFG, 0xf70f);
 
-       data = sram_read(tp, SRAM_10M_AMP1);
-       data |= GDAC_IB_UPALL;
-       sram_write(tp, SRAM_10M_AMP1, data);
-       data = sram_read(tp, SRAM_10M_AMP2);
-       data |= AMP_DN;
-       sram_write(tp, SRAM_10M_AMP2, data);
+       /* Adjust 10M Amplitude */
+       sram_write(tp, SRAM_10M_AMP1, 0x00af);
+       sram_write(tp, SRAM_10M_AMP2, 0x0208);
 
        set_bit(PHY_RESET, &tp->flags);
 }
@@ -3706,6 +3704,7 @@ static const struct net_device_ops rtl8152_netdev_ops = {
        .ndo_set_mac_address    = rtl8152_set_mac_address,
        .ndo_change_mtu         = rtl8152_change_mtu,
        .ndo_validate_addr      = eth_validate_addr,
+       .ndo_features_check     = rtl8152_features_check,
 };
 
 static void r8152b_get_version(struct r8152 *tp)
index b8bd7191572dca25315c71558b434902720a63cc..5ca97713bfb33b5d5a7770f3ae6a2000a19df423 100644 (file)
@@ -760,7 +760,6 @@ static int virtnet_poll(struct napi_struct *napi, int budget)
                container_of(napi, struct receive_queue, napi);
        unsigned int r, received = 0;
 
-again:
        received += virtnet_receive(rq, budget - received);
 
        /* Out of packets? */
@@ -771,7 +770,6 @@ again:
                    napi_schedule_prep(napi)) {
                        virtqueue_disable_cb(rq->vq);
                        __napi_schedule(napi);
-                       goto again;
                }
        }
 
index 49d9f229199851c48f5a9e6f1b282b42cedc2a41..7fbd89fbe107878f5c2be4358bb13420ca6389ec 100644 (file)
@@ -1579,8 +1579,10 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
        bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk);
 
        skb = udp_tunnel_handle_offloads(skb, udp_sum);
-       if (IS_ERR(skb))
-               return -EINVAL;
+       if (IS_ERR(skb)) {
+               err = -EINVAL;
+               goto err;
+       }
 
        skb_scrub_packet(skb, xnet);
 
@@ -1590,12 +1592,16 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
 
        /* Need space for new headers (invalidates iph ptr) */
        err = skb_cow_head(skb, min_headroom);
-       if (unlikely(err))
-               return err;
+       if (unlikely(err)) {
+               kfree_skb(skb);
+               goto err;
+       }
 
        skb = vlan_hwaccel_push_inside(skb);
-       if (WARN_ON(!skb))
-               return -ENOMEM;
+       if (WARN_ON(!skb)) {
+               err = -ENOMEM;
+               goto err;
+       }
 
        vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
        vxh->vx_flags = htonl(VXLAN_FLAGS);
@@ -1606,6 +1612,9 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
        udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
                             ttl, src_port, dst_port);
        return 0;
+err:
+       dst_release(dst);
+       return err;
 }
 #endif
 
@@ -1621,7 +1630,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
 
        skb = udp_tunnel_handle_offloads(skb, udp_sum);
        if (IS_ERR(skb))
-               return -EINVAL;
+               return PTR_ERR(skb);
 
        min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
                        + VXLAN_HLEN + sizeof(struct iphdr)
@@ -1629,8 +1638,10 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
 
        /* Need space for new headers (invalidates iph ptr) */
        err = skb_cow_head(skb, min_headroom);
-       if (unlikely(err))
+       if (unlikely(err)) {
+               kfree_skb(skb);
                return err;
+       }
 
        skb = vlan_hwaccel_push_inside(skb);
        if (WARN_ON(!skb))
@@ -1776,9 +1787,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
                                     tos, ttl, df, src_port, dst_port,
                                     htonl(vni << 8),
                                     !net_eq(vxlan->net, dev_net(vxlan->dev)));
-
-               if (err < 0)
+               if (err < 0) {
+                       /* skb is already freed. */
+                       skb = NULL;
                        goto rt_tx_error;
+               }
+
                iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
 #if IS_ENABLED(CONFIG_IPV6)
        } else {
index 9a72640237cb7678500468343e6f09101c169e81..62b0bf4fdf6b0144f4696703113f344b2993546c 100644 (file)
@@ -285,6 +285,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
 
        __ath_cancel_work(sc);
 
+       disable_irq(sc->irq);
        tasklet_disable(&sc->intr_tq);
        tasklet_disable(&sc->bcon_tasklet);
        spin_lock_bh(&sc->sc_pcu_lock);
@@ -331,6 +332,7 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan)
                r = -EIO;
 
 out:
+       enable_irq(sc->irq);
        spin_unlock_bh(&sc->sc_pcu_lock);
        tasklet_enable(&sc->bcon_tasklet);
        tasklet_enable(&sc->intr_tq);
@@ -512,9 +514,6 @@ irqreturn_t ath_isr(int irq, void *dev)
        if (!ah || test_bit(ATH_OP_INVALID, &common->op_flags))
                return IRQ_NONE;
 
-       if (!AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
-               return IRQ_NONE;
-
        /* shared irq, not for us */
        if (!ath9k_hw_intrpend(ah))
                return IRQ_NONE;
@@ -529,7 +528,7 @@ irqreturn_t ath_isr(int irq, void *dev)
        ath9k_debug_sync_cause(sc, sync_cause);
        status &= ah->imask;    /* discard unasked-for bits */
 
-       if (AR_SREV_9100(ah) && test_bit(ATH_OP_HW_RESET, &common->op_flags))
+       if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
                return IRQ_HANDLED;
 
        /*
index 3c06e9365949a02e03e96d0f9fb51df9c006451c..9880dae2a56994b1e75a13acbba740e3af0aec7a 100644 (file)
@@ -1070,7 +1070,7 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
         */
        if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
            ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
-            (sdiodev->pdata->oob_irq_supported)))
+            (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
                bus_if->wowl_supported = true;
 #endif
 
@@ -1167,7 +1167,7 @@ static int brcmf_ops_sdio_resume(struct device *dev)
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
        brcmf_dbg(SDIO, "Enter\n");
-       if (sdiodev->pdata->oob_irq_supported)
+       if (sdiodev->pdata && sdiodev->pdata->oob_irq_supported)
                disable_irq_wake(sdiodev->pdata->oob_irq_nr);
        brcmf_sdio_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS);
        atomic_set(&sdiodev->suspend, false);
index 91c0cb3c368e07d4dfd889d0ea5c765b395742d6..21de4fe6cf2d0ff87f46ef0b280d2a53f0999dc3 100644 (file)
@@ -65,7 +65,8 @@ config IPW2100_DEBUG
 
 config IPW2200
        tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection"
-       depends on PCI && CFG80211 && CFG80211_WEXT
+       depends on PCI && CFG80211
+       select CFG80211_WEXT
        select WIRELESS_EXT
        select WEXT_SPY
        select WEXT_PRIV
index e5be2d21868fa975619b72fb8217cad0f54cefe6..a5f9198d57473e6ab18966ca58ec88047f4428dc 100644 (file)
@@ -69,8 +69,8 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL7260_UCODE_API_MAX  10
-#define IWL3160_UCODE_API_MAX  10
+#define IWL7260_UCODE_API_MAX  12
+#define IWL3160_UCODE_API_MAX  12
 
 /* Oldest version we won't warn about */
 #define IWL7260_UCODE_API_OK   10
 #define IWL7265_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
 
 #define IWL7265D_FW_PRE "iwlwifi-7265D-"
-#define IWL7265D_MODULE_FIRMWARE(api) IWL7265_FW_PRE __stringify(api) ".ucode"
+#define IWL7265D_MODULE_FIRMWARE(api) IWL7265D_FW_PRE __stringify(api) ".ucode"
 
 #define NVM_HW_SECTION_NUM_FAMILY_7000         0
 
index bf0a95cb71535f390dfcfcc5820d39901359d440..3668fc57e7708be5e655353078f0bb44589ad6a1 100644 (file)
@@ -69,7 +69,7 @@
 #include "iwl-agn-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX  10
+#define IWL8000_UCODE_API_MAX  12
 
 /* Oldest version we won't warn about */
 #define IWL8000_UCODE_API_OK   10
index 38de1513e4dedd5588367e44d2877ceed39234b6..850b85a478063b9a5fc8ddc1e31eedb5b83b18c2 100644 (file)
@@ -1323,10 +1323,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
 
  try_again:
        /* try next, if any */
-       kfree(pieces);
        release_firmware(ucode_raw);
        if (iwl_request_firmware(drv, false))
                goto out_unbind;
+       kfree(pieces);
        return;
 
  out_free_fw:
index 9564ae173d060a46bd34c60970ce77d6eb483a73..1f7f15eb86da208df591ae8e7ca27e52c5921acf 100644 (file)
@@ -310,6 +310,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE      (0x01000000)
 
 #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT        28
+#define FH_MEM_TB_MAX_LENGTH                   (0x00020000)
 
 /* TFDB  Area - TFDs buffer table */
 #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
index f2a047f6bb3e519a6ab3ce3032be18aac3aa9aa9..660ddb1b7d8a4280e2ed62f679b4f32867a053ec 100644 (file)
@@ -243,6 +243,10 @@ enum iwl_ucode_tlv_flag {
  * @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
  * @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
  *     longer than the passive one, which is essential for fragmented scan.
+ * @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
+ *     regardless of the band or the number of the probes. FW will calculate
+ *     the actual dwell time.
+ * @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too.
  */
 enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID     = BIT(0),
@@ -253,6 +257,8 @@ enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_LMAC_SCAN             = BIT(6),
        IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF     = BIT(7),
        IWL_UCODE_TLV_API_FRAGMENTED_SCAN       = BIT(8),
+       IWL_UCODE_TLV_API_BASIC_DWELL           = BIT(13),
+       IWL_UCODE_TLV_API_SINGLE_SCAN_EBS       = BIT(16),
 };
 
 /**
index 1f2acf47bfb2c78ddb1ee623f9254e35fa8eb109..cfc0e65b34a5e14494d83af1b560d0a33493aa66 100644 (file)
@@ -653,8 +653,11 @@ enum iwl_scan_channel_flags {
 };
 
 /* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
- * @flags: enum iwl_scan_channel_flgs
- * @non_ebs_ratio: how many regular scan iteration before EBS
+ * @flags: enum iwl_scan_channel_flags
+ * @non_ebs_ratio: defines the ratio of number of scan iterations where EBS is
+ *     involved.
+ *     1 - EBS is disabled.
+ *     2 - every second scan will be full scan(and so on).
  */
 struct iwl_scan_channel_opt {
        __le16 flags;
@@ -672,6 +675,7 @@ struct iwl_scan_channel_opt {
  * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented
  * @IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED: insert WFA vendor-specific TPC report
  *     and DS parameter set IEs into probe requests.
+ * @IWL_MVM_LMAC_SCAN_FLAG_MATCH: Send match found notification on matches
  */
 enum iwl_mvm_lmac_scan_flags {
        IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL         = BIT(0),
@@ -681,6 +685,7 @@ enum iwl_mvm_lmac_scan_flags {
        IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS   = BIT(4),
        IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED       = BIT(5),
        IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED     = BIT(6),
+       IWL_MVM_LMAC_SCAN_FLAG_MATCH            = BIT(9),
 };
 
 enum iwl_scan_priority {
index 31a5b3f4266c3edaf26a05dfca208ddd2082f8ca..20915587c8207a46bf7525db41df3af98c46404a 100644 (file)
@@ -1004,8 +1004,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
 {
        lockdep_assert_held(&mvm->mutex);
 
-       /* disallow low power states when the FW is down */
-       iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+       /*
+        * Disallow low power states when the FW is down by taking
+        * the UCODE_DOWN ref. in case of ongoing hw restart the
+        * ref is already taken, so don't take it again.
+        */
+       if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+               iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
 
        /* async_handlers_wk is now blocked */
 
@@ -1023,6 +1028,12 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
        /* the fw is stopped, the aux sta is dead: clean up driver state */
        iwl_mvm_del_aux_sta(mvm);
 
+       /*
+        * Clear IN_HW_RESTART flag when stopping the hw (as restart_complete()
+        * won't be called in this case).
+        */
+       clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
+
        mvm->ucode_loaded = false;
 }
 
@@ -3332,18 +3343,16 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
                msk |= mvmsta->tfd_queue_msk;
        }
 
-       if (drop) {
-               if (iwl_mvm_flush_tx_path(mvm, msk, true))
-                       IWL_ERR(mvm, "flush request fail\n");
-               mutex_unlock(&mvm->mutex);
-       } else {
-               mutex_unlock(&mvm->mutex);
+       msk &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
 
-               /* this can take a while, and we may need/want other operations
-                * to succeed while doing this, so do it without the mutex held
-                */
-               iwl_trans_wait_tx_queue_empty(mvm->trans, msk);
-       }
+       if (iwl_mvm_flush_tx_path(mvm, msk, true))
+               IWL_ERR(mvm, "flush request fail\n");
+       mutex_unlock(&mvm->mutex);
+
+       /* this can take a while, and we may need/want other operations
+        * to succeed while doing this, so do it without the mutex held
+        */
+       iwl_trans_wait_tx_queue_empty(mvm->trans, msk);
 }
 
 const struct ieee80211_ops iwl_mvm_hw_ops = {
index e5294d01181e404c44d78190df5ae869d8c0cd21..844bf7c4c8def639dbc65329fe9f4e157715cbdf 100644 (file)
@@ -72,6 +72,8 @@
 
 #define IWL_PLCP_QUIET_THRESH 1
 #define IWL_ACTIVE_QUIET_TIME 10
+#define IWL_DENSE_EBS_SCAN_RATIO 5
+#define IWL_SPARSE_EBS_SCAN_RATIO 1
 
 struct iwl_mvm_scan_params {
        u32 max_out_time;
@@ -171,15 +173,21 @@ static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
  * already included in the probe template, so we need to set only
  * req->n_ssids - 1 bits in addition to the first bit.
  */
-static u16 iwl_mvm_get_active_dwell(enum ieee80211_band band, int n_ssids)
+static u16 iwl_mvm_get_active_dwell(struct iwl_mvm *mvm,
+                                   enum ieee80211_band band, int n_ssids)
 {
+       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL)
+               return 10;
        if (band == IEEE80211_BAND_2GHZ)
                return 20  + 3 * (n_ssids + 1);
        return 10  + 2 * (n_ssids + 1);
 }
 
-static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
+static u16 iwl_mvm_get_passive_dwell(struct iwl_mvm *mvm,
+                                    enum ieee80211_band band)
 {
+       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_BASIC_DWELL)
+                       return 110;
        return band == IEEE80211_BAND_2GHZ ? 100 + 20 : 100 + 10;
 }
 
@@ -331,7 +339,8 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
                 */
                if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
                        u32 passive_dwell =
-                               iwl_mvm_get_passive_dwell(IEEE80211_BAND_2GHZ);
+                               iwl_mvm_get_passive_dwell(mvm,
+                                                         IEEE80211_BAND_2GHZ);
                        params->max_out_time = passive_dwell;
                } else {
                        params->passive_fragmented = true;
@@ -348,8 +357,8 @@ not_bound:
                        params->dwell[band].passive = frag_passive_dwell;
                else
                        params->dwell[band].passive =
-                               iwl_mvm_get_passive_dwell(band);
-               params->dwell[band].active = iwl_mvm_get_active_dwell(band,
+                               iwl_mvm_get_passive_dwell(mvm, band);
+               params->dwell[band].active = iwl_mvm_get_active_dwell(mvm, band,
                                                                      n_ssids);
        }
 }
@@ -1098,6 +1107,12 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
                return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN,
                                          notify);
 
+       if (mvm->scan_status == IWL_MVM_SCAN_NONE)
+               return 0;
+
+       if (iwl_mvm_is_radio_killed(mvm))
+               goto out;
+
        if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
            (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
             mvm->scan_status != IWL_MVM_SCAN_OS)) {
@@ -1134,6 +1149,7 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
        if (mvm->scan_status == IWL_MVM_SCAN_OS)
                iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
 
+out:
        mvm->scan_status = IWL_MVM_SCAN_NONE;
 
        if (notify) {
@@ -1290,18 +1306,6 @@ iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
        cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
        cmd->iter_num = cpu_to_le32(1);
 
-       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
-           mvm->last_ebs_successful) {
-               cmd->channel_opt[0].flags =
-                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
-                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
-                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
-               cmd->channel_opt[1].flags =
-                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
-                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
-                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
-       }
-
        if (iwl_mvm_rrm_scan_needed(mvm))
                cmd->scan_flags |=
                        cpu_to_le32(IWL_MVM_LMAC_SCAN_FLAGS_RRM_ENABLED);
@@ -1376,6 +1380,22 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
        cmd->schedule[1].iterations = 0;
        cmd->schedule[1].full_scan_mul = 0;
 
+       if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
+           mvm->last_ebs_successful) {
+               cmd->channel_opt[0].flags =
+                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+               cmd->channel_opt[0].non_ebs_ratio =
+                       cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
+               cmd->channel_opt[1].flags =
+                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+               cmd->channel_opt[1].non_ebs_ratio =
+                       cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
+       }
+
        for (i = 1; i <= req->req.n_ssids; i++)
                ssid_bitmap |= BIT(i);
 
@@ -1448,6 +1468,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
 
        if (iwl_mvm_scan_pass_all(mvm, req))
                flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
+       else
+               flags |= IWL_MVM_LMAC_SCAN_FLAG_MATCH;
 
        if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
                flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
@@ -1474,6 +1496,22 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
        cmd->schedule[1].iterations = 0xff;
        cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
 
+       if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
+           mvm->last_ebs_successful) {
+               cmd->channel_opt[0].flags =
+                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+               cmd->channel_opt[0].non_ebs_ratio =
+                       cpu_to_le16(IWL_DENSE_EBS_SCAN_RATIO);
+               cmd->channel_opt[1].flags =
+                       cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
+                                   IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+                                   IWL_SCAN_CHANNEL_FLAG_CACHE_ADD);
+               cmd->channel_opt[1].non_ebs_ratio =
+                       cpu_to_le16(IWL_SPARSE_EBS_SCAN_RATIO);
+       }
+
        iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
                                       ssid_bitmap, cmd);
 
index 4f15d9decc81bd4fe80bd2ac716667e2c3b97aa1..c59d07567d9041688401c0345376e9dc52de3157 100644 (file)
@@ -90,8 +90,6 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
 
        if (ieee80211_is_probe_resp(fc))
                tx_flags |= TX_CMD_FLG_TSF;
-       else if (ieee80211_is_back_req(fc))
-               tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
 
        if (ieee80211_has_morefrags(fc))
                tx_flags |= TX_CMD_FLG_MORE_FRAG;
@@ -100,6 +98,15 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
                u8 *qc = ieee80211_get_qos_ctl(hdr);
                tx_cmd->tid_tspec = qc[0] & 0xf;
                tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
+       } else if (ieee80211_is_back_req(fc)) {
+               struct ieee80211_bar *bar = (void *)skb->data;
+               u16 control = le16_to_cpu(bar->control);
+
+               tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR;
+               tx_cmd->tid_tspec = (control &
+                                    IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
+                       IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
+               WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT);
        } else {
                tx_cmd->tid_tspec = IWL_TID_NON_QOS;
                if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)
@@ -108,8 +115,12 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb,
                        tx_flags &= ~TX_CMD_FLG_SEQ_CTL;
        }
 
-       /* tid_tspec will default to 0 = BE when QOS isn't enabled */
-       ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
+       /* Default to 0 (BE) when tid_spec is set to IWL_TID_NON_QOS */
+       if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT)
+               ac = tid_to_mac80211_ac[tx_cmd->tid_tspec];
+       else
+               ac = tid_to_mac80211_ac[0];
+
        tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, hdr, info, ac) <<
                        TX_CMD_FLG_BT_PRIO_POS;
 
index e56e77ef5d2e3d28d9a30185ef257aa43912ed23..917431e30f747bf9411c8c33b1f013d18b14f29e 100644 (file)
@@ -665,7 +665,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
        if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
                return false;
 
-       if (!mvm->cfg->rx_with_siso_diversity)
+       if (mvm->cfg->rx_with_siso_diversity)
                return false;
 
        ieee80211_iterate_active_interfaces_atomic(
index 3ee8e3848876f48cce72ce98dff2e2bfde875a23..d5aadb00dd9e4a6acf4e29c72dd0d55d59d59203 100644 (file)
@@ -367,7 +367,11 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
 
 /* 3165 Series */
        {IWL_PCI_DEVICE(0x3165, 0x4010, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4012, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4110, iwl3165_2ac_cfg)},
        {IWL_PCI_DEVICE(0x3165, 0x4210, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4410, iwl3165_2ac_cfg)},
+       {IWL_PCI_DEVICE(0x3165, 0x4510, iwl3165_2ac_cfg)},
 
 /* 7265 Series */
        {IWL_PCI_DEVICE(0x095A, 0x5010, iwl7265_2ac_cfg)},
@@ -523,8 +527,10 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        else if (cfg == &iwl7265_n_cfg)
                cfg_7265d = &iwl7265d_n_cfg;
        if (cfg_7265d &&
-           (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D)
+           (iwl_trans->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) {
                cfg = cfg_7265d;
+               iwl_trans->cfg = cfg_7265d;
+       }
 #endif
 
        pci_set_drvdata(pdev, iwl_trans);
index 5d79a1f44b8e43a723b9de98ca780a9ea5bc5812..523fe0c88dcb2d464ec915085371d376aec22e28 100644 (file)
@@ -614,7 +614,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
 {
        u8 *v_addr;
        dma_addr_t p_addr;
-       u32 offset, chunk_sz = section->len;
+       u32 offset, chunk_sz = min_t(u32, FH_MEM_TB_MAX_LENGTH, section->len);
        int ret = 0;
 
        IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
@@ -1012,16 +1012,21 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        /* Stop the device, and put it in low power state */
        iwl_pcie_apm_stop(trans);
 
-       /* Upon stop, the APM issues an interrupt if HW RF kill is set.
-        * Clean again the interrupt here
+       /* stop and reset the on-board processor */
+       iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+       udelay(20);
+
+       /*
+        * Upon stop, the APM issues an interrupt if HW RF kill is set.
+        * This is a bug in certain verions of the hardware.
+        * Certain devices also keep sending HW RF kill interrupt all
+        * the time, unless the interrupt is ACKed even if the interrupt
+        * should be masked. Re-ACK all the interrupts here.
         */
        spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
        spin_unlock(&trans_pcie->irq_lock);
 
-       /* stop and reset the on-board processor */
-       iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
-       udelay(20);
 
        /* clear all status bits */
        clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);
index 846a2e6e34d855d62726eda65b51ee427bc1a939..c70efb9a6e78ccf22170bb8bbfe0abe89be695ef 100644 (file)
@@ -666,7 +666,8 @@ tx_status_ok:
 }
 
 static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
-                                   u8 *entry, int rxring_idx, int desc_idx)
+                                   struct sk_buff *new_skb, u8 *entry,
+                                   int rxring_idx, int desc_idx)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -674,11 +675,15 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
        u8 tmp_one = 1;
        struct sk_buff *skb;
 
+       if (likely(new_skb)) {
+               skb = new_skb;
+               goto remap;
+       }
        skb = dev_alloc_skb(rtlpci->rxbuffersize);
        if (!skb)
                return 0;
-       rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
 
+remap:
        /* just set skb->cb to mapping addr for pci_unmap_single use */
        *((dma_addr_t *)skb->cb) =
                pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
@@ -686,6 +691,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw,
        bufferaddress = *((dma_addr_t *)skb->cb);
        if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
                return 0;
+       rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb;
        if (rtlpriv->use_new_trx_flow) {
                rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
                                            HW_DESC_RX_PREPARE,
@@ -781,6 +787,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                /*rx pkt */
                struct sk_buff *skb = rtlpci->rx_ring[rxring_idx].rx_buf[
                                      rtlpci->rx_ring[rxring_idx].idx];
+               struct sk_buff *new_skb;
 
                if (rtlpriv->use_new_trx_flow) {
                        rx_remained_cnt =
@@ -807,6 +814,13 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                pci_unmap_single(rtlpci->pdev, *((dma_addr_t *)skb->cb),
                                 rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE);
 
+               /* get a new skb - if fail, old one will be reused */
+               new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+               if (unlikely(!new_skb)) {
+                       pr_err("Allocation of new skb failed in %s\n",
+                              __func__);
+                       goto no_new;
+               }
                if (rtlpriv->use_new_trx_flow) {
                        buffer_desc =
                          &rtlpci->rx_ring[rxring_idx].buffer_desc
@@ -911,14 +925,16 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        schedule_work(&rtlpriv->works.lps_change_work);
                }
 end:
+               skb = new_skb;
+no_new:
                if (rtlpriv->use_new_trx_flow) {
-                       _rtl_pci_init_one_rxdesc(hw, (u8 *)buffer_desc,
+                       _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc,
                                                 rxring_idx,
-                                              rtlpci->rx_ring[rxring_idx].idx);
+                                                rtlpci->rx_ring[rxring_idx].idx);
                } else {
-                       _rtl_pci_init_one_rxdesc(hw, (u8 *)pdesc, rxring_idx,
+                       _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc,
+                                                rxring_idx,
                                                 rtlpci->rx_ring[rxring_idx].idx);
-
                        if (rtlpci->rx_ring[rxring_idx].idx ==
                            rtlpci->rxringcount - 1)
                                rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc,
@@ -1307,7 +1323,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
                rtlpci->rx_ring[rxring_idx].idx = 0;
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        entry = &rtlpci->rx_ring[rxring_idx].buffer_desc[i];
-                       if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+                       if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
                                                      rxring_idx, i))
                                return -ENOMEM;
                }
@@ -1332,7 +1348,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw, int rxring_idx)
 
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        entry = &rtlpci->rx_ring[rxring_idx].desc[i];
-                       if (!_rtl_pci_init_one_rxdesc(hw, (u8 *)entry,
+                       if (!_rtl_pci_init_one_rxdesc(hw, NULL, (u8 *)entry,
                                                      rxring_idx, i))
                                return -ENOMEM;
                }
index efbaf2ae1999a97982a8e57274e3cf09f95b42ec..794204e34fba4fb74d1c21f2fef0837ef340feaa 100644 (file)
@@ -737,6 +737,7 @@ static void connect(struct backend_info *be)
                }
 
                queue->remaining_credit = credit_bytes;
+               queue->credit_usec = credit_usec;
 
                err = connect_rings(be, queue);
                if (err) {
index 22bcb4e12e2a1318fc1802fb3c5ff6b2cb4acf92..d8c10764f13061fd355e0e36abff7c83d3a458a5 100644 (file)
@@ -88,10 +88,8 @@ struct netfront_cb {
 #define IRQ_NAME_SIZE (QUEUE_NAME_SIZE + 3)
 
 struct netfront_stats {
-       u64                     rx_packets;
-       u64                     tx_packets;
-       u64                     rx_bytes;
-       u64                     tx_bytes;
+       u64                     packets;
+       u64                     bytes;
        struct u64_stats_sync   syncp;
 };
 
@@ -160,7 +158,8 @@ struct netfront_info {
        struct netfront_queue *queues;
 
        /* Statistics */
-       struct netfront_stats __percpu *stats;
+       struct netfront_stats __percpu *rx_stats;
+       struct netfront_stats __percpu *tx_stats;
 
        atomic_t rx_gso_checksum_fixup;
 };
@@ -565,7 +564,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        unsigned short id;
        struct netfront_info *np = netdev_priv(dev);
-       struct netfront_stats *stats = this_cpu_ptr(np->stats);
+       struct netfront_stats *tx_stats = this_cpu_ptr(np->tx_stats);
        struct xen_netif_tx_request *tx;
        char *data = skb->data;
        RING_IDX i;
@@ -672,10 +671,10 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (notify)
                notify_remote_via_irq(queue->tx_irq);
 
-       u64_stats_update_begin(&stats->syncp);
-       stats->tx_bytes += skb->len;
-       stats->tx_packets++;
-       u64_stats_update_end(&stats->syncp);
+       u64_stats_update_begin(&tx_stats->syncp);
+       tx_stats->bytes += skb->len;
+       tx_stats->packets++;
+       u64_stats_update_end(&tx_stats->syncp);
 
        /* Note: It is not safe to access skb after xennet_tx_buf_gc()! */
        xennet_tx_buf_gc(queue);
@@ -931,7 +930,7 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb)
 static int handle_incoming_queue(struct netfront_queue *queue,
                                 struct sk_buff_head *rxq)
 {
-       struct netfront_stats *stats = this_cpu_ptr(queue->info->stats);
+       struct netfront_stats *rx_stats = this_cpu_ptr(queue->info->rx_stats);
        int packets_dropped = 0;
        struct sk_buff *skb;
 
@@ -952,10 +951,10 @@ static int handle_incoming_queue(struct netfront_queue *queue,
                        continue;
                }
 
-               u64_stats_update_begin(&stats->syncp);
-               stats->rx_packets++;
-               stats->rx_bytes += skb->len;
-               u64_stats_update_end(&stats->syncp);
+               u64_stats_update_begin(&rx_stats->syncp);
+               rx_stats->packets++;
+               rx_stats->bytes += skb->len;
+               u64_stats_update_end(&rx_stats->syncp);
 
                /* Pass it up. */
                napi_gro_receive(&queue->napi, skb);
@@ -1079,18 +1078,22 @@ static struct rtnl_link_stats64 *xennet_get_stats64(struct net_device *dev,
        int cpu;
 
        for_each_possible_cpu(cpu) {
-               struct netfront_stats *stats = per_cpu_ptr(np->stats, cpu);
+               struct netfront_stats *rx_stats = per_cpu_ptr(np->rx_stats, cpu);
+               struct netfront_stats *tx_stats = per_cpu_ptr(np->tx_stats, cpu);
                u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
                unsigned int start;
 
                do {
-                       start = u64_stats_fetch_begin_irq(&stats->syncp);
+                       start = u64_stats_fetch_begin_irq(&tx_stats->syncp);
+                       tx_packets = tx_stats->packets;
+                       tx_bytes = tx_stats->bytes;
+               } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start));
 
-                       rx_packets = stats->rx_packets;
-                       tx_packets = stats->tx_packets;
-                       rx_bytes = stats->rx_bytes;
-                       tx_bytes = stats->tx_bytes;
-               } while (u64_stats_fetch_retry_irq(&stats->syncp, start));
+               do {
+                       start = u64_stats_fetch_begin_irq(&rx_stats->syncp);
+                       rx_packets = rx_stats->packets;
+                       rx_bytes = rx_stats->bytes;
+               } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
 
                tot->rx_packets += rx_packets;
                tot->tx_packets += tx_packets;
@@ -1275,6 +1278,15 @@ static const struct net_device_ops xennet_netdev_ops = {
 #endif
 };
 
+static void xennet_free_netdev(struct net_device *netdev)
+{
+       struct netfront_info *np = netdev_priv(netdev);
+
+       free_percpu(np->rx_stats);
+       free_percpu(np->tx_stats);
+       free_netdev(netdev);
+}
+
 static struct net_device *xennet_create_dev(struct xenbus_device *dev)
 {
        int err;
@@ -1295,8 +1307,11 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        np->queues = NULL;
 
        err = -ENOMEM;
-       np->stats = netdev_alloc_pcpu_stats(struct netfront_stats);
-       if (np->stats == NULL)
+       np->rx_stats = netdev_alloc_pcpu_stats(struct netfront_stats);
+       if (np->rx_stats == NULL)
+               goto exit;
+       np->tx_stats = netdev_alloc_pcpu_stats(struct netfront_stats);
+       if (np->tx_stats == NULL)
                goto exit;
 
        netdev->netdev_ops      = &xennet_netdev_ops;
@@ -1327,7 +1342,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        return netdev;
 
  exit:
-       free_netdev(netdev);
+       xennet_free_netdev(netdev);
        return ERR_PTR(err);
 }
 
@@ -1369,7 +1384,7 @@ static int netfront_probe(struct xenbus_device *dev,
        return 0;
 
  fail:
-       free_netdev(netdev);
+       xennet_free_netdev(netdev);
        dev_set_drvdata(&dev->dev, NULL);
        return err;
 }
@@ -2189,9 +2204,7 @@ static int xennet_remove(struct xenbus_device *dev)
                info->queues = NULL;
        }
 
-       free_percpu(info->stats);
-
-       free_netdev(info->netdev);
+       xennet_free_netdev(info->netdev);
 
        return 0;
 }
index ea63fbd228ed684234722c6f35db36060559accf..352b4f28f82cd729fb842a210e7460ff9f123833 100644 (file)
@@ -114,17 +114,6 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
                ret = of_overlay_apply_one(ov, tchild, child);
                if (ret)
                        return ret;
-
-               /* The properties are already copied, now do the child nodes */
-               for_each_child_of_node(child, grandchild) {
-                       ret = of_overlay_apply_single_device_node(ov, tchild, grandchild);
-                       if (ret) {
-                               pr_err("%s: Failed to apply single node @%s/%s\n",
-                                       __func__, tchild->full_name,
-                                       grandchild->name);
-                               return ret;
-                       }
-               }
        }
 
        return ret;
index 5b33c6a2180752888a36e7a15f81b81f29c8477a..b0d50d70a8a1d4772cae2075223959406059ea10 100644 (file)
@@ -188,7 +188,7 @@ static void of_dma_configure(struct device *dev)
                size = dev->coherent_dma_mask;
        } else {
                offset = PFN_DOWN(paddr - dma_addr);
-               dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", dev->dma_pfn_offset);
+               dev_dbg(dev, "dma_pfn_offset(%#08lx)\n", offset);
        }
        dev->dma_pfn_offset = offset;
 
@@ -566,6 +566,10 @@ static int of_platform_notify(struct notifier_block *nb,
                if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS))
                        return NOTIFY_OK;       /* not for us */
 
+               /* already populated? (driver using of_populate manually) */
+               if (of_node_check_flag(rd->dn, OF_POPULATED))
+                       return NOTIFY_OK;
+
                /* pdev_parent may be NULL when no bus platform device */
                pdev_parent = of_find_device_by_node(rd->dn->parent);
                pdev = of_platform_device_create(rd->dn, NULL,
@@ -581,6 +585,11 @@ static int of_platform_notify(struct notifier_block *nb,
                break;
 
        case OF_RECONFIG_CHANGE_REMOVE:
+
+               /* already depopulated? */
+               if (!of_node_check_flag(rd->dn, OF_POPULATED))
+                       return NOTIFY_OK;
+
                /* find our device by node */
                pdev = of_find_device_by_node(rd->dn);
                if (pdev == NULL)
index 75976da22b2e2c997fe70d7ea1b6c9a1c622face..a2b687d5f324700a0adff54e991905053445a167 100644 (file)
                        };
                };
 
+               overlay10 {
+                       fragment@0 {
+                               target-path = "/testcase-data/overlay-node/test-bus";
+                               __overlay__ {
+
+                                       /* suppress DTC warning */
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       test-selftest10 {
+                                               compatible = "selftest";
+                                               status = "okay";
+                                               reg = <10>;
+
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               test-selftest101 {
+                                                       compatible = "selftest";
+                                                       status = "okay";
+                                                       reg = <1>;
+                                               };
+
+                                       };
+                               };
+                       };
+               };
+
+               overlay11 {
+                       fragment@0 {
+                               target-path = "/testcase-data/overlay-node/test-bus";
+                               __overlay__ {
+
+                                       /* suppress DTC warning */
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       test-selftest11 {
+                                               compatible = "selftest";
+                                               status = "okay";
+                                               reg = <11>;
+
+                                               #address-cells = <1>;
+                                               #size-cells = <0>;
+
+                                               test-selftest111 {
+                                                       compatible = "selftest";
+                                                       status = "okay";
+                                                       reg = <1>;
+                                               };
+
+                                       };
+                               };
+                       };
+               };
        };
 };
index 844838e11ef1a1f8f4d6ac9b52721a1b668dc6aa..41a4a138f53b26c547296805eaf425ebb359268f 100644 (file)
@@ -978,6 +978,9 @@ static int selftest_probe(struct platform_device *pdev)
        }
 
        dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+
+       of_platform_populate(np, NULL, NULL, &pdev->dev);
+
        return 0;
 }
 
@@ -1385,6 +1388,39 @@ static void of_selftest_overlay_8(void)
        selftest(1, "overlay test %d passed\n", 8);
 }
 
+/* test insertion of a bus with parent devices */
+static void of_selftest_overlay_10(void)
+{
+       int ret;
+       char *child_path;
+
+       /* device should disable */
+       ret = of_selftest_apply_overlay_check(10, 10, 0, 1);
+       if (selftest(ret == 0, "overlay test %d failed; overlay application\n", 10))
+               return;
+
+       child_path = kasprintf(GFP_KERNEL, "%s/test-selftest101",
+                       selftest_path(10));
+       if (selftest(child_path, "overlay test %d failed; kasprintf\n", 10))
+               return;
+
+       ret = of_path_platform_device_exists(child_path);
+       kfree(child_path);
+       if (selftest(ret, "overlay test %d failed; no child device\n", 10))
+               return;
+}
+
+/* test insertion of a bus with parent devices (and revert) */
+static void of_selftest_overlay_11(void)
+{
+       int ret;
+
+       /* device should disable */
+       ret = of_selftest_apply_revert_overlay_check(11, 11, 0, 1);
+       if (selftest(ret == 0, "overlay test %d failed; overlay application\n", 11))
+               return;
+}
+
 static void __init of_selftest_overlay(void)
 {
        struct device_node *bus_np = NULL;
@@ -1433,6 +1469,9 @@ static void __init of_selftest_overlay(void)
        of_selftest_overlay_6();
        of_selftest_overlay_8();
 
+       of_selftest_overlay_10();
+       of_selftest_overlay_11();
+
 out:
        of_node_put(bus_np);
 }
index 37e71ff6408dca41ff5790417f549eead9ddea97..dceb9ddfd99af6d754b0190fe2eb99431f64f4a6 100644 (file)
@@ -694,9 +694,8 @@ lba_fixup_bus(struct pci_bus *bus)
                int i;
                /* PCI-PCI Bridge */
                pci_read_bridge_bases(bus);
-               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
-                       pci_claim_resource(bus->self, i);
-               }
+               for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++)
+                       pci_claim_bridge_resource(bus->self, i);
        } else {
                /* Host-PCI Bridge */
                int err;
index 73aef51a28f0760fefa6b4344235e7f341bebb3d..8fb16188cd82aaff9d346a70f46e0257e468fe29 100644 (file)
@@ -228,6 +228,49 @@ int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
 }
 EXPORT_SYMBOL(pci_bus_alloc_resource);
 
+/*
+ * The @idx resource of @dev should be a PCI-PCI bridge window.  If this
+ * resource fits inside a window of an upstream bridge, do nothing.  If it
+ * overlaps an upstream window but extends outside it, clip the resource so
+ * it fits completely inside.
+ */
+bool pci_bus_clip_resource(struct pci_dev *dev, int idx)
+{
+       struct pci_bus *bus = dev->bus;
+       struct resource *res = &dev->resource[idx];
+       struct resource orig_res = *res;
+       struct resource *r;
+       int i;
+
+       pci_bus_for_each_resource(bus, r, i) {
+               resource_size_t start, end;
+
+               if (!r)
+                       continue;
+
+               if (resource_type(res) != resource_type(r))
+                       continue;
+
+               start = max(r->start, res->start);
+               end = min(r->end, res->end);
+
+               if (start > end)
+                       continue;       /* no overlap */
+
+               if (res->start == start && res->end == end)
+                       return false;   /* no change */
+
+               res->start = start;
+               res->end = end;
+               dev_printk(KERN_DEBUG, &dev->dev, "%pR clipped to %pR\n",
+                                &orig_res, res);
+
+               return true;
+       }
+
+       return false;
+}
+
 void __weak pcibios_resource_survey_bus(struct pci_bus *bus) { }
 
 /**
index cab05f31223f08166cc0a8e179759fc99812a286..e9d4fd861ba1c84a82f9561841d4e1da26715a2a 100644 (file)
@@ -3271,7 +3271,8 @@ static int pci_parent_bus_reset(struct pci_dev *dev, int probe)
 {
        struct pci_dev *pdev;
 
-       if (pci_is_root_bus(dev->bus) || dev->subordinate || !dev->bus->self)
+       if (pci_is_root_bus(dev->bus) || dev->subordinate ||
+           !dev->bus->self || dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
                return -ENOTTY;
 
        list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3305,7 +3306,8 @@ static int pci_dev_reset_slot_function(struct pci_dev *dev, int probe)
 {
        struct pci_dev *pdev;
 
-       if (dev->subordinate || !dev->slot)
+       if (dev->subordinate || !dev->slot ||
+           dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET)
                return -ENOTTY;
 
        list_for_each_entry(pdev, &dev->bus->devices, bus_list)
@@ -3557,6 +3559,20 @@ int pci_try_reset_function(struct pci_dev *dev)
 }
 EXPORT_SYMBOL_GPL(pci_try_reset_function);
 
+/* Do any devices on or below this bus prevent a bus reset? */
+static bool pci_bus_resetable(struct pci_bus *bus)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &bus->devices, bus_list) {
+               if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
+                   (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
+                       return false;
+       }
+
+       return true;
+}
+
 /* Lock devices from the top of the tree down */
 static void pci_bus_lock(struct pci_bus *bus)
 {
@@ -3607,6 +3623,22 @@ unlock:
        return 0;
 }
 
+/* Do any devices on or below this slot prevent a bus reset? */
+static bool pci_slot_resetable(struct pci_slot *slot)
+{
+       struct pci_dev *dev;
+
+       list_for_each_entry(dev, &slot->bus->devices, bus_list) {
+               if (!dev->slot || dev->slot != slot)
+                       continue;
+               if (dev->dev_flags & PCI_DEV_FLAGS_NO_BUS_RESET ||
+                   (dev->subordinate && !pci_bus_resetable(dev->subordinate)))
+                       return false;
+       }
+
+       return true;
+}
+
 /* Lock devices from the top of the tree down */
 static void pci_slot_lock(struct pci_slot *slot)
 {
@@ -3728,7 +3760,7 @@ static int pci_slot_reset(struct pci_slot *slot, int probe)
 {
        int rc;
 
-       if (!slot)
+       if (!slot || !pci_slot_resetable(slot))
                return -ENOTTY;
 
        if (!probe)
@@ -3820,7 +3852,7 @@ EXPORT_SYMBOL_GPL(pci_try_reset_slot);
 
 static int pci_bus_reset(struct pci_bus *bus, int probe)
 {
-       if (!bus->self)
+       if (!bus->self || !pci_bus_resetable(bus))
                return -ENOTTY;
 
        if (probe)
index 8aff29a804ffa6e9ddaa30e2277d5d654f1df508..d54632a1db43cbed30d89fb91b84fef489cbc4a4 100644 (file)
@@ -208,6 +208,7 @@ void __pci_bus_size_bridges(struct pci_bus *bus,
 void __pci_bus_assign_resources(const struct pci_bus *bus,
                                struct list_head *realloc_head,
                                struct list_head *fail_head);
+bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
 
 /**
  * pci_ari_enabled - query ARI forwarding status
index ed6f89b6efe5c2cab127dd15613cab59be736fd7..e52356aa09b87adc778a29bbc3ca40c1ffdf638d 100644 (file)
@@ -3028,6 +3028,20 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169,
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID,
                         quirk_broken_intx_masking);
 
+static void quirk_no_bus_reset(struct pci_dev *dev)
+{
+       dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET;
+}
+
+/*
+ * Atheros AR93xx chips do not behave after a bus reset.  The device will
+ * throw a Link Down error on AER-capable systems and regardless of AER,
+ * config space of the device is never accessible again and typically
+ * causes the system to hang or reset when access is attempted.
+ * http://www.spinics.net/lists/linux-pci/msg34797.html
+ */
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+
 #ifdef CONFIG_ACPI
 /*
  * Apple: Shutdown Cactus Ridge Thunderbolt controller.
index 0482235eee9262f79ecd69f907c8c41c2364d914..e3e17f3c0f0f2929da94d7411c0740a391dc56c6 100644 (file)
@@ -530,9 +530,8 @@ EXPORT_SYMBOL(pci_setup_cardbus);
    config space writes, so it's quite possible that an I/O window of
    the bridge will have some undesirable address (e.g. 0) after the
    first write. Ditto 64-bit prefetchable MMIO.  */
-static void pci_setup_bridge_io(struct pci_bus *bus)
+static void pci_setup_bridge_io(struct pci_dev *bridge)
 {
-       struct pci_dev *bridge = bus->self;
        struct resource *res;
        struct pci_bus_region region;
        unsigned long io_mask;
@@ -545,7 +544,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
                io_mask = PCI_IO_1K_RANGE_MASK;
 
        /* Set up the top and bottom of the PCI I/O segment for this bus. */
-       res = bus->resource[0];
+       res = &bridge->resource[PCI_BRIDGE_RESOURCES + 0];
        pcibios_resource_to_bus(bridge->bus, &region, res);
        if (res->flags & IORESOURCE_IO) {
                pci_read_config_word(bridge, PCI_IO_BASE, &l);
@@ -568,15 +567,14 @@ static void pci_setup_bridge_io(struct pci_bus *bus)
        pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
 }
 
-static void pci_setup_bridge_mmio(struct pci_bus *bus)
+static void pci_setup_bridge_mmio(struct pci_dev *bridge)
 {
-       struct pci_dev *bridge = bus->self;
        struct resource *res;
        struct pci_bus_region region;
        u32 l;
 
        /* Set up the top and bottom of the PCI Memory segment for this bus. */
-       res = bus->resource[1];
+       res = &bridge->resource[PCI_BRIDGE_RESOURCES + 1];
        pcibios_resource_to_bus(bridge->bus, &region, res);
        if (res->flags & IORESOURCE_MEM) {
                l = (region.start >> 16) & 0xfff0;
@@ -588,9 +586,8 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)
        pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
 }
 
-static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
+static void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
 {
-       struct pci_dev *bridge = bus->self;
        struct resource *res;
        struct pci_bus_region region;
        u32 l, bu, lu;
@@ -602,7 +599,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)
 
        /* Set up PREF base/limit. */
        bu = lu = 0;
-       res = bus->resource[2];
+       res = &bridge->resource[PCI_BRIDGE_RESOURCES + 2];
        pcibios_resource_to_bus(bridge->bus, &region, res);
        if (res->flags & IORESOURCE_PREFETCH) {
                l = (region.start >> 16) & 0xfff0;
@@ -630,13 +627,13 @@ static void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
                 &bus->busn_res);
 
        if (type & IORESOURCE_IO)
-               pci_setup_bridge_io(bus);
+               pci_setup_bridge_io(bridge);
 
        if (type & IORESOURCE_MEM)
-               pci_setup_bridge_mmio(bus);
+               pci_setup_bridge_mmio(bridge);
 
        if (type & IORESOURCE_PREFETCH)
-               pci_setup_bridge_mmio_pref(bus);
+               pci_setup_bridge_mmio_pref(bridge);
 
        pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
 }
@@ -649,6 +646,41 @@ void pci_setup_bridge(struct pci_bus *bus)
        __pci_setup_bridge(bus, type);
 }
 
+
+int pci_claim_bridge_resource(struct pci_dev *bridge, int i)
+{
+       if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END)
+               return 0;
+
+       if (pci_claim_resource(bridge, i) == 0)
+               return 0;       /* claimed the window */
+
+       if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+               return 0;
+
+       if (!pci_bus_clip_resource(bridge, i))
+               return -EINVAL; /* clipping didn't change anything */
+
+       switch (i - PCI_BRIDGE_RESOURCES) {
+       case 0:
+               pci_setup_bridge_io(bridge);
+               break;
+       case 1:
+               pci_setup_bridge_mmio(bridge);
+               break;
+       case 2:
+               pci_setup_bridge_mmio_pref(bridge);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (pci_claim_resource(bridge, i) == 0)
+               return 0;       /* claimed a smaller window */
+
+       return -EINVAL;
+}
+
 /* Check whether the bridge supports optional I/O and
    prefetchable memory ranges. If not, the respective
    base/limit registers must be read-only and read as 0. */
index e34da13885e8c422a7fdecc153d6407c0b52999f..27fa62ce613618debb31fadb6bb50a51d9e65893 100644 (file)
@@ -1050,7 +1050,8 @@ static int miphy28lp_init(struct phy *phy)
                ret = miphy28lp_init_usb3(miphy_phy);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
 
        mutex_unlock(&miphy_dev->miphy_mutex);
index c96e8183a8ffe061e017976daa40632ac5a22c56..efe724f97e02fbf9eba84c215628993fa3ea1274 100644 (file)
 /**
  * omap_control_pcie_pcs - set the PCS delay count
  * @dev: the control module device
- * @id: index of the pcie PHY (should be 1 or 2)
  * @delay: 8 bit delay value
  */
-void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay)
+void omap_control_pcie_pcs(struct device *dev, u8 delay)
 {
        u32 val;
        struct omap_control_phy *control_phy;
@@ -55,8 +54,8 @@ void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay)
 
        val = readl(control_phy->pcie_pcs);
        val &= ~(OMAP_CTRL_PCIE_PCS_MASK <<
-               (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT));
-       val |= delay << (id * OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT);
+               OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT);
+       val |= (delay << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT);
        writel(val, control_phy->pcie_pcs);
 }
 EXPORT_SYMBOL_GPL(omap_control_pcie_pcs);
index fb02a67c91811e5291757c8fbb330439c3d95e89..a2b08f3ccb031cbf3a484cb0afab5665c0fb3ad7 100644 (file)
@@ -244,7 +244,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
        else
                data->num_phys = 3;
 
-       if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy"))
+       if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy") ||
+           of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy"))
                data->disc_thresh = 3;
        else
                data->disc_thresh = 2;
index 1387b4d4afe376556661f49938bf71bb85572d94..465de2c800f228d7fa4961083e243349f5fbcd33 100644 (file)
@@ -82,7 +82,6 @@ struct ti_pipe3 {
        struct clk              *refclk;
        struct clk              *div_clk;
        struct pipe3_dpll_map   *dpll_map;
-       u8                      id;
 };
 
 static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -217,8 +216,13 @@ static int ti_pipe3_init(struct phy *x)
        u32 val;
        int ret = 0;
 
+       /*
+        * Set pcie_pcs register to 0x96 for proper functioning of phy
+        * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table
+        * 18-1804.
+        */
        if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) {
-               omap_control_pcie_pcs(phy->control_dev, phy->id, 0xF1);
+               omap_control_pcie_pcs(phy->control_dev, 0x96);
                return 0;
        }
 
@@ -347,8 +351,6 @@ static int ti_pipe3_probe(struct platform_device *pdev)
        }
 
        if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
-               if (of_property_read_u8(node, "id", &phy->id) < 0)
-                       phy->id = 1;
 
                clk = devm_clk_get(phy->dev, "dpll_ref");
                if (IS_ERR(clk)) {
index e4f65510c87e8928666e195b6b76e52cae9252b5..89dca77ca0382e93909188cad63ccd9ef6bff41b 100644 (file)
@@ -1801,14 +1801,15 @@ void pinctrl_unregister(struct pinctrl_dev *pctldev)
        if (pctldev == NULL)
                return;
 
-       mutex_lock(&pinctrldev_list_mutex);
        mutex_lock(&pctldev->mutex);
-
        pinctrl_remove_device_debugfs(pctldev);
+       mutex_unlock(&pctldev->mutex);
 
        if (!IS_ERR(pctldev->p))
                pinctrl_put(pctldev->p);
 
+       mutex_lock(&pinctrldev_list_mutex);
+       mutex_lock(&pctldev->mutex);
        /* TODO: check that no pinmuxes are still active? */
        list_del(&pctldev->node);
        /* Destroy descriptor tree */
index dfd021e8268f40e8f8900bdb5e69f79c389accd6..f4cd0b9b2438b3548fafa4746b6c6a6cf8874bb4 100644 (file)
@@ -177,7 +177,7 @@ struct at91_pinctrl {
        struct device           *dev;
        struct pinctrl_dev      *pctl;
 
-       int                     nbanks;
+       int                     nactive_banks;
 
        uint32_t                *mux_mask;
        int                     nmux;
@@ -653,12 +653,18 @@ static int pin_check_config(struct at91_pinctrl *info, const char *name,
        int mux;
 
        /* check if it's a valid config */
-       if (pin->bank >= info->nbanks) {
+       if (pin->bank >= gpio_banks) {
                dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
-                       name, index, pin->bank, info->nbanks);
+                       name, index, pin->bank, gpio_banks);
                return -EINVAL;
        }
 
+       if (!gpio_chips[pin->bank]) {
+               dev_err(info->dev, "%s: pin conf %d bank_id %d not enabled\n",
+                       name, index, pin->bank);
+               return -ENXIO;
+       }
+
        if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
                dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
                        name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
@@ -981,7 +987,8 @@ static void at91_pinctrl_child_count(struct at91_pinctrl *info,
 
        for_each_child_of_node(np, child) {
                if (of_device_is_compatible(child, gpio_compat)) {
-                       info->nbanks++;
+                       if (of_device_is_available(child))
+                               info->nactive_banks++;
                } else {
                        info->nfunctions++;
                        info->ngroups += of_get_child_count(child);
@@ -1003,11 +1010,11 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info,
        }
 
        size /= sizeof(*list);
-       if (!size || size % info->nbanks) {
-               dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
+       if (!size || size % gpio_banks) {
+               dev_err(info->dev, "wrong mux mask array should be by %d\n", gpio_banks);
                return -EINVAL;
        }
-       info->nmux = size / info->nbanks;
+       info->nmux = size / gpio_banks;
 
        info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
        if (!info->mux_mask) {
@@ -1131,7 +1138,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
                of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
        at91_pinctrl_child_count(info, np);
 
-       if (info->nbanks < 1) {
+       if (gpio_banks < 1) {
                dev_err(&pdev->dev, "you need to specify at least one gpio-controller\n");
                return -EINVAL;
        }
@@ -1144,7 +1151,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
 
        dev_dbg(&pdev->dev, "mux-mask\n");
        tmp = info->mux_mask;
-       for (i = 0; i < info->nbanks; i++) {
+       for (i = 0; i < gpio_banks; i++) {
                for (j = 0; j < info->nmux; j++, tmp++) {
                        dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
                }
@@ -1162,7 +1169,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
        if (!info->groups)
                return -ENOMEM;
 
-       dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
+       dev_dbg(&pdev->dev, "nbanks = %d\n", gpio_banks);
        dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
        dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
 
@@ -1185,7 +1192,7 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
 {
        struct at91_pinctrl *info;
        struct pinctrl_pin_desc *pdesc;
-       int ret, i, j, k;
+       int ret, i, j, k, ngpio_chips_enabled = 0;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
@@ -1200,23 +1207,27 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
         * to obtain references to the struct gpio_chip * for them, and we
         * need this to proceed.
         */
-       for (i = 0; i < info->nbanks; i++) {
-               if (!gpio_chips[i]) {
-                       dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
-                       devm_kfree(&pdev->dev, info);
-                       return -EPROBE_DEFER;
-               }
+       for (i = 0; i < gpio_banks; i++)
+               if (gpio_chips[i])
+                       ngpio_chips_enabled++;
+
+       if (ngpio_chips_enabled < info->nactive_banks) {
+               dev_warn(&pdev->dev,
+                        "All GPIO chips are not registered yet (%d/%d)\n",
+                        ngpio_chips_enabled, info->nactive_banks);
+               devm_kfree(&pdev->dev, info);
+               return -EPROBE_DEFER;
        }
 
        at91_pinctrl_desc.name = dev_name(&pdev->dev);
-       at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
+       at91_pinctrl_desc.npins = gpio_banks * MAX_NB_GPIO_PER_BANK;
        at91_pinctrl_desc.pins = pdesc =
                devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
 
        if (!at91_pinctrl_desc.pins)
                return -ENOMEM;
 
-       for (i = 0 , k = 0; i < info->nbanks; i++) {
+       for (i = 0, k = 0; i < gpio_banks; i++) {
                for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
                        pdesc->number = k;
                        pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
@@ -1234,8 +1245,9 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
        }
 
        /* We will handle a range of GPIO pins */
-       for (i = 0; i < info->nbanks; i++)
-               pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
+       for (i = 0; i < gpio_banks; i++)
+               if (gpio_chips[i])
+                       pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
 
        dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
 
@@ -1613,9 +1625,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
 static int at91_gpio_of_irq_setup(struct platform_device *pdev,
                                  struct at91_gpio_chip *at91_gpio)
 {
+       struct gpio_chip        *gpiochip_prev = NULL;
        struct at91_gpio_chip   *prev = NULL;
        struct irq_data         *d = irq_get_irq_data(at91_gpio->pioc_virq);
-       int ret;
+       int ret, i;
 
        at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
 
@@ -1641,24 +1654,33 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
                return ret;
        }
 
-       /* Setup chained handler */
-       if (at91_gpio->pioc_idx)
-               prev = gpio_chips[at91_gpio->pioc_idx - 1];
-
        /* The top level handler handles one bank of GPIOs, except
         * on some SoC it can handle up to three...
         * We only set up the handler for the first of the list.
         */
-       if (prev && prev->next == at91_gpio)
+       gpiochip_prev = irq_get_handler_data(at91_gpio->pioc_virq);
+       if (!gpiochip_prev) {
+               /* Then register the chain on the parent IRQ */
+               gpiochip_set_chained_irqchip(&at91_gpio->chip,
+                                            &gpio_irqchip,
+                                            at91_gpio->pioc_virq,
+                                            gpio_irq_handler);
                return 0;
+       }
 
-       /* Then register the chain on the parent IRQ */
-       gpiochip_set_chained_irqchip(&at91_gpio->chip,
-                                    &gpio_irqchip,
-                                    at91_gpio->pioc_virq,
-                                    gpio_irq_handler);
+       prev = container_of(gpiochip_prev, struct at91_gpio_chip, chip);
 
-       return 0;
+       /* we can only have 2 banks before */
+       for (i = 0; i < 2; i++) {
+               if (prev->next) {
+                       prev = prev->next;
+               } else {
+                       prev->next = at91_gpio;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
 }
 
 /* This structure is replicated for each GPIO block allocated at probe time */
@@ -1675,24 +1697,6 @@ static struct gpio_chip at91_gpio_template = {
        .ngpio                  = MAX_NB_GPIO_PER_BANK,
 };
 
-static void at91_gpio_probe_fixup(void)
-{
-       unsigned i;
-       struct at91_gpio_chip *at91_gpio, *last = NULL;
-
-       for (i = 0; i < gpio_banks; i++) {
-               at91_gpio = gpio_chips[i];
-
-               /*
-                * GPIO controller are grouped on some SoC:
-                * PIOC, PIOD and PIOE can share the same IRQ line
-                */
-               if (last && last->pioc_virq == at91_gpio->pioc_virq)
-                       last->next = at91_gpio;
-               last = at91_gpio;
-       }
-}
-
 static struct of_device_id at91_gpio_of_match[] = {
        { .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
        { .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
@@ -1805,8 +1809,6 @@ static int at91_gpio_probe(struct platform_device *pdev)
        gpio_chips[alias_idx] = at91_chip;
        gpio_banks = max(gpio_banks, alias_idx + 1);
 
-       at91_gpio_probe_fixup();
-
        ret = at91_gpio_of_irq_setup(pdev, at91_chip);
        if (ret)
                goto irq_setup_err;
index ba74f0aa60c76ac76d90d2edaff8c219d280e6a3..43eacc924b7eb96c0cb0b4fd02d2f91f3c9a2fde 100644 (file)
@@ -89,6 +89,7 @@ struct rockchip_iomux {
  * @reg_pull: optional separate register for additional pull settings
  * @clk: clock of the gpio bank
  * @irq: interrupt of the gpio bank
+ * @saved_enables: Saved content of GPIO_INTEN at suspend time.
  * @pin_base: first pin number
  * @nr_pins: number of pins in this bank
  * @name: name of the bank
@@ -107,6 +108,7 @@ struct rockchip_pin_bank {
        struct regmap                   *regmap_pull;
        struct clk                      *clk;
        int                             irq;
+       u32                             saved_enables;
        u32                             pin_base;
        u8                              nr_pins;
        char                            *name;
@@ -1396,10 +1398,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
        struct irq_chip *chip = irq_get_chip(irq);
        struct rockchip_pin_bank *bank = irq_get_handler_data(irq);
-       u32 polarity = 0, data = 0;
        u32 pend;
-       bool edge_changed = false;
-       unsigned long flags;
 
        dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name);
 
@@ -1407,12 +1406,6 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
 
        pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS);
 
-       if (bank->toggle_edge_mode) {
-               polarity = readl_relaxed(bank->reg_base +
-                                        GPIO_INT_POLARITY);
-               data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT);
-       }
-
        while (pend) {
                unsigned int virq;
 
@@ -1432,27 +1425,31 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
                 * needs manual intervention.
                 */
                if (bank->toggle_edge_mode & BIT(irq)) {
-                       if (data & BIT(irq))
-                               polarity &= ~BIT(irq);
-                       else
-                               polarity |= BIT(irq);
+                       u32 data, data_old, polarity;
+                       unsigned long flags;
 
-                       edge_changed = true;
-               }
+                       data = readl_relaxed(bank->reg_base + GPIO_EXT_PORT);
+                       do {
+                               spin_lock_irqsave(&bank->slock, flags);
 
-               generic_handle_irq(virq);
-       }
+                               polarity = readl_relaxed(bank->reg_base +
+                                                        GPIO_INT_POLARITY);
+                               if (data & BIT(irq))
+                                       polarity &= ~BIT(irq);
+                               else
+                                       polarity |= BIT(irq);
+                               writel(polarity,
+                                      bank->reg_base + GPIO_INT_POLARITY);
 
-       if (bank->toggle_edge_mode && edge_changed) {
-               /* Interrupt params should only be set with ints disabled */
-               spin_lock_irqsave(&bank->slock, flags);
+                               spin_unlock_irqrestore(&bank->slock, flags);
 
-               data = readl_relaxed(bank->reg_base + GPIO_INTEN);
-               writel_relaxed(0, bank->reg_base + GPIO_INTEN);
-               writel(polarity, bank->reg_base + GPIO_INT_POLARITY);
-               writel(data, bank->reg_base + GPIO_INTEN);
+                               data_old = data;
+                               data = readl_relaxed(bank->reg_base +
+                                                    GPIO_EXT_PORT);
+                       } while ((data & BIT(irq)) != (data_old & BIT(irq)));
+               }
 
-               spin_unlock_irqrestore(&bank->slock, flags);
+               generic_handle_irq(virq);
        }
 
        chained_irq_exit(chip, desc);
@@ -1543,6 +1540,51 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
        return 0;
 }
 
+static void rockchip_irq_suspend(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct rockchip_pin_bank *bank = gc->private;
+
+       bank->saved_enables = irq_reg_readl(gc, GPIO_INTEN);
+       irq_reg_writel(gc, gc->wake_active, GPIO_INTEN);
+}
+
+static void rockchip_irq_resume(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct rockchip_pin_bank *bank = gc->private;
+
+       irq_reg_writel(gc, bank->saved_enables, GPIO_INTEN);
+}
+
+static void rockchip_irq_disable(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       irq_gc_lock(gc);
+
+       val = irq_reg_readl(gc, GPIO_INTEN);
+       val &= ~d->mask;
+       irq_reg_writel(gc, val, GPIO_INTEN);
+
+       irq_gc_unlock(gc);
+}
+
+static void rockchip_irq_enable(struct irq_data *d)
+{
+       struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       u32 val;
+
+       irq_gc_lock(gc);
+
+       val = irq_reg_readl(gc, GPIO_INTEN);
+       val |= d->mask;
+       irq_reg_writel(gc, val, GPIO_INTEN);
+
+       irq_gc_unlock(gc);
+}
+
 static int rockchip_interrupts_register(struct platform_device *pdev,
                                                struct rockchip_pinctrl *info)
 {
@@ -1581,12 +1623,16 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
                gc = irq_get_domain_generic_chip(bank->domain, 0);
                gc->reg_base = bank->reg_base;
                gc->private = bank;
-               gc->chip_types[0].regs.mask = GPIO_INTEN;
+               gc->chip_types[0].regs.mask = GPIO_INTMASK;
                gc->chip_types[0].regs.ack = GPIO_PORTS_EOI;
                gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
-               gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
-               gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+               gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
+               gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
+               gc->chip_types[0].chip.irq_enable = rockchip_irq_enable;
+               gc->chip_types[0].chip.irq_disable = rockchip_irq_disable;
                gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
+               gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend;
+               gc->chip_types[0].chip.irq_resume = rockchip_irq_resume;
                gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type;
                gc->wake_enabled = IRQ_MSK(bank->nr_pins);
 
index 7c9d51382248d9c5b3069653d72f26e20751c214..9e5ec00084bb1dcc2aad395af7c37d2bf0e3044a 100644 (file)
@@ -1012,8 +1012,10 @@ static void st_pinconf_dbg_show(struct pinctrl_dev *pctldev,
                                   struct seq_file *s, unsigned pin_id)
 {
        unsigned long config;
-       st_pinconf_get(pctldev, pin_id, &config);
 
+       mutex_unlock(&pctldev->mutex);
+       st_pinconf_get(pctldev, pin_id, &config);
+       mutex_lock(&pctldev->mutex);
        seq_printf(s, "[OE:%ld,PU:%ld,OD:%ld]\n"
                "\t\t[retime:%ld,invclk:%ld,clknotdat:%ld,"
                "de:%ld,rt-clk:%ld,rt-delay:%ld]",
@@ -1443,6 +1445,7 @@ static struct gpio_chip st_gpio_template = {
 
 static struct irq_chip st_gpio_irqchip = {
        .name           = "GPIO",
+       .irq_disable    = st_gpio_irq_mask,
        .irq_mask       = st_gpio_irq_mask,
        .irq_unmask     = st_gpio_irq_unmask,
        .irq_set_type   = st_gpio_irq_set_type,
index c5cef59f59654cad158677f8dbc664051a222508..779950c62e53d238e7a4c35d7290ca66475fed86 100644 (file)
@@ -798,10 +798,8 @@ static int pinmux_xway_probe(struct platform_device *pdev)
 
        /* load the gpio chip */
        xway_chip.dev = &pdev->dev;
-       of_gpiochip_add(&xway_chip);
        ret = gpiochip_add(&xway_chip);
        if (ret) {
-               of_gpiochip_remove(&xway_chip);
                dev_err(&pdev->dev, "Failed to register gpio chip\n");
                return ret;
        }
index e730935fa4577deb2582ea493ab60aa2b0f176fe..ed7017df065d3f002bada2659f4be9baccf6c1f2 100644 (file)
@@ -865,10 +865,10 @@ static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action,
 
 static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl)
 {
-       int i = 0;
+       int i;
        const struct msm_function *func = pctrl->soc->functions;
 
-       for (; i <= pctrl->soc->nfunctions; i++)
+       for (i = 0; i < pctrl->soc->nfunctions; i++)
                if (!strcmp(func[i].name, "ps_hold")) {
                        pctrl->restart_nb.notifier_call = msm_ps_hold_restart;
                        pctrl->restart_nb.priority = 128;
index 9411eae39a4ec5fc32f993d1583a3c329e2365b1..3d21efe11d7b77c511ff651201ca9a14c467e058 100644 (file)
@@ -2,11 +2,9 @@
  *  Driver for Dell laptop extras
  *
  *  Copyright (c) Red Hat <mjg@redhat.com>
- *  Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com>
- *  Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com>
  *
- *  Based on documentation in the libsmbios package:
- *  Copyright (C) 2005-2014 Dell Inc.
+ *  Based on documentation in the libsmbios package, Copyright (C) 2005 Dell
+ *  Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include "../../firmware/dcdbas.h"
 
 #define BRIGHTNESS_TOKEN 0x7d
-#define KBD_LED_OFF_TOKEN 0x01E1
-#define KBD_LED_ON_TOKEN 0x01E2
-#define KBD_LED_AUTO_TOKEN 0x01E3
-#define KBD_LED_AUTO_25_TOKEN 0x02EA
-#define KBD_LED_AUTO_50_TOKEN 0x02EB
-#define KBD_LED_AUTO_75_TOKEN 0x02EC
-#define KBD_LED_AUTO_100_TOKEN 0x02F6
 
 /* This structure will be modified by the firmware when we enter
  * system management mode, hence the volatiles */
@@ -71,13 +62,6 @@ struct calling_interface_structure {
 
 struct quirk_entry {
        u8 touchpad_led;
-
-       int needs_kbd_timeouts;
-       /*
-        * Ordered list of timeouts expressed in seconds.
-        * The list must end with -1
-        */
-       int kbd_timeouts[];
 };
 
 static struct quirk_entry *quirks;
@@ -92,15 +76,6 @@ static int __init dmi_matched(const struct dmi_system_id *dmi)
        return 1;
 }
 
-/*
- * These values come from Windows utility provided by Dell. If any other value
- * is used then BIOS silently set timeout to 0 without any error message.
- */
-static struct quirk_entry quirk_dell_xps13_9333 = {
-       .needs_kbd_timeouts = 1,
-       .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 },
-};
-
 static int da_command_address;
 static int da_command_code;
 static int da_num_tokens;
@@ -292,15 +267,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
                },
                .driver_data = &quirk_dell_vostro_v130,
        },
-       {
-               .callback = dmi_matched,
-               .ident = "Dell XPS13 9333",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS13 9333"),
-               },
-               .driver_data = &quirk_dell_xps13_9333,
-       },
        { }
 };
 
@@ -365,29 +331,17 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
        }
 }
 
-static int find_token_id(int tokenid)
+static int find_token_location(int tokenid)
 {
        int i;
-
        for (i = 0; i < da_num_tokens; i++) {
                if (da_tokens[i].tokenID == tokenid)
-                       return i;
+                       return da_tokens[i].location;
        }
 
        return -1;
 }
 
-static int find_token_location(int tokenid)
-{
-       int id;
-
-       id = find_token_id(tokenid);
-       if (id == -1)
-               return -1;
-
-       return da_tokens[id].location;
-}
-
 static struct calling_interface_buffer *
 dell_send_request(struct calling_interface_buffer *buffer, int class,
                  int select)
@@ -408,20 +362,6 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
        return buffer;
 }
 
-static inline int dell_smi_error(int value)
-{
-       switch (value) {
-       case 0: /* Completed successfully */
-               return 0;
-       case -1: /* Completed with error */
-               return -EIO;
-       case -2: /* Function not supported */
-               return -ENXIO;
-       default: /* Unknown error */
-               return -EINVAL;
-       }
-}
-
 /* Derived from information in DellWirelessCtl.cpp:
    Class 17, select 11 is radio control. It returns an array of 32-bit values.
 
@@ -776,7 +716,7 @@ static int dell_send_intensity(struct backlight_device *bd)
        else
                dell_send_request(buffer, 1, 1);
 
- out:
+out:
        release_buffer();
        return ret;
 }
@@ -800,7 +740,7 @@ static int dell_get_intensity(struct backlight_device *bd)
 
        ret = buffer->output[1];
 
- out:
+out:
        release_buffer();
        return ret;
 }
@@ -849,984 +789,6 @@ static void touchpad_led_exit(void)
        led_classdev_unregister(&touchpad_led);
 }
 
-/*
- * Derived from information in smbios-keyboard-ctl:
- *
- * cbClass 4
- * cbSelect 11
- * Keyboard illumination
- * cbArg1 determines the function to be performed
- *
- * cbArg1 0x0 = Get Feature Information
- *  cbRES1         Standard return codes (0, -1, -2)
- *  cbRES2, word0  Bitmap of user-selectable modes
- *     bit 0     Always off (All systems)
- *     bit 1     Always on (Travis ATG, Siberia)
- *     bit 2     Auto: ALS-based On; ALS-based Off (Travis ATG)
- *     bit 3     Auto: ALS- and input-activity-based On; input-activity based Off
- *     bit 4     Auto: Input-activity-based On; input-activity based Off
- *     bit 5     Auto: Input-activity-based On (illumination level 25%); input-activity based Off
- *     bit 6     Auto: Input-activity-based On (illumination level 50%); input-activity based Off
- *     bit 7     Auto: Input-activity-based On (illumination level 75%); input-activity based Off
- *     bit 8     Auto: Input-activity-based On (illumination level 100%); input-activity based Off
- *     bits 9-15 Reserved for future use
- *  cbRES2, byte2  Reserved for future use
- *  cbRES2, byte3  Keyboard illumination type
- *     0         Reserved
- *     1         Tasklight
- *     2         Backlight
- *     3-255     Reserved for future use
- *  cbRES3, byte0  Supported auto keyboard illumination trigger bitmap.
- *     bit 0     Any keystroke
- *     bit 1     Touchpad activity
- *     bit 2     Pointing stick
- *     bit 3     Any mouse
- *     bits 4-7  Reserved for future use
- *  cbRES3, byte1  Supported timeout unit bitmap
- *     bit 0     Seconds
- *     bit 1     Minutes
- *     bit 2     Hours
- *     bit 3     Days
- *     bits 4-7  Reserved for future use
- *  cbRES3, byte2  Number of keyboard light brightness levels
- *  cbRES4, byte0  Maximum acceptable seconds value (0 if seconds not supported).
- *  cbRES4, byte1  Maximum acceptable minutes value (0 if minutes not supported).
- *  cbRES4, byte2  Maximum acceptable hours value (0 if hours not supported).
- *  cbRES4, byte3  Maximum acceptable days value (0 if days not supported)
- *
- * cbArg1 0x1 = Get Current State
- *  cbRES1         Standard return codes (0, -1, -2)
- *  cbRES2, word0  Bitmap of current mode state
- *     bit 0     Always off (All systems)
- *     bit 1     Always on (Travis ATG, Siberia)
- *     bit 2     Auto: ALS-based On; ALS-based Off (Travis ATG)
- *     bit 3     Auto: ALS- and input-activity-based On; input-activity based Off
- *     bit 4     Auto: Input-activity-based On; input-activity based Off
- *     bit 5     Auto: Input-activity-based On (illumination level 25%); input-activity based Off
- *     bit 6     Auto: Input-activity-based On (illumination level 50%); input-activity based Off
- *     bit 7     Auto: Input-activity-based On (illumination level 75%); input-activity based Off
- *     bit 8     Auto: Input-activity-based On (illumination level 100%); input-activity based Off
- *     bits 9-15 Reserved for future use
- *     Note: Only One bit can be set
- *  cbRES2, byte2  Currently active auto keyboard illumination triggers.
- *     bit 0     Any keystroke
- *     bit 1     Touchpad activity
- *     bit 2     Pointing stick
- *     bit 3     Any mouse
- *     bits 4-7  Reserved for future use
- *  cbRES2, byte3  Current Timeout
- *     bits 7:6  Timeout units indicator:
- *     00b       Seconds
- *     01b       Minutes
- *     10b       Hours
- *     11b       Days
- *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
- *     NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte
- *     are set upon return from the [Get feature information] call.
- *  cbRES3, byte0  Current setting of ALS value that turns the light on or off.
- *  cbRES3, byte1  Current ALS reading
- *  cbRES3, byte2  Current keyboard light level.
- *
- * cbArg1 0x2 = Set New State
- *  cbRES1         Standard return codes (0, -1, -2)
- *  cbArg2, word0  Bitmap of current mode state
- *     bit 0     Always off (All systems)
- *     bit 1     Always on (Travis ATG, Siberia)
- *     bit 2     Auto: ALS-based On; ALS-based Off (Travis ATG)
- *     bit 3     Auto: ALS- and input-activity-based On; input-activity based Off
- *     bit 4     Auto: Input-activity-based On; input-activity based Off
- *     bit 5     Auto: Input-activity-based On (illumination level 25%); input-activity based Off
- *     bit 6     Auto: Input-activity-based On (illumination level 50%); input-activity based Off
- *     bit 7     Auto: Input-activity-based On (illumination level 75%); input-activity based Off
- *     bit 8     Auto: Input-activity-based On (illumination level 100%); input-activity based Off
- *     bits 9-15 Reserved for future use
- *     Note: Only One bit can be set
- *  cbArg2, byte2  Desired auto keyboard illumination triggers. Must remain inactive to allow
- *                 keyboard to turn off automatically.
- *     bit 0     Any keystroke
- *     bit 1     Touchpad activity
- *     bit 2     Pointing stick
- *     bit 3     Any mouse
- *     bits 4-7  Reserved for future use
- *  cbArg2, byte3  Desired Timeout
- *     bits 7:6  Timeout units indicator:
- *     00b       Seconds
- *     01b       Minutes
- *     10b       Hours
- *     11b       Days
- *     bits 5:0  Timeout value (0-63) in sec/min/hr/day
- *  cbArg3, byte0  Desired setting of ALS value that turns the light on or off.
- *  cbArg3, byte2  Desired keyboard light level.
- */
-
-
-enum kbd_timeout_unit {
-       KBD_TIMEOUT_SECONDS = 0,
-       KBD_TIMEOUT_MINUTES,
-       KBD_TIMEOUT_HOURS,
-       KBD_TIMEOUT_DAYS,
-};
-
-enum kbd_mode_bit {
-       KBD_MODE_BIT_OFF = 0,
-       KBD_MODE_BIT_ON,
-       KBD_MODE_BIT_ALS,
-       KBD_MODE_BIT_TRIGGER_ALS,
-       KBD_MODE_BIT_TRIGGER,
-       KBD_MODE_BIT_TRIGGER_25,
-       KBD_MODE_BIT_TRIGGER_50,
-       KBD_MODE_BIT_TRIGGER_75,
-       KBD_MODE_BIT_TRIGGER_100,
-};
-
-#define kbd_is_als_mode_bit(bit) \
-       ((bit) == KBD_MODE_BIT_ALS || (bit) == KBD_MODE_BIT_TRIGGER_ALS)
-#define kbd_is_trigger_mode_bit(bit) \
-       ((bit) >= KBD_MODE_BIT_TRIGGER_ALS && (bit) <= KBD_MODE_BIT_TRIGGER_100)
-#define kbd_is_level_mode_bit(bit) \
-       ((bit) >= KBD_MODE_BIT_TRIGGER_25 && (bit) <= KBD_MODE_BIT_TRIGGER_100)
-
-struct kbd_info {
-       u16 modes;
-       u8 type;
-       u8 triggers;
-       u8 levels;
-       u8 seconds;
-       u8 minutes;
-       u8 hours;
-       u8 days;
-};
-
-struct kbd_state {
-       u8 mode_bit;
-       u8 triggers;
-       u8 timeout_value;
-       u8 timeout_unit;
-       u8 als_setting;
-       u8 als_value;
-       u8 level;
-};
-
-static const int kbd_tokens[] = {
-       KBD_LED_OFF_TOKEN,
-       KBD_LED_AUTO_25_TOKEN,
-       KBD_LED_AUTO_50_TOKEN,
-       KBD_LED_AUTO_75_TOKEN,
-       KBD_LED_AUTO_100_TOKEN,
-       KBD_LED_ON_TOKEN,
-};
-
-static u16 kbd_token_bits;
-
-static struct kbd_info kbd_info;
-static bool kbd_als_supported;
-static bool kbd_triggers_supported;
-
-static u8 kbd_mode_levels[16];
-static int kbd_mode_levels_count;
-
-static u8 kbd_previous_level;
-static u8 kbd_previous_mode_bit;
-
-static bool kbd_led_present;
-
-/*
- * NOTE: there are three ways to set the keyboard backlight level.
- * First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value).
- * Second, via kbd_state.level (assigning numerical value <= kbd_info.levels).
- * Third, via SMBIOS tokens (KBD_LED_* in kbd_tokens)
- *
- * There are laptops which support only one of these methods. If we want to
- * support as many machines as possible we need to implement all three methods.
- * The first two methods use the kbd_state structure. The third uses SMBIOS
- * tokens. If kbd_info.levels == 0, the machine does not support setting the
- * keyboard backlight level via kbd_state.level.
- */
-
-static int kbd_get_info(struct kbd_info *info)
-{
-       u8 units;
-       int ret;
-
-       get_buffer();
-
-       buffer->input[0] = 0x0;
-       dell_send_request(buffer, 4, 11);
-       ret = buffer->output[0];
-
-       if (ret) {
-               ret = dell_smi_error(ret);
-               goto out;
-       }
-
-       info->modes = buffer->output[1] & 0xFFFF;
-       info->type = (buffer->output[1] >> 24) & 0xFF;
-       info->triggers = buffer->output[2] & 0xFF;
-       units = (buffer->output[2] >> 8) & 0xFF;
-       info->levels = (buffer->output[2] >> 16) & 0xFF;
-
-       if (units & BIT(0))
-               info->seconds = (buffer->output[3] >> 0) & 0xFF;
-       if (units & BIT(1))
-               info->minutes = (buffer->output[3] >> 8) & 0xFF;
-       if (units & BIT(2))
-               info->hours = (buffer->output[3] >> 16) & 0xFF;
-       if (units & BIT(3))
-               info->days = (buffer->output[3] >> 24) & 0xFF;
-
- out:
-       release_buffer();
-       return ret;
-}
-
-static unsigned int kbd_get_max_level(void)
-{
-       if (kbd_info.levels != 0)
-               return kbd_info.levels;
-       if (kbd_mode_levels_count > 0)
-               return kbd_mode_levels_count - 1;
-       return 0;
-}
-
-static int kbd_get_level(struct kbd_state *state)
-{
-       int i;
-
-       if (kbd_info.levels != 0)
-               return state->level;
-
-       if (kbd_mode_levels_count > 0) {
-               for (i = 0; i < kbd_mode_levels_count; ++i)
-                       if (kbd_mode_levels[i] == state->mode_bit)
-                               return i;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int kbd_set_level(struct kbd_state *state, u8 level)
-{
-       if (kbd_info.levels != 0) {
-               if (level != 0)
-                       kbd_previous_level = level;
-               if (state->level == level)
-                       return 0;
-               state->level = level;
-               if (level != 0 && state->mode_bit == KBD_MODE_BIT_OFF)
-                       state->mode_bit = kbd_previous_mode_bit;
-               else if (level == 0 && state->mode_bit != KBD_MODE_BIT_OFF) {
-                       kbd_previous_mode_bit = state->mode_bit;
-                       state->mode_bit = KBD_MODE_BIT_OFF;
-               }
-               return 0;
-       }
-
-       if (kbd_mode_levels_count > 0 && level < kbd_mode_levels_count) {
-               if (level != 0)
-                       kbd_previous_level = level;
-               state->mode_bit = kbd_mode_levels[level];
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int kbd_get_state(struct kbd_state *state)
-{
-       int ret;
-
-       get_buffer();
-
-       buffer->input[0] = 0x1;
-       dell_send_request(buffer, 4, 11);
-       ret = buffer->output[0];
-
-       if (ret) {
-               ret = dell_smi_error(ret);
-               goto out;
-       }
-
-       state->mode_bit = ffs(buffer->output[1] & 0xFFFF);
-       if (state->mode_bit != 0)
-               state->mode_bit--;
-
-       state->triggers = (buffer->output[1] >> 16) & 0xFF;
-       state->timeout_value = (buffer->output[1] >> 24) & 0x3F;
-       state->timeout_unit = (buffer->output[1] >> 30) & 0x3;
-       state->als_setting = buffer->output[2] & 0xFF;
-       state->als_value = (buffer->output[2] >> 8) & 0xFF;
-       state->level = (buffer->output[2] >> 16) & 0xFF;
-
- out:
-       release_buffer();
-       return ret;
-}
-
-static int kbd_set_state(struct kbd_state *state)
-{
-       int ret;
-
-       get_buffer();
-       buffer->input[0] = 0x2;
-       buffer->input[1] = BIT(state->mode_bit) & 0xFFFF;
-       buffer->input[1] |= (state->triggers & 0xFF) << 16;
-       buffer->input[1] |= (state->timeout_value & 0x3F) << 24;
-       buffer->input[1] |= (state->timeout_unit & 0x3) << 30;
-       buffer->input[2] = state->als_setting & 0xFF;
-       buffer->input[2] |= (state->level & 0xFF) << 16;
-       dell_send_request(buffer, 4, 11);
-       ret = buffer->output[0];
-       release_buffer();
-
-       return dell_smi_error(ret);
-}
-
-static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
-{
-       int ret;
-
-       ret = kbd_set_state(state);
-       if (ret == 0)
-               return 0;
-
-       /*
-        * When setting the new state fails,try to restore the previous one.
-        * This is needed on some machines where BIOS sets a default state when
-        * setting a new state fails. This default state could be all off.
-        */
-
-       if (kbd_set_state(old))
-               pr_err("Setting old previous keyboard state failed\n");
-
-       return ret;
-}
-
-static int kbd_set_token_bit(u8 bit)
-{
-       int id;
-       int ret;
-
-       if (bit >= ARRAY_SIZE(kbd_tokens))
-               return -EINVAL;
-
-       id = find_token_id(kbd_tokens[bit]);
-       if (id == -1)
-               return -EINVAL;
-
-       get_buffer();
-       buffer->input[0] = da_tokens[id].location;
-       buffer->input[1] = da_tokens[id].value;
-       dell_send_request(buffer, 1, 0);
-       ret = buffer->output[0];
-       release_buffer();
-
-       return dell_smi_error(ret);
-}
-
-static int kbd_get_token_bit(u8 bit)
-{
-       int id;
-       int ret;
-       int val;
-
-       if (bit >= ARRAY_SIZE(kbd_tokens))
-               return -EINVAL;
-
-       id = find_token_id(kbd_tokens[bit]);
-       if (id == -1)
-               return -EINVAL;
-
-       get_buffer();
-       buffer->input[0] = da_tokens[id].location;
-       dell_send_request(buffer, 0, 0);
-       ret = buffer->output[0];
-       val = buffer->output[1];
-       release_buffer();
-
-       if (ret)
-               return dell_smi_error(ret);
-
-       return (val == da_tokens[id].value);
-}
-
-static int kbd_get_first_active_token_bit(void)
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) {
-               ret = kbd_get_token_bit(i);
-               if (ret == 1)
-                       return i;
-       }
-
-       return ret;
-}
-
-static int kbd_get_valid_token_counts(void)
-{
-       return hweight16(kbd_token_bits);
-}
-
-static inline int kbd_init_info(void)
-{
-       struct kbd_state state;
-       int ret;
-       int i;
-
-       ret = kbd_get_info(&kbd_info);
-       if (ret)
-               return ret;
-
-       kbd_get_state(&state);
-
-       /* NOTE: timeout value is stored in 6 bits so max value is 63 */
-       if (kbd_info.seconds > 63)
-               kbd_info.seconds = 63;
-       if (kbd_info.minutes > 63)
-               kbd_info.minutes = 63;
-       if (kbd_info.hours > 63)
-               kbd_info.hours = 63;
-       if (kbd_info.days > 63)
-               kbd_info.days = 63;
-
-       /* NOTE: On tested machines ON mode did not work and caused
-        *       problems (turned backlight off) so do not use it
-        */
-       kbd_info.modes &= ~BIT(KBD_MODE_BIT_ON);
-
-       kbd_previous_level = kbd_get_level(&state);
-       kbd_previous_mode_bit = state.mode_bit;
-
-       if (kbd_previous_level == 0 && kbd_get_max_level() != 0)
-               kbd_previous_level = 1;
-
-       if (kbd_previous_mode_bit == KBD_MODE_BIT_OFF) {
-               kbd_previous_mode_bit =
-                       ffs(kbd_info.modes & ~BIT(KBD_MODE_BIT_OFF));
-               if (kbd_previous_mode_bit != 0)
-                       kbd_previous_mode_bit--;
-       }
-
-       if (kbd_info.modes & (BIT(KBD_MODE_BIT_ALS) |
-                             BIT(KBD_MODE_BIT_TRIGGER_ALS)))
-               kbd_als_supported = true;
-
-       if (kbd_info.modes & (
-           BIT(KBD_MODE_BIT_TRIGGER_ALS) | BIT(KBD_MODE_BIT_TRIGGER) |
-           BIT(KBD_MODE_BIT_TRIGGER_25) | BIT(KBD_MODE_BIT_TRIGGER_50) |
-           BIT(KBD_MODE_BIT_TRIGGER_75) | BIT(KBD_MODE_BIT_TRIGGER_100)
-          ))
-               kbd_triggers_supported = true;
-
-       /* kbd_mode_levels[0] is reserved, see below */
-       for (i = 0; i < 16; ++i)
-               if (kbd_is_level_mode_bit(i) && (BIT(i) & kbd_info.modes))
-                       kbd_mode_levels[1 + kbd_mode_levels_count++] = i;
-
-       /*
-        * Find the first supported mode and assign to kbd_mode_levels[0].
-        * This should be 0 (off), but we cannot depend on the BIOS to
-        * support 0.
-        */
-       if (kbd_mode_levels_count > 0) {
-               for (i = 0; i < 16; ++i) {
-                       if (BIT(i) & kbd_info.modes) {
-                               kbd_mode_levels[0] = i;
-                               break;
-                       }
-               }
-               kbd_mode_levels_count++;
-       }
-
-       return 0;
-
-}
-
-static inline void kbd_init_tokens(void)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i)
-               if (find_token_id(kbd_tokens[i]) != -1)
-                       kbd_token_bits |= BIT(i);
-}
-
-static void kbd_init(void)
-{
-       int ret;
-
-       ret = kbd_init_info();
-       kbd_init_tokens();
-
-       if (kbd_token_bits != 0 || ret == 0)
-               kbd_led_present = true;
-}
-
-static ssize_t kbd_led_timeout_store(struct device *dev,
-                                    struct device_attribute *attr,
-                                    const char *buf, size_t count)
-{
-       struct kbd_state new_state;
-       struct kbd_state state;
-       bool convert;
-       int value;
-       int ret;
-       char ch;
-       u8 unit;
-       int i;
-
-       ret = sscanf(buf, "%d %c", &value, &ch);
-       if (ret < 1)
-               return -EINVAL;
-       else if (ret == 1)
-               ch = 's';
-
-       if (value < 0)
-               return -EINVAL;
-
-       convert = false;
-
-       switch (ch) {
-       case 's':
-               if (value > kbd_info.seconds)
-                       convert = true;
-               unit = KBD_TIMEOUT_SECONDS;
-               break;
-       case 'm':
-               if (value > kbd_info.minutes)
-                       convert = true;
-               unit = KBD_TIMEOUT_MINUTES;
-               break;
-       case 'h':
-               if (value > kbd_info.hours)
-                       convert = true;
-               unit = KBD_TIMEOUT_HOURS;
-               break;
-       case 'd':
-               if (value > kbd_info.days)
-                       convert = true;
-               unit = KBD_TIMEOUT_DAYS;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       if (quirks && quirks->needs_kbd_timeouts)
-               convert = true;
-
-       if (convert) {
-               /* Convert value from current units to seconds */
-               switch (unit) {
-               case KBD_TIMEOUT_DAYS:
-                       value *= 24;
-               case KBD_TIMEOUT_HOURS:
-                       value *= 60;
-               case KBD_TIMEOUT_MINUTES:
-                       value *= 60;
-                       unit = KBD_TIMEOUT_SECONDS;
-               }
-
-               if (quirks && quirks->needs_kbd_timeouts) {
-                       for (i = 0; quirks->kbd_timeouts[i] != -1; i++) {
-                               if (value <= quirks->kbd_timeouts[i]) {
-                                       value = quirks->kbd_timeouts[i];
-                                       break;
-                               }
-                       }
-               }
-
-               if (value <= kbd_info.seconds && kbd_info.seconds) {
-                       unit = KBD_TIMEOUT_SECONDS;
-               } else if (value / 60 <= kbd_info.minutes && kbd_info.minutes) {
-                       value /= 60;
-                       unit = KBD_TIMEOUT_MINUTES;
-               } else if (value / (60 * 60) <= kbd_info.hours && kbd_info.hours) {
-                       value /= (60 * 60);
-                       unit = KBD_TIMEOUT_HOURS;
-               } else if (value / (60 * 60 * 24) <= kbd_info.days && kbd_info.days) {
-                       value /= (60 * 60 * 24);
-                       unit = KBD_TIMEOUT_DAYS;
-               } else {
-                       return -EINVAL;
-               }
-       }
-
-       ret = kbd_get_state(&state);
-       if (ret)
-               return ret;
-
-       new_state = state;
-       new_state.timeout_value = value;
-       new_state.timeout_unit = unit;
-
-       ret = kbd_set_state_safe(&new_state, &state);
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static ssize_t kbd_led_timeout_show(struct device *dev,
-                                   struct device_attribute *attr, char *buf)
-{
-       struct kbd_state state;
-       int ret;
-       int len;
-
-       ret = kbd_get_state(&state);
-       if (ret)
-               return ret;
-
-       len = sprintf(buf, "%d", state.timeout_value);
-
-       switch (state.timeout_unit) {
-       case KBD_TIMEOUT_SECONDS:
-               return len + sprintf(buf+len, "s\n");
-       case KBD_TIMEOUT_MINUTES:
-               return len + sprintf(buf+len, "m\n");
-       case KBD_TIMEOUT_HOURS:
-               return len + sprintf(buf+len, "h\n");
-       case KBD_TIMEOUT_DAYS:
-               return len + sprintf(buf+len, "d\n");
-       default:
-               return -EINVAL;
-       }
-
-       return len;
-}
-
-static DEVICE_ATTR(stop_timeout, S_IRUGO | S_IWUSR,
-                  kbd_led_timeout_show, kbd_led_timeout_store);
-
-static const char * const kbd_led_triggers[] = {
-       "keyboard",
-       "touchpad",
-       /*"trackstick"*/ NULL, /* NOTE: trackstick is just alias for touchpad */
-       "mouse",
-};
-
-static ssize_t kbd_led_triggers_store(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t count)
-{
-       struct kbd_state new_state;
-       struct kbd_state state;
-       bool triggers_enabled = false;
-       bool als_enabled = false;
-       bool disable_als = false;
-       bool enable_als = false;
-       int trigger_bit = -1;
-       char trigger[21];
-       int i, ret;
-
-       ret = sscanf(buf, "%20s", trigger);
-       if (ret != 1)
-               return -EINVAL;
-
-       if (trigger[0] != '+' && trigger[0] != '-')
-               return -EINVAL;
-
-       ret = kbd_get_state(&state);
-       if (ret)
-               return ret;
-
-       if (kbd_als_supported)
-               als_enabled = kbd_is_als_mode_bit(state.mode_bit);
-
-       if (kbd_triggers_supported)
-               triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit);
-
-       if (kbd_als_supported) {
-               if (strcmp(trigger, "+als") == 0) {
-                       if (als_enabled)
-                               return count;
-                       enable_als = true;
-               } else if (strcmp(trigger, "-als") == 0) {
-                       if (!als_enabled)
-                               return count;
-                       disable_als = true;
-               }
-       }
-
-       if (enable_als || disable_als) {
-               new_state = state;
-               if (enable_als) {
-                       if (triggers_enabled)
-                               new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS;
-                       else
-                               new_state.mode_bit = KBD_MODE_BIT_ALS;
-               } else {
-                       if (triggers_enabled) {
-                               new_state.mode_bit = KBD_MODE_BIT_TRIGGER;
-                               kbd_set_level(&new_state, kbd_previous_level);
-                       } else {
-                               new_state.mode_bit = KBD_MODE_BIT_ON;
-                       }
-               }
-               if (!(kbd_info.modes & BIT(new_state.mode_bit)))
-                       return -EINVAL;
-               ret = kbd_set_state_safe(&new_state, &state);
-               if (ret)
-                       return ret;
-               kbd_previous_mode_bit = new_state.mode_bit;
-               return count;
-       }
-
-       if (kbd_triggers_supported) {
-               for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) {
-                       if (!(kbd_info.triggers & BIT(i)))
-                               continue;
-                       if (!kbd_led_triggers[i])
-                               continue;
-                       if (strcmp(trigger+1, kbd_led_triggers[i]) != 0)
-                               continue;
-                       if (trigger[0] == '+' &&
-                           triggers_enabled && (state.triggers & BIT(i)))
-                               return count;
-                       if (trigger[0] == '-' &&
-                           (!triggers_enabled || !(state.triggers & BIT(i))))
-                               return count;
-                       trigger_bit = i;
-                       break;
-               }
-       }
-
-       if (trigger_bit != -1) {
-               new_state = state;
-               if (trigger[0] == '+')
-                       new_state.triggers |= BIT(trigger_bit);
-               else {
-                       new_state.triggers &= ~BIT(trigger_bit);
-                       /* NOTE: trackstick bit (2) must be disabled when
-                        *       disabling touchpad bit (1), otherwise touchpad
-                        *       bit (1) will not be disabled */
-                       if (trigger_bit == 1)
-                               new_state.triggers &= ~BIT(2);
-               }
-               if ((kbd_info.triggers & new_state.triggers) !=
-                   new_state.triggers)
-                       return -EINVAL;
-               if (new_state.triggers && !triggers_enabled) {
-                       if (als_enabled)
-                               new_state.mode_bit = KBD_MODE_BIT_TRIGGER_ALS;
-                       else {
-                               new_state.mode_bit = KBD_MODE_BIT_TRIGGER;
-                               kbd_set_level(&new_state, kbd_previous_level);
-                       }
-               } else if (new_state.triggers == 0) {
-                       if (als_enabled)
-                               new_state.mode_bit = KBD_MODE_BIT_ALS;
-                       else
-                               kbd_set_level(&new_state, 0);
-               }
-               if (!(kbd_info.modes & BIT(new_state.mode_bit)))
-                       return -EINVAL;
-               ret = kbd_set_state_safe(&new_state, &state);
-               if (ret)
-                       return ret;
-               if (new_state.mode_bit != KBD_MODE_BIT_OFF)
-                       kbd_previous_mode_bit = new_state.mode_bit;
-               return count;
-       }
-
-       return -EINVAL;
-}
-
-static ssize_t kbd_led_triggers_show(struct device *dev,
-                                    struct device_attribute *attr, char *buf)
-{
-       struct kbd_state state;
-       bool triggers_enabled;
-       int level, i, ret;
-       int len = 0;
-
-       ret = kbd_get_state(&state);
-       if (ret)
-               return ret;
-
-       len = 0;
-
-       if (kbd_triggers_supported) {
-               triggers_enabled = kbd_is_trigger_mode_bit(state.mode_bit);
-               level = kbd_get_level(&state);
-               for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); ++i) {
-                       if (!(kbd_info.triggers & BIT(i)))
-                               continue;
-                       if (!kbd_led_triggers[i])
-                               continue;
-                       if ((triggers_enabled || level <= 0) &&
-                           (state.triggers & BIT(i)))
-                               buf[len++] = '+';
-                       else
-                               buf[len++] = '-';
-                       len += sprintf(buf+len, "%s ", kbd_led_triggers[i]);
-               }
-       }
-
-       if (kbd_als_supported) {
-               if (kbd_is_als_mode_bit(state.mode_bit))
-                       len += sprintf(buf+len, "+als ");
-               else
-                       len += sprintf(buf+len, "-als ");
-       }
-
-       if (len)
-               buf[len - 1] = '\n';
-
-       return len;
-}
-
-static DEVICE_ATTR(start_triggers, S_IRUGO | S_IWUSR,
-                  kbd_led_triggers_show, kbd_led_triggers_store);
-
-static ssize_t kbd_led_als_store(struct device *dev,
-                                struct device_attribute *attr,
-                                const char *buf, size_t count)
-{
-       struct kbd_state state;
-       struct kbd_state new_state;
-       u8 setting;
-       int ret;
-
-       ret = kstrtou8(buf, 10, &setting);
-       if (ret)
-               return ret;
-
-       ret = kbd_get_state(&state);
-       if (ret)
-               return ret;
-
-       new_state = state;
-       new_state.als_setting = setting;
-
-       ret = kbd_set_state_safe(&new_state, &state);
-       if (ret)
-               return ret;
-
-       return count;
-}
-
-static ssize_t kbd_led_als_show(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       struct kbd_state state;
-       int ret;
-
-       ret = kbd_get_state(&state);
-       if (ret)
-               return ret;
-
-       return sprintf(buf, "%d\n", state.als_setting);
-}
-
-static DEVICE_ATTR(als_setting, S_IRUGO | S_IWUSR,
-                  kbd_led_als_show, kbd_led_als_store);
-
-static struct attribute *kbd_led_attrs[] = {
-       &dev_attr_stop_timeout.attr,
-       &dev_attr_start_triggers.attr,
-       &dev_attr_als_setting.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(kbd_led);
-
-static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev)
-{
-       int ret;
-       u16 num;
-       struct kbd_state state;
-
-       if (kbd_get_max_level()) {
-               ret = kbd_get_state(&state);
-               if (ret)
-                       return 0;
-               ret = kbd_get_level(&state);
-               if (ret < 0)
-                       return 0;
-               return ret;
-       }
-
-       if (kbd_get_valid_token_counts()) {
-               ret = kbd_get_first_active_token_bit();
-               if (ret < 0)
-                       return 0;
-               for (num = kbd_token_bits; num != 0 && ret > 0; --ret)
-                       num &= num - 1; /* clear the first bit set */
-               if (num == 0)
-                       return 0;
-               return ffs(num) - 1;
-       }
-
-       pr_warn("Keyboard brightness level control not supported\n");
-       return 0;
-}
-
-static void kbd_led_level_set(struct led_classdev *led_cdev,
-                             enum led_brightness value)
-{
-       struct kbd_state state;
-       struct kbd_state new_state;
-       u16 num;
-
-       if (kbd_get_max_level()) {
-               if (kbd_get_state(&state))
-                       return;
-               new_state = state;
-               if (kbd_set_level(&new_state, value))
-                       return;
-               kbd_set_state_safe(&new_state, &state);
-               return;
-       }
-
-       if (kbd_get_valid_token_counts()) {
-               for (num = kbd_token_bits; num != 0 && value > 0; --value)
-                       num &= num - 1; /* clear the first bit set */
-               if (num == 0)
-                       return;
-               kbd_set_token_bit(ffs(num) - 1);
-               return;
-       }
-
-       pr_warn("Keyboard brightness level control not supported\n");
-}
-
-static struct led_classdev kbd_led = {
-       .name           = "dell::kbd_backlight",
-       .brightness_set = kbd_led_level_set,
-       .brightness_get = kbd_led_level_get,
-       .groups         = kbd_led_groups,
-};
-
-static int __init kbd_led_init(struct device *dev)
-{
-       kbd_init();
-       if (!kbd_led_present)
-               return -ENODEV;
-       kbd_led.max_brightness = kbd_get_max_level();
-       if (!kbd_led.max_brightness) {
-               kbd_led.max_brightness = kbd_get_valid_token_counts();
-               if (kbd_led.max_brightness)
-                       kbd_led.max_brightness--;
-       }
-       return led_classdev_register(dev, &kbd_led);
-}
-
-static void brightness_set_exit(struct led_classdev *led_cdev,
-                               enum led_brightness value)
-{
-       /* Don't change backlight level on exit */
-};
-
-static void kbd_led_exit(void)
-{
-       if (!kbd_led_present)
-               return;
-       kbd_led.brightness_set = brightness_set_exit;
-       led_classdev_unregister(&kbd_led);
-}
-
 static int __init dell_init(void)
 {
        int max_intensity = 0;
@@ -1879,8 +841,6 @@ static int __init dell_init(void)
        if (quirks && quirks->touchpad_led)
                touchpad_led_init(&platform_device->dev);
 
-       kbd_led_init(&platform_device->dev);
-
        dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
        if (dell_laptop_dir != NULL)
                debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
@@ -1948,7 +908,6 @@ static void __exit dell_exit(void)
        debugfs_remove_recursive(dell_laptop_dir);
        if (quirks && quirks->touchpad_led)
                touchpad_led_exit();
-       kbd_led_exit();
        i8042_remove_filter(dell_laptop_i8042_filter);
        cancel_delayed_work_sync(&dell_rfkill_work);
        backlight_device_unregister(dell_backlight_device);
@@ -1965,7 +924,5 @@ module_init(dell_init);
 module_exit(dell_exit);
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
-MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
 MODULE_DESCRIPTION("Dell laptop driver");
 MODULE_LICENSE("GPL");
index c71443c4f265780b1fe7fa001e0a3fd6101a4886..97b5e4ee1ca40ae4bc5b50ab7e413833de693af7 100644 (file)
@@ -1041,6 +1041,7 @@ static const struct x86_cpu_id rapl_ids[] = {
        RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
        RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
        RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
+       RAPL_CPU(0x56, rapl_defaults_core),/* Future Xeon */
        RAPL_CPU(0x5A, rapl_defaults_atom),/* Annidale */
        {}
 };
index e225711bb8bc0009114d6ec0d95ab8d2bb2d68f3..9c48fb32f6601bf4065db65cd2a099bc57f3812d 100644 (file)
@@ -1488,7 +1488,7 @@ struct regulator *regulator_get_optional(struct device *dev, const char *id)
 }
 EXPORT_SYMBOL_GPL(regulator_get_optional);
 
-/* Locks held by regulator_put() */
+/* regulator_list_mutex lock held by regulator_put() */
 static void _regulator_put(struct regulator *regulator)
 {
        struct regulator_dev *rdev;
@@ -1503,12 +1503,14 @@ static void _regulator_put(struct regulator *regulator)
        /* remove any sysfs entries */
        if (regulator->dev)
                sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name);
+       mutex_lock(&rdev->mutex);
        kfree(regulator->supply_name);
        list_del(&regulator->list);
        kfree(regulator);
 
        rdev->open_count--;
        rdev->exclusive = 0;
+       mutex_unlock(&rdev->mutex);
 
        module_put(rdev->owner);
 }
index c1444c3d84c2823a8b4eaed28e9bf5036290ce26..ff828117798fd3f4775cd5cc6c8e86d8fbe33a00 100644 (file)
@@ -405,6 +405,40 @@ static struct regulator_ops s2mps14_reg_ops;
        .enable_mask    = S2MPS14_ENABLE_MASK                   \
 }
 
+#define regulator_desc_s2mps13_buck7(num, min, step, min_sel) {        \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPS13_BUCK##num,                    \
+       .ops            = &s2mps14_reg_ops,                     \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = min,                                  \
+       .uV_step        = step,                                 \
+       .linear_min_sel = min_sel,                              \
+       .n_voltages     = S2MPS14_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS13_BUCK_RAMP_DELAY,              \
+       .vsel_reg       = S2MPS13_REG_B1OUT + (num) * 2 - 1,    \
+       .vsel_mask      = S2MPS14_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS13_REG_B1CTRL + (num - 1) * 2,   \
+       .enable_mask    = S2MPS14_ENABLE_MASK                   \
+}
+
+#define regulator_desc_s2mps13_buck8_10(num, min, step, min_sel) {     \
+       .name           = "BUCK"#num,                           \
+       .id             = S2MPS13_BUCK##num,                    \
+       .ops            = &s2mps14_reg_ops,                     \
+       .type           = REGULATOR_VOLTAGE,                    \
+       .owner          = THIS_MODULE,                          \
+       .min_uV         = min,                                  \
+       .uV_step        = step,                                 \
+       .linear_min_sel = min_sel,                              \
+       .n_voltages     = S2MPS14_BUCK_N_VOLTAGES,              \
+       .ramp_delay     = S2MPS13_BUCK_RAMP_DELAY,              \
+       .vsel_reg       = S2MPS13_REG_B1OUT + (num) * 2 - 1,    \
+       .vsel_mask      = S2MPS14_BUCK_VSEL_MASK,               \
+       .enable_reg     = S2MPS13_REG_B1CTRL + (num) * 2 - 1,   \
+       .enable_mask    = S2MPS14_ENABLE_MASK                   \
+}
+
 static const struct regulator_desc s2mps13_regulators[] = {
        regulator_desc_s2mps13_ldo(1,  MIN_800_MV,  STEP_12_5_MV, 0x00),
        regulator_desc_s2mps13_ldo(2,  MIN_1400_MV, STEP_50_MV,   0x0C),
@@ -452,10 +486,10 @@ static const struct regulator_desc s2mps13_regulators[] = {
        regulator_desc_s2mps13_buck(4,  MIN_500_MV,  STEP_6_25_MV, 0x10),
        regulator_desc_s2mps13_buck(5,  MIN_500_MV,  STEP_6_25_MV, 0x10),
        regulator_desc_s2mps13_buck(6,  MIN_500_MV,  STEP_6_25_MV, 0x10),
-       regulator_desc_s2mps13_buck(7,  MIN_500_MV,  STEP_6_25_MV, 0x10),
-       regulator_desc_s2mps13_buck(8,  MIN_1000_MV, STEP_12_5_MV, 0x20),
-       regulator_desc_s2mps13_buck(9,  MIN_1000_MV, STEP_12_5_MV, 0x20),
-       regulator_desc_s2mps13_buck(10, MIN_500_MV,  STEP_6_25_MV, 0x10),
+       regulator_desc_s2mps13_buck7(7,  MIN_500_MV,  STEP_6_25_MV, 0x10),
+       regulator_desc_s2mps13_buck8_10(8,  MIN_1000_MV, STEP_12_5_MV, 0x20),
+       regulator_desc_s2mps13_buck8_10(9,  MIN_1000_MV, STEP_12_5_MV, 0x20),
+       regulator_desc_s2mps13_buck8_10(10, MIN_500_MV,  STEP_6_25_MV, 0x10),
 };
 
 static int s2mps14_regulator_enable(struct regulator_dev *rdev)
@@ -570,7 +604,7 @@ static struct regulator_ops s2mps14_reg_ops = {
        .enable_mask    = S2MPS14_ENABLE_MASK           \
 }
 
-#define regulator_desc_s2mps14_buck(num, min, step) {          \
+#define regulator_desc_s2mps14_buck(num, min, step, min_sel) { \
        .name           = "BUCK"#num,                           \
        .id             = S2MPS14_BUCK##num,                    \
        .ops            = &s2mps14_reg_ops,                     \
@@ -579,7 +613,7 @@ static struct regulator_ops s2mps14_reg_ops = {
        .min_uV         = min,                                  \
        .uV_step        = step,                                 \
        .n_voltages     = S2MPS14_BUCK_N_VOLTAGES,              \
-       .linear_min_sel = S2MPS14_BUCK1235_START_SEL,           \
+       .linear_min_sel = min_sel,                              \
        .ramp_delay     = S2MPS14_BUCK_RAMP_DELAY,              \
        .vsel_reg       = S2MPS14_REG_B1CTRL2 + (num - 1) * 2,  \
        .vsel_mask      = S2MPS14_BUCK_VSEL_MASK,               \
@@ -613,11 +647,16 @@ static const struct regulator_desc s2mps14_regulators[] = {
        regulator_desc_s2mps14_ldo(23, MIN_800_MV, STEP_25_MV),
        regulator_desc_s2mps14_ldo(24, MIN_1800_MV, STEP_25_MV),
        regulator_desc_s2mps14_ldo(25, MIN_1800_MV, STEP_25_MV),
-       regulator_desc_s2mps14_buck(1, MIN_600_MV, STEP_6_25_MV),
-       regulator_desc_s2mps14_buck(2, MIN_600_MV, STEP_6_25_MV),
-       regulator_desc_s2mps14_buck(3, MIN_600_MV, STEP_6_25_MV),
-       regulator_desc_s2mps14_buck(4, MIN_1400_MV, STEP_12_5_MV),
-       regulator_desc_s2mps14_buck(5, MIN_600_MV, STEP_6_25_MV),
+       regulator_desc_s2mps14_buck(1, MIN_600_MV, STEP_6_25_MV,
+                                   S2MPS14_BUCK1235_START_SEL),
+       regulator_desc_s2mps14_buck(2, MIN_600_MV, STEP_6_25_MV,
+                                   S2MPS14_BUCK1235_START_SEL),
+       regulator_desc_s2mps14_buck(3, MIN_600_MV, STEP_6_25_MV,
+                                   S2MPS14_BUCK1235_START_SEL),
+       regulator_desc_s2mps14_buck(4, MIN_1400_MV, STEP_12_5_MV,
+                                   S2MPS14_BUCK4_START_SEL),
+       regulator_desc_s2mps14_buck(5, MIN_600_MV, STEP_6_25_MV,
+                                   S2MPS14_BUCK1235_START_SEL),
 };
 
 static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
index eebc52cb69849ea99f07c9c6694389a92e39afa5..3d95c87160b35003635460d5d67379d3da33d27f 100644 (file)
@@ -102,6 +102,8 @@ static int sunxi_reset_init(struct device_node *np)
                goto err_alloc;
        }
 
+       spin_lock_init(&data->lock);
+
        data->rcdev.owner = THIS_MODULE;
        data->rcdev.nr_resets = size * 32;
        data->rcdev.ops = &sunxi_reset_ops;
@@ -157,6 +159,8 @@ static int sunxi_reset_probe(struct platform_device *pdev)
        if (IS_ERR(data->membase))
                return PTR_ERR(data->membase);
 
+       spin_lock_init(&data->lock);
+
        data->rcdev.owner = THIS_MODULE;
        data->rcdev.nr_resets = resource_size(res) * 32;
        data->rcdev.ops = &sunxi_reset_ops;
index b5e7c4670205ba15e82cba6f2325d5cd5b994bcc..89ac1d5083c66093b63caa973e37ff4897a1bb6b 100644 (file)
@@ -832,6 +832,7 @@ static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume);
 static const struct platform_device_id s5m_rtc_id[] = {
        { "s5m-rtc",            S5M8767X },
        { "s2mps14-rtc",        S2MPS14X },
+       { },
 };
 
 static struct platform_driver s5m_rtc_driver = {
index 91e97ec0141892cbf4d1676480d5fda3223b0e6b..4d41bf75c23318577638fa45493aab748e0473a7 100644 (file)
@@ -1163,9 +1163,13 @@ static inline int ap_test_config_card_id(unsigned int id)
  */
 static inline int ap_test_config_domain(unsigned int domain)
 {
-       if (!ap_configuration)
-               return 1;
-       return ap_test_config(ap_configuration->aqm, domain);
+       if (!ap_configuration)    /* QCI not supported */
+               if (domain < 16)
+                       return 1; /* then domains 0...15 are configured */
+               else
+                       return 0;
+       else
+               return ap_test_config(ap_configuration->aqm, domain);
 }
 
 /**
index f407e3763432648f3271a80e2d432b7da8736c65..642c77c76b8432d07534e393335353cfbc27233a 100644 (file)
@@ -1784,6 +1784,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
        QETH_DBF_TEXT(SETUP, 2, "idxanswr");
        card = CARD_FROM_CDEV(channel->ccwdev);
        iob = qeth_get_buffer(channel);
+       if (!iob)
+               return -ENOMEM;
        iob->callback = idx_reply_cb;
        memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1));
        channel->ccw.count = QETH_BUFSIZE;
@@ -1834,6 +1836,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
        QETH_DBF_TEXT(SETUP, 2, "idxactch");
 
        iob = qeth_get_buffer(channel);
+       if (!iob)
+               return -ENOMEM;
        iob->callback = idx_reply_cb;
        memcpy(&channel->ccw, WRITE_CCW, sizeof(struct ccw1));
        channel->ccw.count = IDX_ACTIVATE_SIZE;
@@ -2021,10 +2025,36 @@ void qeth_prepare_control_data(struct qeth_card *card, int len,
 }
 EXPORT_SYMBOL_GPL(qeth_prepare_control_data);
 
+/**
+ * qeth_send_control_data() -  send control command to the card
+ * @card:                      qeth_card structure pointer
+ * @len:                       size of the command buffer
+ * @iob:                       qeth_cmd_buffer pointer
+ * @reply_cb:                  callback function pointer
+ * @cb_card:                   pointer to the qeth_card structure
+ * @cb_reply:                  pointer to the qeth_reply structure
+ * @cb_cmd:                    pointer to the original iob for non-IPA
+ *                             commands, or to the qeth_ipa_cmd structure
+ *                             for the IPA commands.
+ * @reply_param:               private pointer passed to the callback
+ *
+ * Returns the value of the `return_code' field of the response
+ * block returned from the hardware, or other error indication.
+ * Value of zero indicates successful execution of the command.
+ *
+ * Callback function gets called one or more times, with cb_cmd
+ * pointing to the response returned by the hardware. Callback
+ * function must return non-zero if more reply blocks are expected,
+ * and zero if the last or only reply block is received. Callback
+ * function can get the value of the reply_param pointer from the
+ * field 'param' of the structure qeth_reply.
+ */
+
 int qeth_send_control_data(struct qeth_card *card, int len,
                struct qeth_cmd_buffer *iob,
-               int (*reply_cb)(struct qeth_card *, struct qeth_reply *,
-                       unsigned long),
+               int (*reply_cb)(struct qeth_card *cb_card,
+                               struct qeth_reply *cb_reply,
+                               unsigned long cb_cmd),
                void *reply_param)
 {
        int rc;
@@ -2914,9 +2944,16 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
        struct qeth_cmd_buffer *iob;
        struct qeth_ipa_cmd *cmd;
 
-       iob = qeth_wait_for_buffer(&card->write);
-       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
-       qeth_fill_ipacmd_header(card, cmd, ipacmd, prot);
+       iob = qeth_get_buffer(&card->write);
+       if (iob) {
+               cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+               qeth_fill_ipacmd_header(card, cmd, ipacmd, prot);
+       } else {
+               dev_warn(&card->gdev->dev,
+                        "The qeth driver ran out of channel command buffers\n");
+               QETH_DBF_MESSAGE(1, "%s The qeth driver ran out of channel command buffers",
+                                dev_name(&card->gdev->dev));
+       }
 
        return iob;
 }
@@ -2932,6 +2969,12 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
 }
 EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd);
 
+/**
+ * qeth_send_ipa_cmd() - send an IPA command
+ *
+ * See qeth_send_control_data() for explanation of the arguments.
+ */
+
 int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
                int (*reply_cb)(struct qeth_card *, struct qeth_reply*,
                        unsigned long),
@@ -2968,6 +3011,8 @@ int qeth_send_startlan(struct qeth_card *card)
        QETH_DBF_TEXT(SETUP, 2, "strtlan");
 
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_STARTLAN, 0);
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
        return rc;
 }
@@ -3013,11 +3058,13 @@ static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
 
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETADAPTERPARMS,
                                     QETH_PROT_IPV4);
-       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
-       cmd->data.setadapterparms.hdr.cmdlength = cmdlen;
-       cmd->data.setadapterparms.hdr.command_code = command;
-       cmd->data.setadapterparms.hdr.used_total = 1;
-       cmd->data.setadapterparms.hdr.seq_no = 1;
+       if (iob) {
+               cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+               cmd->data.setadapterparms.hdr.cmdlength = cmdlen;
+               cmd->data.setadapterparms.hdr.command_code = command;
+               cmd->data.setadapterparms.hdr.used_total = 1;
+               cmd->data.setadapterparms.hdr.seq_no = 1;
+       }
 
        return iob;
 }
@@ -3030,6 +3077,8 @@ int qeth_query_setadapterparms(struct qeth_card *card)
        QETH_CARD_TEXT(card, 3, "queryadp");
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_COMMANDS_SUPPORTED,
                                   sizeof(struct qeth_ipacmd_setadpparms));
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_send_ipa_cmd(card, iob, qeth_query_setadapterparms_cb, NULL);
        return rc;
 }
@@ -3080,6 +3129,8 @@ int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot)
 
        QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot);
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot);
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL);
        return rc;
 }
@@ -3119,6 +3170,8 @@ int qeth_query_switch_attributes(struct qeth_card *card,
                return -ENOMEDIUM;
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_SWITCH_ATTRIBUTES,
                                sizeof(struct qeth_ipacmd_setadpparms_hdr));
+       if (!iob)
+               return -ENOMEM;
        return qeth_send_ipa_cmd(card, iob,
                                qeth_query_switch_attributes_cb, sw_info);
 }
@@ -3146,6 +3199,8 @@ static int qeth_query_setdiagass(struct qeth_card *card)
 
        QETH_DBF_TEXT(SETUP, 2, "qdiagass");
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.diagass.subcmd_len = 16;
        cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY;
@@ -3197,6 +3252,8 @@ int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action)
 
        QETH_DBF_TEXT(SETUP, 2, "diagtrap");
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.diagass.subcmd_len = 80;
        cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP;
@@ -4162,6 +4219,8 @@ void qeth_setadp_promisc_mode(struct qeth_card *card)
 
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_PROMISC_MODE,
                        sizeof(struct qeth_ipacmd_setadpparms));
+       if (!iob)
+               return;
        cmd = (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
        cmd->data.setadapterparms.data.mode = mode;
        qeth_send_ipa_cmd(card, iob, qeth_setadp_promisc_mode_cb, NULL);
@@ -4232,6 +4291,8 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
 
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_ALTER_MAC_ADDRESS,
                                   sizeof(struct qeth_ipacmd_setadpparms));
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.setadapterparms.data.change_addr.cmd = CHANGE_ADDR_READ_MAC;
        cmd->data.setadapterparms.data.change_addr.addr_size = OSA_ADDR_LEN;
@@ -4345,6 +4406,8 @@ static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL,
                                   sizeof(struct qeth_ipacmd_setadpparms_hdr) +
                                   sizeof(struct qeth_set_access_ctrl));
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
        access_ctrl_req->subcmd_code = isolation;
@@ -4588,6 +4651,10 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
 
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL,
                                   QETH_SNMP_SETADP_CMDLENGTH + req_len);
+       if (!iob) {
+               rc = -ENOMEM;
+               goto out;
+       }
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len);
        rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len,
@@ -4599,7 +4666,7 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata)
                if (copy_to_user(udata, qinfo.udata, qinfo.udata_len))
                        rc = -EFAULT;
        }
-
+out:
        kfree(ureq);
        kfree(qinfo.udata);
        return rc;
@@ -4670,6 +4737,10 @@ int qeth_query_oat_command(struct qeth_card *card, char __user *udata)
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT,
                                   sizeof(struct qeth_ipacmd_setadpparms_hdr) +
                                   sizeof(struct qeth_query_oat));
+       if (!iob) {
+               rc = -ENOMEM;
+               goto out_free;
+       }
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        oat_req = &cmd->data.setadapterparms.data.query_oat;
        oat_req->subcmd_code = oat_data.command;
@@ -4735,6 +4806,8 @@ static int qeth_query_card_info(struct qeth_card *card,
                return -EOPNOTSUPP;
        iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_CARD_INFO,
                sizeof(struct qeth_ipacmd_setadpparms_hdr));
+       if (!iob)
+               return -ENOMEM;
        return qeth_send_ipa_cmd(card, iob, qeth_query_card_info_cb,
                                        (void *)carrier_info);
 }
@@ -5060,11 +5133,23 @@ retriable:
        card->options.adp.supported_funcs = 0;
        card->options.sbp.supported_funcs = 0;
        card->info.diagass_support = 0;
-       qeth_query_ipassists(card, QETH_PROT_IPV4);
-       if (qeth_is_supported(card, IPA_SETADAPTERPARMS))
-               qeth_query_setadapterparms(card);
-       if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
-               qeth_query_setdiagass(card);
+       rc = qeth_query_ipassists(card, QETH_PROT_IPV4);
+       if (rc == -ENOMEM)
+               goto out;
+       if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) {
+               rc = qeth_query_setadapterparms(card);
+               if (rc < 0) {
+                       QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
+                       goto out;
+               }
+       }
+       if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) {
+               rc = qeth_query_setdiagass(card);
+               if (rc < 0) {
+                       QETH_DBF_TEXT_(SETUP, 2, "7err%d", rc);
+                       goto out;
+               }
+       }
        return 0;
 out:
        dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
index d02cd1a679432fc7ef485295d308bac046f96df9..ce87ae72edbd62caae02d88035c991b6909d0bfd 100644 (file)
@@ -27,10 +27,7 @@ static int qeth_l2_set_offline(struct ccwgroup_device *);
 static int qeth_l2_stop(struct net_device *);
 static int qeth_l2_send_delmac(struct qeth_card *, __u8 *);
 static int qeth_l2_send_setdelmac(struct qeth_card *, __u8 *,
-                          enum qeth_ipa_cmds,
-                          int (*reply_cb) (struct qeth_card *,
-                                           struct qeth_reply*,
-                                           unsigned long));
+                          enum qeth_ipa_cmds);
 static void qeth_l2_set_multicast_list(struct net_device *);
 static int qeth_l2_recover(void *);
 static void qeth_bridgeport_query_support(struct qeth_card *card);
@@ -130,56 +127,71 @@ static struct net_device *qeth_l2_netdev_by_devno(unsigned char *read_dev_no)
        return ndev;
 }
 
-static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card,
-                               struct qeth_reply *reply,
-                               unsigned long data)
+static int qeth_setdel_makerc(struct qeth_card *card, int retcode)
 {
-       struct qeth_ipa_cmd *cmd;
-       __u8 *mac;
+       int rc;
 
-       QETH_CARD_TEXT(card, 2, "L2Sgmacb");
-       cmd = (struct qeth_ipa_cmd *) data;
-       mac = &cmd->data.setdelmac.mac[0];
-       /* MAC already registered, needed in couple/uncouple case */
-       if (cmd->hdr.return_code ==  IPA_RC_L2_DUP_MAC) {
-               QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n",
-                         mac, QETH_CARD_IFNAME(card));
-               cmd->hdr.return_code = 0;
+       if (retcode)
+               QETH_CARD_TEXT_(card, 2, "err%04x", retcode);
+       switch (retcode) {
+       case IPA_RC_SUCCESS:
+               rc = 0;
+               break;
+       case IPA_RC_L2_UNSUPPORTED_CMD:
+               rc = -ENOSYS;
+               break;
+       case IPA_RC_L2_ADDR_TABLE_FULL:
+               rc = -ENOSPC;
+               break;
+       case IPA_RC_L2_DUP_MAC:
+       case IPA_RC_L2_DUP_LAYER3_MAC:
+               rc = -EEXIST;
+               break;
+       case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
+       case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
+               rc = -EPERM;
+               break;
+       case IPA_RC_L2_MAC_NOT_FOUND:
+               rc = -ENOENT;
+               break;
+       case -ENOMEM:
+               rc = -ENOMEM;
+               break;
+       default:
+               rc = -EIO;
+               break;
        }
-       if (cmd->hdr.return_code)
-               QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n",
-                         mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code);
-       return 0;
+       return rc;
 }
 
 static int qeth_l2_send_setgroupmac(struct qeth_card *card, __u8 *mac)
 {
-       QETH_CARD_TEXT(card, 2, "L2Sgmac");
-       return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETGMAC,
-                                         qeth_l2_send_setgroupmac_cb);
-}
-
-static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card,
-                               struct qeth_reply *reply,
-                               unsigned long data)
-{
-       struct qeth_ipa_cmd *cmd;
-       __u8 *mac;
+       int rc;
 
-       QETH_CARD_TEXT(card, 2, "L2Dgmacb");
-       cmd = (struct qeth_ipa_cmd *) data;
-       mac = &cmd->data.setdelmac.mac[0];
-       if (cmd->hdr.return_code)
-               QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n",
-                         mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code);
-       return 0;
+       QETH_CARD_TEXT(card, 2, "L2Sgmac");
+       rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac,
+                                       IPA_CMD_SETGMAC));
+       if (rc == -EEXIST)
+               QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s\n",
+                       mac, QETH_CARD_IFNAME(card));
+       else if (rc)
+               QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %d\n",
+                       mac, QETH_CARD_IFNAME(card), rc);
+       return rc;
 }
 
 static int qeth_l2_send_delgroupmac(struct qeth_card *card, __u8 *mac)
 {
+       int rc;
+
        QETH_CARD_TEXT(card, 2, "L2Dgmac");
-       return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELGMAC,
-                                         qeth_l2_send_delgroupmac_cb);
+       rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac,
+                                       IPA_CMD_DELGMAC));
+       if (rc)
+               QETH_DBF_MESSAGE(2,
+                       "Could not delete group MAC %pM on %s: %d\n",
+                       mac, QETH_CARD_IFNAME(card), rc);
+       return rc;
 }
 
 static void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac, int vmac)
@@ -197,10 +209,11 @@ static void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac, int vmac)
        mc->is_vmac = vmac;
 
        if (vmac) {
-               rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC,
-                                       NULL);
+               rc = qeth_setdel_makerc(card,
+                       qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC));
        } else {
-               rc = qeth_l2_send_setgroupmac(card, mac);
+               rc = qeth_setdel_makerc(card,
+                       qeth_l2_send_setgroupmac(card, mac));
        }
 
        if (!rc)
@@ -218,7 +231,7 @@ static void qeth_l2_del_all_mc(struct qeth_card *card, int del)
                if (del) {
                        if (mc->is_vmac)
                                qeth_l2_send_setdelmac(card, mc->mc_addr,
-                                       IPA_CMD_DELVMAC, NULL);
+                                       IPA_CMD_DELVMAC);
                        else
                                qeth_l2_send_delgroupmac(card, mc->mc_addr);
                }
@@ -291,6 +304,8 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
 
        QETH_CARD_TEXT_(card, 4, "L2sdv%x", ipacmd);
        iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.setdelvlan.vlan_id = i;
        return qeth_send_ipa_cmd(card, iob,
@@ -313,6 +328,7 @@ static int qeth_l2_vlan_rx_add_vid(struct net_device *dev,
 {
        struct qeth_card *card = dev->ml_priv;
        struct qeth_vlan_vid *id;
+       int rc;
 
        QETH_CARD_TEXT_(card, 4, "aid:%d", vid);
        if (!vid)
@@ -328,7 +344,11 @@ static int qeth_l2_vlan_rx_add_vid(struct net_device *dev,
        id = kmalloc(sizeof(struct qeth_vlan_vid), GFP_ATOMIC);
        if (id) {
                id->vid = vid;
-               qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN);
+               rc = qeth_l2_send_setdelvlan(card, vid, IPA_CMD_SETVLAN);
+               if (rc) {
+                       kfree(id);
+                       return rc;
+               }
                spin_lock_bh(&card->vlanlock);
                list_add_tail(&id->list, &card->vid_list);
                spin_unlock_bh(&card->vlanlock);
@@ -343,6 +363,7 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
 {
        struct qeth_vlan_vid *id, *tmpid = NULL;
        struct qeth_card *card = dev->ml_priv;
+       int rc = 0;
 
        QETH_CARD_TEXT_(card, 4, "kid:%d", vid);
        if (card->info.type == QETH_CARD_TYPE_OSM) {
@@ -363,11 +384,11 @@ static int qeth_l2_vlan_rx_kill_vid(struct net_device *dev,
        }
        spin_unlock_bh(&card->vlanlock);
        if (tmpid) {
-               qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
+               rc = qeth_l2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
                kfree(tmpid);
        }
        qeth_l2_set_multicast_list(card->dev);
-       return 0;
+       return rc;
 }
 
 static int qeth_l2_stop_card(struct qeth_card *card, int recovery_mode)
@@ -539,91 +560,62 @@ out:
 }
 
 static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
-                          enum qeth_ipa_cmds ipacmd,
-                          int (*reply_cb) (struct qeth_card *,
-                                           struct qeth_reply*,
-                                           unsigned long))
+                          enum qeth_ipa_cmds ipacmd)
 {
        struct qeth_ipa_cmd *cmd;
        struct qeth_cmd_buffer *iob;
 
        QETH_CARD_TEXT(card, 2, "L2sdmac");
        iob = qeth_get_ipacmd_buffer(card, ipacmd, QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.setdelmac.mac_length = OSA_ADDR_LEN;
        memcpy(&cmd->data.setdelmac.mac, mac, OSA_ADDR_LEN);
-       return qeth_send_ipa_cmd(card, iob, reply_cb, NULL);
+       return qeth_send_ipa_cmd(card, iob, NULL, NULL);
 }
 
-static int qeth_l2_send_setmac_cb(struct qeth_card *card,
-                          struct qeth_reply *reply,
-                          unsigned long data)
+static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
 {
-       struct qeth_ipa_cmd *cmd;
+       int rc;
 
-       QETH_CARD_TEXT(card, 2, "L2Smaccb");
-       cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->hdr.return_code) {
-               QETH_CARD_TEXT_(card, 2, "L2er%x", cmd->hdr.return_code);
+       QETH_CARD_TEXT(card, 2, "L2Setmac");
+       rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac,
+                                       IPA_CMD_SETVMAC));
+       if (rc == 0) {
+               card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
+               memcpy(card->dev->dev_addr, mac, OSA_ADDR_LEN);
+               dev_info(&card->gdev->dev,
+                       "MAC address %pM successfully registered on device %s\n",
+                       card->dev->dev_addr, card->dev->name);
+       } else {
                card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
-               switch (cmd->hdr.return_code) {
-               case IPA_RC_L2_DUP_MAC:
-               case IPA_RC_L2_DUP_LAYER3_MAC:
+               switch (rc) {
+               case -EEXIST:
                        dev_warn(&card->gdev->dev,
-                               "MAC address %pM already exists\n",
-                               cmd->data.setdelmac.mac);
+                               "MAC address %pM already exists\n", mac);
                        break;
-               case IPA_RC_L2_MAC_NOT_AUTH_BY_HYP:
-               case IPA_RC_L2_MAC_NOT_AUTH_BY_ADP:
+               case -EPERM:
                        dev_warn(&card->gdev->dev,
-                               "MAC address %pM is not authorized\n",
-                               cmd->data.setdelmac.mac);
-                       break;
-               default:
+                               "MAC address %pM is not authorized\n", mac);
                        break;
                }
-       } else {
-               card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
-               memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac,
-                      OSA_ADDR_LEN);
-               dev_info(&card->gdev->dev,
-                       "MAC address %pM successfully registered on device %s\n",
-                       card->dev->dev_addr, card->dev->name);
-       }
-       return 0;
-}
-
-static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
-{
-       QETH_CARD_TEXT(card, 2, "L2Setmac");
-       return qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC,
-                                         qeth_l2_send_setmac_cb);
-}
-
-static int qeth_l2_send_delmac_cb(struct qeth_card *card,
-                          struct qeth_reply *reply,
-                          unsigned long data)
-{
-       struct qeth_ipa_cmd *cmd;
-
-       QETH_CARD_TEXT(card, 2, "L2Dmaccb");
-       cmd = (struct qeth_ipa_cmd *) data;
-       if (cmd->hdr.return_code) {
-               QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
-               return 0;
        }
-       card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
-
-       return 0;
+       return rc;
 }
 
 static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
 {
+       int rc;
+
        QETH_CARD_TEXT(card, 2, "L2Delmac");
        if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
                return 0;
-       return qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC,
-                                         qeth_l2_send_delmac_cb);
+       rc = qeth_setdel_makerc(card, qeth_l2_send_setdelmac(card, mac,
+                                       IPA_CMD_DELVMAC));
+       if (rc == 0)
+               card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
+       return rc;
 }
 
 static int qeth_l2_request_initial_mac(struct qeth_card *card)
@@ -651,7 +643,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
                if (rc) {
                        QETH_DBF_MESSAGE(2, "couldn't get MAC address on "
                                "device %s: x%x\n", CARD_BUS_ID(card), rc);
-                       QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc);
+                       QETH_DBF_TEXT_(SETUP, 2, "1err%04x", rc);
                        return rc;
                }
                QETH_DBF_HEX(SETUP, 2, card->dev->dev_addr, OSA_ADDR_LEN);
@@ -687,7 +679,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
                return -ERESTARTSYS;
        }
        rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
-       if (!rc || (rc == IPA_RC_L2_MAC_NOT_FOUND))
+       if (!rc || (rc == -ENOENT))
                rc = qeth_l2_send_setmac(card, addr->sa_data);
        return rc ? -EINVAL : 0;
 }
@@ -996,7 +988,7 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        recover_flag = card->state;
        rc = qeth_core_hardsetup_card(card);
        if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
+               QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
                rc = -ENODEV;
                goto out_remove;
        }
@@ -1730,6 +1722,8 @@ static void qeth_bridgeport_query_support(struct qeth_card *card)
 
        QETH_CARD_TEXT(card, 2, "brqsuppo");
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+       if (!iob)
+               return;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.sbp.hdr.cmdlength =
                sizeof(struct qeth_ipacmd_sbp_hdr) +
@@ -1805,6 +1799,8 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
        if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS))
                return -EOPNOTSUPP;
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.sbp.hdr.cmdlength =
                sizeof(struct qeth_ipacmd_sbp_hdr);
@@ -1817,9 +1813,7 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
        if (rc)
                return rc;
        rc = qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
-       if (rc)
-               return rc;
-       return 0;
+       return rc;
 }
 EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports);
 
@@ -1873,6 +1867,8 @@ int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
        if (!(card->options.sbp.supported_funcs & setcmd))
                return -EOPNOTSUPP;
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.sbp.hdr.cmdlength = cmdlength;
        cmd->data.sbp.hdr.command_code = setcmd;
index 625227ad16ee91cd2b4ca1aaa8a9541408e2a838..e2a0ee845399d64d48a5dfdb813161feeb9e58e2 100644 (file)
@@ -549,6 +549,8 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
        QETH_CARD_TEXT(card, 4, "setdelmc");
 
        iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        memcpy(&cmd->data.setdelipm.mac, addr->mac, OSA_ADDR_LEN);
        if (addr->proto == QETH_PROT_IPV6)
@@ -588,6 +590,8 @@ static int qeth_l3_send_setdelip(struct qeth_card *card,
        QETH_CARD_TEXT_(card, 4, "flags%02X", flags);
 
        iob = qeth_get_ipacmd_buffer(card, ipacmd, addr->proto);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        if (addr->proto == QETH_PROT_IPV6) {
                memcpy(cmd->data.setdelip6.ip_addr, &addr->u.a6.addr,
@@ -616,6 +620,8 @@ static int qeth_l3_send_setrouting(struct qeth_card *card,
 
        QETH_CARD_TEXT(card, 4, "setroutg");
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETRTG, prot);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.setrtg.type = (type);
        rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
@@ -1049,12 +1055,14 @@ static struct qeth_cmd_buffer *qeth_l3_get_setassparms_cmd(
        QETH_CARD_TEXT(card, 4, "getasscm");
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, prot);
 
-       cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
-       cmd->data.setassparms.hdr.assist_no = ipa_func;
-       cmd->data.setassparms.hdr.length = 8 + len;
-       cmd->data.setassparms.hdr.command_code = cmd_code;
-       cmd->data.setassparms.hdr.return_code = 0;
-       cmd->data.setassparms.hdr.seq_no = 0;
+       if (iob) {
+               cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+               cmd->data.setassparms.hdr.assist_no = ipa_func;
+               cmd->data.setassparms.hdr.length = 8 + len;
+               cmd->data.setassparms.hdr.command_code = cmd_code;
+               cmd->data.setassparms.hdr.return_code = 0;
+               cmd->data.setassparms.hdr.seq_no = 0;
+       }
 
        return iob;
 }
@@ -1090,6 +1098,8 @@ static int qeth_l3_send_simple_setassparms_ipv6(struct qeth_card *card,
        QETH_CARD_TEXT(card, 4, "simassp6");
        iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
                                       0, QETH_PROT_IPV6);
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_l3_send_setassparms(card, iob, 0, 0,
                                   qeth_l3_default_setassparms_cb, NULL);
        return rc;
@@ -1108,6 +1118,8 @@ static int qeth_l3_send_simple_setassparms(struct qeth_card *card,
                length = sizeof(__u32);
        iob = qeth_l3_get_setassparms_cmd(card, ipa_func, cmd_code,
                                       length, QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_l3_send_setassparms(card, iob, length, data,
                                   qeth_l3_default_setassparms_cb, NULL);
        return rc;
@@ -1494,6 +1506,8 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
 
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
                                     QETH_PROT_IPV6);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
                        card->info.unique_id;
@@ -1537,6 +1551,8 @@ static int qeth_l3_get_unique_id(struct qeth_card *card)
 
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_CREATE_ADDR,
                                     QETH_PROT_IPV6);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        *((__u16 *) &cmd->data.create_destroy_addr.unique_id[6]) =
                        card->info.unique_id;
@@ -1611,6 +1627,8 @@ qeth_diags_trace(struct qeth_card *card, enum qeth_diags_trace_cmds diags_cmd)
        QETH_DBF_TEXT(SETUP, 2, "diagtrac");
 
        iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.diagass.subcmd_len = 16;
        cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRACE;
@@ -2442,6 +2460,8 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
                        IPA_CMD_ASS_ARP_QUERY_INFO,
                        sizeof(struct qeth_arp_query_data) - sizeof(char),
                        prot);
+       if (!iob)
+               return -ENOMEM;
        cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
        cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
        cmd->data.setassparms.data.query_arp.reply_bits = 0;
@@ -2535,6 +2555,8 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card,
                                       IPA_CMD_ASS_ARP_ADD_ENTRY,
                                       sizeof(struct qeth_arp_cache_entry),
                                       QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_l3_send_setassparms(card, iob,
                                   sizeof(struct qeth_arp_cache_entry),
                                   (unsigned long) entry,
@@ -2574,6 +2596,8 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card,
                                       IPA_CMD_ASS_ARP_REMOVE_ENTRY,
                                       12,
                                       QETH_PROT_IPV4);
+       if (!iob)
+               return -ENOMEM;
        rc = qeth_l3_send_setassparms(card, iob,
                                   12, (unsigned long)buf,
                                   qeth_l3_default_setassparms_cb, NULL);
@@ -3262,6 +3286,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
 
 static int qeth_l3_setup_netdev(struct qeth_card *card)
 {
+       int rc;
+
        if (card->info.type == QETH_CARD_TYPE_OSD ||
            card->info.type == QETH_CARD_TYPE_OSX) {
                if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
@@ -3293,7 +3319,9 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
                        return -ENODEV;
                card->dev->flags |= IFF_NOARP;
                card->dev->netdev_ops = &qeth_l3_netdev_ops;
-               qeth_l3_iqd_read_initial_mac(card);
+               rc = qeth_l3_iqd_read_initial_mac(card);
+               if (rc)
+                       return rc;
                if (card->options.hsuid[0])
                        memcpy(card->dev->perm_addr, card->options.hsuid, 9);
        } else
@@ -3360,7 +3388,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
        recover_flag = card->state;
        rc = qeth_core_hardsetup_card(card);
        if (rc) {
-               QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
+               QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
                rc = -ENODEV;
                goto out_remove;
        }
@@ -3401,7 +3429,7 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
 contin:
        rc = qeth_l3_setadapter_parms(card);
        if (rc)
-               QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
+               QETH_DBF_TEXT_(SETUP, 2, "2err%04x", rc);
        if (!card->options.sniffer) {
                rc = qeth_l3_start_ipassists(card);
                if (rc) {
@@ -3410,10 +3438,10 @@ contin:
                }
                rc = qeth_l3_setrouting_v4(card);
                if (rc)
-                       QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
+                       QETH_DBF_TEXT_(SETUP, 2, "4err%04x", rc);
                rc = qeth_l3_setrouting_v6(card);
                if (rc)
-                       QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
+                       QETH_DBF_TEXT_(SETUP, 2, "5err%04x", rc);
        }
        netif_tx_disable(card->dev);
 
index 3b73b96619e2deeb82e203927f57904913a51dff..26270c351624f229cf85b6069ffe53ee26d50bef 100644 (file)
@@ -39,7 +39,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.6.0.16"
+#define DRV_VERSION            "1.6.0.17"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
index 2097de42a14775c1b164485482e834198a77f474..155b286f1a9d3cc8b366a6a5b7610ae562337f62 100644 (file)
@@ -1892,6 +1892,21 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
                goto fnic_abort_cmd_end;
        }
 
+       /* IO out of order */
+
+       if (!(CMD_FLAGS(sc) & (FNIC_IO_ABORTED | FNIC_IO_DONE))) {
+               spin_unlock_irqrestore(io_lock, flags);
+               FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+                       "Issuing Host reset due to out of order IO\n");
+
+               if (fnic_host_reset(sc) == FAILED) {
+                       FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+                               "fnic_host_reset failed.\n");
+               }
+               ret = FAILED;
+               goto fnic_abort_cmd_end;
+       }
+
        CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE;
 
        /*
index df4e27cd996a3c68cf095e40d7a6ccf7ebf6a065..9219953ee949a9dfaf1ff0f044e41a3e5c13adc7 100644 (file)
@@ -683,6 +683,7 @@ static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd,
        ipr_reinit_ipr_cmnd(ipr_cmd);
        ipr_cmd->u.scratch = 0;
        ipr_cmd->sibling = NULL;
+       ipr_cmd->eh_comp = NULL;
        ipr_cmd->fast_done = fast_done;
        init_timer(&ipr_cmd->timer);
 }
@@ -848,6 +849,8 @@ static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
 
        scsi_dma_unmap(ipr_cmd->scsi_cmd);
        scsi_cmd->scsi_done(scsi_cmd);
+       if (ipr_cmd->eh_comp)
+               complete(ipr_cmd->eh_comp);
        list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q);
 }
 
@@ -4811,6 +4814,84 @@ static int ipr_slave_alloc(struct scsi_device *sdev)
        return rc;
 }
 
+/**
+ * ipr_match_lun - Match function for specified LUN
+ * @ipr_cmd:   ipr command struct
+ * @device:            device to match (sdev)
+ *
+ * Returns:
+ *     1 if command matches sdev / 0 if command does not match sdev
+ **/
+static int ipr_match_lun(struct ipr_cmnd *ipr_cmd, void *device)
+{
+       if (ipr_cmd->scsi_cmd && ipr_cmd->scsi_cmd->device == device)
+               return 1;
+       return 0;
+}
+
+/**
+ * ipr_wait_for_ops - Wait for matching commands to complete
+ * @ipr_cmd:   ipr command struct
+ * @device:            device to match (sdev)
+ * @match:             match function to use
+ *
+ * Returns:
+ *     SUCCESS / FAILED
+ **/
+static int ipr_wait_for_ops(struct ipr_ioa_cfg *ioa_cfg, void *device,
+                           int (*match)(struct ipr_cmnd *, void *))
+{
+       struct ipr_cmnd *ipr_cmd;
+       int wait;
+       unsigned long flags;
+       struct ipr_hrr_queue *hrrq;
+       signed long timeout = IPR_ABORT_TASK_TIMEOUT;
+       DECLARE_COMPLETION_ONSTACK(comp);
+
+       ENTER;
+       do {
+               wait = 0;
+
+               for_each_hrrq(hrrq, ioa_cfg) {
+                       spin_lock_irqsave(hrrq->lock, flags);
+                       list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
+                               if (match(ipr_cmd, device)) {
+                                       ipr_cmd->eh_comp = &comp;
+                                       wait++;
+                               }
+                       }
+                       spin_unlock_irqrestore(hrrq->lock, flags);
+               }
+
+               if (wait) {
+                       timeout = wait_for_completion_timeout(&comp, timeout);
+
+                       if (!timeout) {
+                               wait = 0;
+
+                               for_each_hrrq(hrrq, ioa_cfg) {
+                                       spin_lock_irqsave(hrrq->lock, flags);
+                                       list_for_each_entry(ipr_cmd, &hrrq->hrrq_pending_q, queue) {
+                                               if (match(ipr_cmd, device)) {
+                                                       ipr_cmd->eh_comp = NULL;
+                                                       wait++;
+                                               }
+                                       }
+                                       spin_unlock_irqrestore(hrrq->lock, flags);
+                               }
+
+                               if (wait)
+                                       dev_err(&ioa_cfg->pdev->dev, "Timed out waiting for aborted commands\n");
+                               LEAVE;
+                               return wait ? FAILED : SUCCESS;
+                       }
+               }
+       } while (wait);
+
+       LEAVE;
+       return SUCCESS;
+}
+
 static int ipr_eh_host_reset(struct scsi_cmnd *cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg;
@@ -5030,11 +5111,17 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd *scsi_cmd)
 static int ipr_eh_dev_reset(struct scsi_cmnd *cmd)
 {
        int rc;
+       struct ipr_ioa_cfg *ioa_cfg;
+
+       ioa_cfg = (struct ipr_ioa_cfg *) cmd->device->host->hostdata;
 
        spin_lock_irq(cmd->device->host->host_lock);
        rc = __ipr_eh_dev_reset(cmd);
        spin_unlock_irq(cmd->device->host->host_lock);
 
+       if (rc == SUCCESS)
+               rc = ipr_wait_for_ops(ioa_cfg, cmd->device, ipr_match_lun);
+
        return rc;
 }
 
@@ -5234,13 +5321,18 @@ static int ipr_eh_abort(struct scsi_cmnd *scsi_cmd)
 {
        unsigned long flags;
        int rc;
+       struct ipr_ioa_cfg *ioa_cfg;
 
        ENTER;
 
+       ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
+
        spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
        rc = ipr_cancel_op(scsi_cmd);
        spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
 
+       if (rc == SUCCESS)
+               rc = ipr_wait_for_ops(ioa_cfg, scsi_cmd->device, ipr_match_lun);
        LEAVE;
        return rc;
 }
index b4f3eec51bc9b19783f931116f63aa70bc2d235a..ec03b42fa2b9fe0f388bc266fd75e8190460f682 100644 (file)
@@ -1606,6 +1606,7 @@ struct ipr_cmnd {
                struct scsi_device *sdev;
        } u;
 
+       struct completion *eh_comp;
        struct ipr_hrr_queue *hrrq;
        struct ipr_ioa_cfg *ioa_cfg;
 };
index 12ca291c1380845e45a40b0b4f5f4dd3356ab429..cce1cbc1a9276f4492d6efa16996313c00daabd6 100644 (file)
@@ -734,7 +734,9 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
         * Return target busy if we've received a non-zero retry_delay_timer
         * in a FCP_RSP.
         */
-       if (time_after(jiffies, fcport->retry_delay_timestamp))
+       if (fcport->retry_delay_timestamp == 0) {
+               /* retry delay not set */
+       } else if (time_after(jiffies, fcport->retry_delay_timestamp))
                fcport->retry_delay_timestamp = 0;
        else
                goto qc24_target_busy;
index e02885451425dbd4af6272ce53d1b2b54f809a43..9b3829931f40d95c2cdd4e673c33a56b510edc9b 100644 (file)
@@ -986,9 +986,9 @@ int scsi_device_get(struct scsi_device *sdev)
                return -ENXIO;
        if (!get_device(&sdev->sdev_gendev))
                return -ENXIO;
-       /* We can fail this if we're doing SCSI operations
+       /* We can fail try_module_get if we're doing SCSI operations
         * from module exit (like cache flush) */
-       try_module_get(sdev->host->hostt->module);
+       __module_get(sdev->host->hostt->module);
 
        return 0;
 }
@@ -1004,14 +1004,7 @@ EXPORT_SYMBOL(scsi_device_get);
  */
 void scsi_device_put(struct scsi_device *sdev)
 {
-#ifdef CONFIG_MODULE_UNLOAD
-       struct module *module = sdev->host->hostt->module;
-
-       /* The module refcount will be zero if scsi_device_get()
-        * was called from a module removal routine */
-       if (module && module_refcount(module) != 0)
-               module_put(module);
-#endif
+       module_put(sdev->host->hostt->module);
        put_device(&sdev->sdev_gendev);
 }
 EXPORT_SYMBOL(scsi_device_put);
index 7b8b51bc29b4353debc9bd9911fcbf939753c782..4aca1b0378c2458212945a3877b303062ea529ca 100644 (file)
@@ -1623,7 +1623,7 @@ resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        req_opcode = cmd[3];
        req_sa = get_unaligned_be16(cmd + 4);
        alloc_len = get_unaligned_be32(cmd + 6);
-       if (alloc_len < 4 && alloc_len > 0xffff) {
+       if (alloc_len < 4 || alloc_len > 0xffff) {
                mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
                return check_condition_result;
        }
@@ -1631,7 +1631,7 @@ resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                a_len = 8192;
        else
                a_len = alloc_len;
-       arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_KERNEL);
+       arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
        if (NULL == arr) {
                mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
                                INSUFF_RES_ASCQ);
index e42fff6e8c109d66891bf291c07f7cb14a875b30..8afb01604d515baff0ed4b10e2d526326935a913 100644 (file)
@@ -1041,7 +1041,7 @@ retry:
                }
                /* signal not to enter either branch of the if () below */
                timeleft = 0;
-               rtn = NEEDS_RETRY;
+               rtn = FAILED;
        } else {
                timeleft = wait_for_completion_timeout(&done, timeout);
                rtn = SUCCESS;
@@ -1081,7 +1081,7 @@ retry:
                        rtn = FAILED;
                        break;
                }
-       } else if (!rtn) {
+       } else if (rtn != FAILED) {
                scsi_abort_eh_cmnd(scmd);
                rtn = FAILED;
        }
index 9ea95dd3e2604eea2613a5a15d074c2357fac7dd..17bb541f7cc259a8a3f52c65ec1cae5636e87f65 100644 (file)
@@ -591,7 +591,6 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb, bool mq)
 static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, bool mq)
 {
        struct scatterlist *first_chunk = NULL;
-       gfp_t gfp_mask = mq ? GFP_NOIO : GFP_ATOMIC;
        int ret;
 
        BUG_ON(!nents);
@@ -606,7 +605,7 @@ static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, bool mq)
        }
 
        ret = __sg_alloc_table(&sdb->table, nents, SCSI_MAX_SG_SEGMENTS,
-                              first_chunk, gfp_mask, scsi_sg_alloc);
+                              first_chunk, GFP_ATOMIC, scsi_sg_alloc);
        if (unlikely(ret))
                scsi_free_sgtable(sdb, mq);
        return ret;
@@ -1144,7 +1143,17 @@ int scsi_init_io(struct scsi_cmnd *cmd)
                struct scsi_data_buffer *prot_sdb = cmd->prot_sdb;
                int ivecs, count;
 
-               BUG_ON(prot_sdb == NULL);
+               if (prot_sdb == NULL) {
+                       /*
+                        * This can happen if someone (e.g. multipath)
+                        * queues a command to a device on an adapter
+                        * that does not support DIX.
+                        */
+                       WARN_ON_ONCE(1);
+                       error = BLKPREP_KILL;
+                       goto err_exit;
+               }
+
                ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
 
                if (scsi_alloc_sgtable(prot_sdb, ivecs, is_mq)) {
index fedab3c21ddf18adcb291a99c49b7b4ac051aa85..399516925d802fea379938b9958778daa7ee37f2 100644 (file)
@@ -2623,8 +2623,9 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
                                sd_config_discard(sdkp, SD_LBP_WS16);
 
                } else {        /* LBP VPD page tells us what to use */
-
-                       if (sdkp->lbpws)
+                       if (sdkp->lbpu && sdkp->max_unmap_blocks && !sdkp->lbprz)
+                               sd_config_discard(sdkp, SD_LBP_UNMAP);
+                       else if (sdkp->lbpws)
                                sd_config_discard(sdkp, SD_LBP_WS16);
                        else if (sdkp->lbpws10)
                                sd_config_discard(sdkp, SD_LBP_WS10);
index 7281316a5ecba79203dc7351b280ab25cd5f2d11..a67d37c7e3c00f9518694f267aa75efd5c73398a 100644 (file)
@@ -271,7 +271,6 @@ int dw_spi_mid_init(struct dw_spi *dws)
        iounmap(clk_reg);
 
        dws->num_cs = 16;
-       dws->fifo_len = 40;     /* FIFO has 40 words buffer */
 
 #ifdef CONFIG_SPI_DW_MID_DMA
        dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
index d0d5542efc06db7a74b46a6a7230a4ce65ba53d5..8edcd1b84562109799281fb48867df8ce73ac7b2 100644 (file)
@@ -621,13 +621,13 @@ static void spi_hw_init(struct dw_spi *dws)
        if (!dws->fifo_len) {
                u32 fifo;
 
-               for (fifo = 2; fifo <= 257; fifo++) {
+               for (fifo = 2; fifo <= 256; fifo++) {
                        dw_writew(dws, DW_SPI_TXFLTR, fifo);
                        if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
                                break;
                }
 
-               dws->fifo_len = (fifo == 257) ? 0 : fifo;
+               dws->fifo_len = (fifo == 2) ? 0 : fifo - 1;
                dw_writew(dws, DW_SPI_TXFLTR, 0);
        }
 }
@@ -673,7 +673,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
        if (dws->dma_ops && dws->dma_ops->dma_init) {
                ret = dws->dma_ops->dma_init(dws);
                if (ret) {
-                       dev_warn(&master->dev, "DMA init failed\n");
+                       dev_warn(dev, "DMA init failed\n");
                        dws->dma_inited = 0;
                }
        }
index b410499cddca9f391a0832ff6e6d6189b7ec1c82..aad6683db81b9a0154d12d3fc71fd5d45fb8bfc3 100644 (file)
@@ -341,7 +341,7 @@ static int img_spfi_start_dma(struct spi_master *master,
                default:
                        rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA;
                        rxconf.src_addr_width = 1;
-                       rxconf.src_maxburst = 1;
+                       rxconf.src_maxburst = 4;
                }
                dmaengine_slave_config(spfi->rx_ch, &rxconf);
 
@@ -368,7 +368,7 @@ static int img_spfi_start_dma(struct spi_master *master,
                default:
                        txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA;
                        txconf.dst_addr_width = 1;
-                       txconf.dst_maxburst = 1;
+                       txconf.dst_maxburst = 4;
                        break;
                }
                dmaengine_slave_config(spfi->tx_ch, &txconf);
@@ -390,14 +390,14 @@ static int img_spfi_start_dma(struct spi_master *master,
                dma_async_issue_pending(spfi->rx_ch);
        }
 
+       spfi_start(spfi);
+
        if (xfer->tx_buf) {
                spfi->tx_dma_busy = true;
                dmaengine_submit(txdesc);
                dma_async_issue_pending(spfi->tx_ch);
        }
 
-       spfi_start(spfi);
-
        return 1;
 
 stop_dma:
index 05c623cfb078d6503bd6d501cc1e821f07784d9e..23822e7df6c1c6e1e2caa18ea19cfcb069c3796d 100644 (file)
@@ -546,8 +546,8 @@ static void giveback(struct driver_data *drv_data)
                        cs_deassert(drv_data);
        }
 
-       spi_finalize_current_message(drv_data->master);
        drv_data->cur_chip = NULL;
+       spi_finalize_current_message(drv_data->master);
 }
 
 static void reset_sccr1(struct driver_data *drv_data)
index 239be7cbe5a83ee5e5a037bec810ee3bd24bf382..3ab7a21445fc253406eaf92abb87ce99974ce828 100644 (file)
@@ -82,7 +82,7 @@ struct sh_msiof_spi_priv {
 #define MDR1_SYNCMD_LR  0x30000000 /*   L/R mode */
 #define MDR1_SYNCAC_SHIFT       25 /* Sync Polarity (1 = Active-low) */
 #define MDR1_BITLSB_SHIFT       24 /* MSB/LSB First (1 = LSB first) */
-#define MDR1_FLD_MASK   0x000000c0 /* Frame Sync Signal Interval (0-3) */
+#define MDR1_FLD_MASK   0x0000000c /* Frame Sync Signal Interval (0-3) */
 #define MDR1_FLD_SHIFT           2
 #define MDR1_XXSTP      0x00000001 /* Transmission/Reception Stop on FIFO */
 /* TMDR1 */
@@ -480,6 +480,8 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
        struct device_node      *np = spi->master->dev.of_node;
        struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master);
 
+       pm_runtime_get_sync(&p->pdev->dev);
+
        if (!np) {
                /*
                 * Use spi->controller_data for CS (same strategy as spi_gpio),
@@ -498,6 +500,9 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
        if (spi->cs_gpio >= 0)
                gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
 
+
+       pm_runtime_put_sync(&p->pdev->dev);
+
        return 0;
 }
 
index 1bf891bd321aa2e0d19bb79e2e217376d31f5e09..4f361b77c749a718621c8767ec97663e43a7c87f 100644 (file)
@@ -264,7 +264,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
 
                if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) &&
                    inode->i_sb->s_root != NULL &&
-                   is_root_inode(inode))
+                   !is_root_inode(inode))
                        ll_invalidate_aliases(inode);
 
                iput(inode);
index 930f6010203e96d6aadb3602fea868bf2a1b5bfd..65d610abe06e53fc0ec8cb34ccd367b7492b40f4 100644 (file)
@@ -632,7 +632,7 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
                return 0;
        }
 
-       if (cfio->fault.ft_flags & VM_FAULT_SIGBUS) {
+       if (cfio->fault.ft_flags & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) {
                CDEBUG(D_PAGE, "got addr %p - SIGBUS\n", vmf->virtual_address);
                return -EFAULT;
        }
index 81784c6f7b8872ed7a0b45aaea1ec0124633db17..77d8753f6ba40df0099dee88b05116f1684e6e93 100644 (file)
@@ -1,6 +1,7 @@
 config VIDEO_TLG2300
        tristate "Telegent TLG2300 USB video capture support (Deprecated)"
        depends on VIDEO_DEV && I2C && SND && DVB_CORE
+       depends on MEDIA_USB_SUPPORT
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
        depends on RC_CORE
index 093535c6217b46000007f370fb047ea8ee24919c..120b70d72d79849e79fb52f2c8580cf7bf0538a1 100644 (file)
@@ -85,23 +85,20 @@ static struct nvec_chip *nvec_power_handle;
 static const struct mfd_cell nvec_devices[] = {
        {
                .name = "nvec-kbd",
-               .id = 1,
        },
        {
                .name = "nvec-mouse",
-               .id = 1,
        },
        {
                .name = "nvec-power",
-               .id = 1,
+               .id = 0,
        },
        {
                .name = "nvec-power",
-               .id = 2,
+               .id = 1,
        },
        {
                .name = "nvec-paz00",
-               .id = 1,
        },
 };
 
@@ -891,7 +888,7 @@ static int tegra_nvec_probe(struct platform_device *pdev)
                nvec_msg_free(nvec, msg);
        }
 
-       ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
+       ret = mfd_add_devices(nvec->dev, 0, nvec_devices,
                              ARRAY_SIZE(nvec_devices), NULL, 0, NULL);
        if (ret)
                dev_err(nvec->dev, "error adding subdevices\n");
index 86c72ba0a0cd5cc019ef068dcec54886f88e7653..f8c5fc371c4cb4ff0b349e9eb2ff871bc60a0574 100644 (file)
@@ -2177,7 +2177,7 @@ bool BBbVT3253Init(struct vnt_private *priv)
                /* Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted) */
                /*bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28);*/
                /* Select VC1/VC2, CR215 = 0x02->0x06 */
-               bResult &= BBbWriteEmbedded(dwIoBase, 0xd7, 0x06);
+               bResult &= BBbWriteEmbedded(priv, 0xd7, 0x06);
                /* }} */
 
                for (ii = 0; ii < CB_VT3253B0_AGC; ii++)
index c8f739dd346eea7e4fc3287eb2eb5338955a1e46..70f870541f9268b598d78c8bf04792877b635231 100644 (file)
@@ -182,6 +182,14 @@ bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel)
        if (pDevice->byCurrentCh == uConnectionChannel)
                return bResult;
 
+       /* Set VGA to max sensitivity */
+       if (pDevice->bUpdateBBVGA &&
+           pDevice->byBBVGACurrent != pDevice->abyBBVGA[0]) {
+               pDevice->byBBVGACurrent = pDevice->abyBBVGA[0];
+
+               BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent);
+       }
+
        /* clear NAV */
        MACvRegBitsOn(pDevice->PortOffset, MAC_REG_MACCR, MACCR_CLRNAV);
 
index 83e4162c0094c4b2bed6853bc8cfb5636011191a..cd1a277d853b5d4cfa6f6e4156761f5d20558e25 100644 (file)
@@ -1232,7 +1232,7 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        head_td = priv->apCurrTD[dma_idx];
 
-       head_td->m_td1TD1.byTCR = (TCR_EDP|TCR_STP);
+       head_td->m_td1TD1.byTCR = 0;
 
        head_td->pTDInfo->skb = skb;
 
@@ -1257,6 +1257,11 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
 
        priv->bPWBitOn = false;
 
+       /* Set TSR1 & ReqCount in TxDescHead */
+       head_td->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
+       head_td->m_td1TD1.wReqCount =
+                       cpu_to_le16((u16)head_td->pTDInfo->dwReqCount);
+
        head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
 
        if (dma_idx == TYPE_AC0DMA)
@@ -1500,9 +1505,11 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw,
                if (conf->enable_beacon) {
                        vnt_beacon_enable(priv, vif, conf);
 
-                       MACvRegBitsOn(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
+                       MACvRegBitsOn(priv->PortOffset, MAC_REG_TCR,
+                                     TCR_AUTOBCNTX);
                } else {
-                       MACvRegBitsOff(priv, MAC_REG_TCR, TCR_AUTOBCNTX);
+                       MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR,
+                                      TCR_AUTOBCNTX);
                }
        }
 
index 61c39dd7ad013c9e40b784c70414fac62bac908b..b5b0155961f22e08959766d01cea8db241893a7e 100644 (file)
@@ -1204,13 +1204,10 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
 
        ptdCurr = (PSTxDesc)pHeadTD;
 
-       ptdCurr->pTDInfo->dwReqCount = cbReqCount - uPadding;
+       ptdCurr->pTDInfo->dwReqCount = cbReqCount;
        ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
        ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
        ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
-       /* Set TSR1 & ReqCount in TxDescHead */
-       ptdCurr->m_td1TD1.byTCR |= (TCR_STP | TCR_EDP | EDMSDU);
-       ptdCurr->m_td1TD1.wReqCount = cpu_to_le16((unsigned short)(cbReqCount));
 
        return cbHeaderLength;
 }
index 55f6774f706f729b92fb2045abb7f9a33740c2b4..aebde3289c50de6722062dfdea21fa1c549090cd 100644 (file)
@@ -2027,10 +2027,10 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                goto reject;
        }
        if (!strncmp("=All", text_ptr, 4)) {
-               cmd->cmd_flags |= IFC_SENDTARGETS_ALL;
+               cmd->cmd_flags |= ICF_SENDTARGETS_ALL;
        } else if (!strncmp("=iqn.", text_ptr, 5) ||
                   !strncmp("=eui.", text_ptr, 5)) {
-               cmd->cmd_flags |= IFC_SENDTARGETS_SINGLE;
+               cmd->cmd_flags |= ICF_SENDTARGETS_SINGLE;
        } else {
                pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr);
                goto reject;
@@ -3415,10 +3415,10 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
                return -ENOMEM;
        }
        /*
-        * Locate pointer to iqn./eui. string for IFC_SENDTARGETS_SINGLE
+        * Locate pointer to iqn./eui. string for ICF_SENDTARGETS_SINGLE
         * explicit case..
         */
-       if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) {
+       if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE) {
                text_ptr = strchr(text_in, '=');
                if (!text_ptr) {
                        pr_err("Unable to locate '=' string in text_in:"
@@ -3434,7 +3434,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
 
        spin_lock(&tiqn_lock);
        list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) {
-               if ((cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) &&
+               if ((cmd->cmd_flags & ICF_SENDTARGETS_SINGLE) &&
                     strcmp(tiqn->tiqn, text_ptr)) {
                        continue;
                }
@@ -3512,7 +3512,7 @@ eob:
                if (end_of_buf)
                        break;
 
-               if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE)
+               if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE)
                        break;
        }
        spin_unlock(&tiqn_lock);
index 09a522bae222d190ec92e157a42f13d2e361da4a..cbcff38ac9b7d30cf5b21882efeb34bb4fb39641 100644 (file)
@@ -135,8 +135,8 @@ enum cmd_flags_table {
        ICF_CONTIG_MEMORY                       = 0x00000020,
        ICF_ATTACHED_TO_RQUEUE                  = 0x00000040,
        ICF_OOO_CMDSN                           = 0x00000080,
-       IFC_SENDTARGETS_ALL                     = 0x00000100,
-       IFC_SENDTARGETS_SINGLE                  = 0x00000200,
+       ICF_SENDTARGETS_ALL                     = 0x00000100,
+       ICF_SENDTARGETS_SINGLE                  = 0x00000200,
 };
 
 /* struct iscsi_cmd->i_state */
index 7653cfb027a200cbec0dd51c95047708837c7227..58f49ff69b1424bf5feb33ed64eba495d8826851 100644 (file)
@@ -1103,51 +1103,6 @@ int se_dev_set_queue_depth(struct se_device *dev, u32 queue_depth)
 }
 EXPORT_SYMBOL(se_dev_set_queue_depth);
 
-int se_dev_set_fabric_max_sectors(struct se_device *dev, u32 fabric_max_sectors)
-{
-       int block_size = dev->dev_attrib.block_size;
-
-       if (dev->export_count) {
-               pr_err("dev[%p]: Unable to change SE Device"
-                       " fabric_max_sectors while export_count is %d\n",
-                       dev, dev->export_count);
-               return -EINVAL;
-       }
-       if (!fabric_max_sectors) {
-               pr_err("dev[%p]: Illegal ZERO value for"
-                       " fabric_max_sectors\n", dev);
-               return -EINVAL;
-       }
-       if (fabric_max_sectors < DA_STATUS_MAX_SECTORS_MIN) {
-               pr_err("dev[%p]: Passed fabric_max_sectors: %u less than"
-                       " DA_STATUS_MAX_SECTORS_MIN: %u\n", dev, fabric_max_sectors,
-                               DA_STATUS_MAX_SECTORS_MIN);
-               return -EINVAL;
-       }
-       if (fabric_max_sectors > DA_STATUS_MAX_SECTORS_MAX) {
-               pr_err("dev[%p]: Passed fabric_max_sectors: %u"
-                       " greater than DA_STATUS_MAX_SECTORS_MAX:"
-                       " %u\n", dev, fabric_max_sectors,
-                       DA_STATUS_MAX_SECTORS_MAX);
-               return -EINVAL;
-       }
-       /*
-        * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
-        */
-       if (!block_size) {
-               block_size = 512;
-               pr_warn("Defaulting to 512 for zero block_size\n");
-       }
-       fabric_max_sectors = se_dev_align_max_sectors(fabric_max_sectors,
-                                                     block_size);
-
-       dev->dev_attrib.fabric_max_sectors = fabric_max_sectors;
-       pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",
-                       dev, fabric_max_sectors);
-       return 0;
-}
-EXPORT_SYMBOL(se_dev_set_fabric_max_sectors);
-
 int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)
 {
        if (dev->export_count) {
@@ -1156,10 +1111,10 @@ int se_dev_set_optimal_sectors(struct se_device *dev, u32 optimal_sectors)
                        dev, dev->export_count);
                return -EINVAL;
        }
-       if (optimal_sectors > dev->dev_attrib.fabric_max_sectors) {
+       if (optimal_sectors > dev->dev_attrib.hw_max_sectors) {
                pr_err("dev[%p]: Passed optimal_sectors %u cannot be"
-                       " greater than fabric_max_sectors: %u\n", dev,
-                       optimal_sectors, dev->dev_attrib.fabric_max_sectors);
+                       " greater than hw_max_sectors: %u\n", dev,
+                       optimal_sectors, dev->dev_attrib.hw_max_sectors);
                return -EINVAL;
        }
 
@@ -1553,8 +1508,6 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        dev->dev_attrib.unmap_granularity_alignment =
                                DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT;
        dev->dev_attrib.max_write_same_len = DA_MAX_WRITE_SAME_LEN;
-       dev->dev_attrib.fabric_max_sectors = DA_FABRIC_MAX_SECTORS;
-       dev->dev_attrib.optimal_sectors = DA_FABRIC_MAX_SECTORS;
 
        xcopy_lun = &dev->xcopy_lun;
        xcopy_lun->lun_se_dev = dev;
@@ -1595,6 +1548,7 @@ int target_configure_device(struct se_device *dev)
        dev->dev_attrib.hw_max_sectors =
                se_dev_align_max_sectors(dev->dev_attrib.hw_max_sectors,
                                         dev->dev_attrib.hw_block_size);
+       dev->dev_attrib.optimal_sectors = dev->dev_attrib.hw_max_sectors;
 
        dev->dev_index = scsi_get_new_index(SCSI_DEVICE_INDEX);
        dev->creation_time = get_jiffies_64();
index c2aea099ea4adf7c0ee60ac7949fa02089162932..d836de200a03bcf24be54004df89c7d6d5039030 100644 (file)
@@ -621,7 +621,16 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
        struct fd_prot fd_prot;
        sense_reason_t rc;
        int ret = 0;
-
+       /*
+        * We are currently limited by the number of iovecs (2048) per
+        * single vfs_[writev,readv] call.
+        */
+       if (cmd->data_length > FD_MAX_BYTES) {
+               pr_err("FILEIO: Not able to process I/O of %u bytes due to"
+                      "FD_MAX_BYTES: %u iovec count limitiation\n",
+                       cmd->data_length, FD_MAX_BYTES);
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+       }
        /*
         * Call vectorized fileio functions to map struct scatterlist
         * physical memory addresses to struct iovec virtual memory.
@@ -959,7 +968,6 @@ static struct configfs_attribute *fileio_backend_dev_attrs[] = {
        &fileio_dev_attrib_hw_block_size.attr,
        &fileio_dev_attrib_block_size.attr,
        &fileio_dev_attrib_hw_max_sectors.attr,
-       &fileio_dev_attrib_fabric_max_sectors.attr,
        &fileio_dev_attrib_optimal_sectors.attr,
        &fileio_dev_attrib_hw_queue_depth.attr,
        &fileio_dev_attrib_queue_depth.attr,
index 3efff94fbd9788838f565218965d180b78a67604..78346b850968ed8da28d88f35cf6a3ac15512a1b 100644 (file)
@@ -124,7 +124,7 @@ static int iblock_configure_device(struct se_device *dev)
        q = bdev_get_queue(bd);
 
        dev->dev_attrib.hw_block_size = bdev_logical_block_size(bd);
-       dev->dev_attrib.hw_max_sectors = UINT_MAX;
+       dev->dev_attrib.hw_max_sectors = queue_max_hw_sectors(q);
        dev->dev_attrib.hw_queue_depth = q->nr_requests;
 
        /*
@@ -883,7 +883,6 @@ static struct configfs_attribute *iblock_backend_dev_attrs[] = {
        &iblock_dev_attrib_hw_block_size.attr,
        &iblock_dev_attrib_block_size.attr,
        &iblock_dev_attrib_hw_max_sectors.attr,
-       &iblock_dev_attrib_fabric_max_sectors.attr,
        &iblock_dev_attrib_optimal_sectors.attr,
        &iblock_dev_attrib_hw_queue_depth.attr,
        &iblock_dev_attrib_queue_depth.attr,
index d56f2aaba9af9a6bb4b89d5c1080d426cba84e63..283cf786ef98be3d0594e847cc9749a072986b80 100644 (file)
@@ -528,6 +528,18 @@ static int core_scsi3_pr_seq_non_holder(
 
                        return 0;
                }
+       } else if (we && registered_nexus) {
+               /*
+                * Reads are allowed for Write Exclusive locks
+                * from all registrants.
+                */
+               if (cmd->data_direction == DMA_FROM_DEVICE) {
+                       pr_debug("Allowing READ CDB: 0x%02x for %s"
+                               " reservation\n", cdb[0],
+                               core_scsi3_pr_dump_type(pr_reg_type));
+
+                       return 0;
+               }
        }
        pr_debug("%s Conflict for %sregistered nexus %s CDB: 0x%2x"
                " for %s reservation\n", transport_dump_cmd_direction(cmd),
index 60ebd170a561943be8bde26cd40112bbd22d1e8e..98e83ac5661bcfe5b3b7b98d6c9fbf21bb27c14e 100644 (file)
@@ -657,7 +657,6 @@ static struct configfs_attribute *rd_mcp_backend_dev_attrs[] = {
        &rd_mcp_dev_attrib_hw_block_size.attr,
        &rd_mcp_dev_attrib_block_size.attr,
        &rd_mcp_dev_attrib_hw_max_sectors.attr,
-       &rd_mcp_dev_attrib_fabric_max_sectors.attr,
        &rd_mcp_dev_attrib_optimal_sectors.attr,
        &rd_mcp_dev_attrib_hw_queue_depth.attr,
        &rd_mcp_dev_attrib_queue_depth.attr,
index 11bea1952435a397172ce69804a1088567bde03f..cd4bed7b27579b14a0f6e517eed23dacb6c1fe02 100644 (file)
@@ -953,21 +953,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 
        if (cmd->se_cmd_flags & SCF_SCSI_DATA_CDB) {
                unsigned long long end_lba;
-
-               if (sectors > dev->dev_attrib.fabric_max_sectors) {
-                       printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
-                               " big sectors %u exceeds fabric_max_sectors:"
-                               " %u\n", cdb[0], sectors,
-                               dev->dev_attrib.fabric_max_sectors);
-                       return TCM_INVALID_CDB_FIELD;
-               }
-               if (sectors > dev->dev_attrib.hw_max_sectors) {
-                       printk_ratelimited(KERN_ERR "SCSI OP %02xh with too"
-                               " big sectors %u exceeds backend hw_max_sectors:"
-                               " %u\n", cdb[0], sectors,
-                               dev->dev_attrib.hw_max_sectors);
-                       return TCM_INVALID_CDB_FIELD;
-               }
 check_lba:
                end_lba = dev->transport->get_blocks(dev) + 1;
                if (cmd->t_task_lba + sectors > end_lba) {
index 1307600fe7264cb55234b6b8e88d8cc15878c799..4c71657da56ab3cdc96b5c1f8d784722f10e2c1d 100644 (file)
@@ -505,7 +505,6 @@ static sense_reason_t
 spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
 {
        struct se_device *dev = cmd->se_dev;
-       u32 max_sectors;
        int have_tp = 0;
        int opt, min;
 
@@ -539,9 +538,7 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
        /*
         * Set MAXIMUM TRANSFER LENGTH
         */
-       max_sectors = min(dev->dev_attrib.fabric_max_sectors,
-                         dev->dev_attrib.hw_max_sectors);
-       put_unaligned_be32(max_sectors, &buf[8]);
+       put_unaligned_be32(dev->dev_attrib.hw_max_sectors, &buf[8]);
 
        /*
         * Set OPTIMAL TRANSFER LENGTH
index 8bfa61c9693dbef6fe6267e16a48c566eae6ac4a..1157b559683b1ff437f9eba74626a90f517d0a1e 100644 (file)
@@ -1118,7 +1118,6 @@ static struct configfs_attribute *tcmu_backend_dev_attrs[] = {
        &tcmu_dev_attrib_hw_block_size.attr,
        &tcmu_dev_attrib_block_size.attr,
        &tcmu_dev_attrib_hw_max_sectors.attr,
-       &tcmu_dev_attrib_fabric_max_sectors.attr,
        &tcmu_dev_attrib_optimal_sectors.attr,
        &tcmu_dev_attrib_hw_queue_depth.attr,
        &tcmu_dev_attrib_queue_depth.attr,
index ad09e51ffae4d097109241d9a19b97c97858109b..f65f0d109fc8c015869a78b355478afb153fde5d 100644 (file)
@@ -4,6 +4,8 @@
  *  Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
  *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
  *
+ *  Copyright (C) 2014  Viresh Kumar <viresh.kumar@linaro.org>
+ *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <linux/cpu.h>
 #include <linux/cpu_cooling.h>
 
+/*
+ * Cooling state <-> CPUFreq frequency
+ *
+ * Cooling states are translated to frequencies throughout this driver and this
+ * is the relation between them.
+ *
+ * Highest cooling state corresponds to lowest possible frequency.
+ *
+ * i.e.
+ *     level 0 --> 1st Max Freq
+ *     level 1 --> 2nd Max Freq
+ *     ...
+ */
+
 /**
  * struct cpufreq_cooling_device - data for cooling device with cpufreq
  * @id: unique integer value corresponding to each cpufreq_cooling_device
  *     cooling devices.
  * @cpufreq_val: integer value representing the absolute value of the clipped
  *     frequency.
+ * @max_level: maximum cooling level. One less than total number of valid
+ *     cpufreq frequencies.
  * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
+ * @node: list_head to link all cpufreq_cooling_device together.
  *
- * This structure is required for keeping information of each
- * cpufreq_cooling_device registered. In order to prevent corruption of this a
- * mutex lock cooling_cpufreq_lock is used.
+ * This structure is required for keeping information of each registered
+ * cpufreq_cooling_device.
  */
 struct cpufreq_cooling_device {
        int id;
        struct thermal_cooling_device *cool_dev;
        unsigned int cpufreq_state;
        unsigned int cpufreq_val;
+       unsigned int max_level;
+       unsigned int *freq_table;       /* In descending order */
        struct cpumask allowed_cpus;
        struct list_head node;
 };
 static DEFINE_IDR(cpufreq_idr);
 static DEFINE_MUTEX(cooling_cpufreq_lock);
 
-static unsigned int cpufreq_dev_count;
-
 static LIST_HEAD(cpufreq_dev_list);
 
 /**
@@ -98,120 +116,30 @@ static void release_idr(struct idr *idr, int id)
 /* Below code defines functions to be used for cpufreq as cooling device */
 
 /**
- * is_cpufreq_valid - function to check frequency transitioning capability.
- * @cpu: cpu for which check is needed.
+ * get_level: Find the level for a particular frequency
+ * @cpufreq_dev: cpufreq_dev for which the property is required
+ * @freq: Frequency
  *
- * This function will check the current state of the system if
- * it is capable of changing the frequency for a given @cpu.
- *
- * Return: 0 if the system is not currently capable of changing
- * the frequency of given cpu. !0 in case the frequency is changeable.
+ * Return: level on success, THERMAL_CSTATE_INVALID on error.
  */
-static int is_cpufreq_valid(int cpu)
+static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev,
+                              unsigned int freq)
 {
-       struct cpufreq_policy policy;
-
-       return !cpufreq_get_policy(&policy, cpu);
-}
-
-enum cpufreq_cooling_property {
-       GET_LEVEL,
-       GET_FREQ,
-       GET_MAXL,
-};
-
-/**
- * get_property - fetch a property of interest for a give cpu.
- * @cpu: cpu for which the property is required
- * @input: query parameter
- * @output: query return
- * @property: type of query (frequency, level, max level)
- *
- * This is the common function to
- * 1. get maximum cpu cooling states
- * 2. translate frequency to cooling state
- * 3. translate cooling state to frequency
- * Note that the code may be not in good shape
- * but it is written in this way in order to:
- * a) reduce duplicate code as most of the code can be shared.
- * b) make sure the logic is consistent when translating between
- *    cooling states and frequencies.
- *
- * Return: 0 on success, -EINVAL when invalid parameters are passed.
- */
-static int get_property(unsigned int cpu, unsigned long input,
-                       unsigned int *output,
-                       enum cpufreq_cooling_property property)
-{
-       int i;
-       unsigned long max_level = 0, level = 0;
-       unsigned int freq = CPUFREQ_ENTRY_INVALID;
-       int descend = -1;
-       struct cpufreq_frequency_table *pos, *table =
-                                       cpufreq_frequency_get_table(cpu);
-
-       if (!output)
-               return -EINVAL;
-
-       if (!table)
-               return -EINVAL;
-
-       cpufreq_for_each_valid_entry(pos, table) {
-               /* ignore duplicate entry */
-               if (freq == pos->frequency)
-                       continue;
-
-               /* get the frequency order */
-               if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
-                       descend = freq > pos->frequency;
-
-               freq = pos->frequency;
-               max_level++;
-       }
-
-       /* No valid cpu frequency entry */
-       if (max_level == 0)
-               return -EINVAL;
+       unsigned long level;
 
-       /* max_level is an index, not a counter */
-       max_level--;
+       for (level = 0; level <= cpufreq_dev->max_level; level++) {
+               if (freq == cpufreq_dev->freq_table[level])
+                       return level;
 
-       /* get max level */
-       if (property == GET_MAXL) {
-               *output = (unsigned int)max_level;
-               return 0;
+               if (freq > cpufreq_dev->freq_table[level])
+                       break;
        }
 
-       if (property == GET_FREQ)
-               level = descend ? input : (max_level - input);
-
-       i = 0;
-       cpufreq_for_each_valid_entry(pos, table) {
-               /* ignore duplicate entry */
-               if (freq == pos->frequency)
-                       continue;
-
-               /* now we have a valid frequency entry */
-               freq = pos->frequency;
-
-               if (property == GET_LEVEL && (unsigned int)input == freq) {
-                       /* get level by frequency */
-                       *output = descend ? i : (max_level - i);
-                       return 0;
-               }
-               if (property == GET_FREQ && level == i) {
-                       /* get frequency by level */
-                       *output = freq;
-                       return 0;
-               }
-               i++;
-       }
-
-       return -EINVAL;
+       return THERMAL_CSTATE_INVALID;
 }
 
 /**
- * cpufreq_cooling_get_level - for a give cpu, return the cooling level.
+ * cpufreq_cooling_get_level - for a given cpu, return the cooling level.
  * @cpu: cpu for which the level is required
  * @freq: the frequency of interest
  *
@@ -223,77 +151,21 @@ static int get_property(unsigned int cpu, unsigned long input,
  */
 unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
 {
-       unsigned int val;
-
-       if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL))
-               return THERMAL_CSTATE_INVALID;
-
-       return (unsigned long)val;
-}
-EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
-
-/**
- * get_cpu_frequency - get the absolute value of frequency from level.
- * @cpu: cpu for which frequency is fetched.
- * @level: cooling level
- *
- * This function matches cooling level with frequency. Based on a cooling level
- * of frequency, equals cooling state of cpu cooling device, it will return
- * the corresponding frequency.
- *     e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
- *
- * Return: 0 on error, the corresponding frequency otherwise.
- */
-static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
-{
-       int ret = 0;
-       unsigned int freq;
-
-       ret = get_property(cpu, level, &freq, GET_FREQ);
-       if (ret)
-               return 0;
-
-       return freq;
-}
-
-/**
- * cpufreq_apply_cooling - function to apply frequency clipping.
- * @cpufreq_device: cpufreq_cooling_device pointer containing frequency
- *     clipping data.
- * @cooling_state: value of the cooling state.
- *
- * Function used to make sure the cpufreq layer is aware of current thermal
- * limits. The limits are applied by updating the cpufreq policy.
- *
- * Return: 0 on success, an error code otherwise (-EINVAL in case wrong
- * cooling state).
- */
-static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
-                                unsigned long cooling_state)
-{
-       unsigned int cpuid, clip_freq;
-       struct cpumask *mask = &cpufreq_device->allowed_cpus;
-       unsigned int cpu = cpumask_any(mask);
-
-
-       /* Check if the old cooling action is same as new cooling action */
-       if (cpufreq_device->cpufreq_state == cooling_state)
-               return 0;
-
-       clip_freq = get_cpu_frequency(cpu, cooling_state);
-       if (!clip_freq)
-               return -EINVAL;
-
-       cpufreq_device->cpufreq_state = cooling_state;
-       cpufreq_device->cpufreq_val = clip_freq;
+       struct cpufreq_cooling_device *cpufreq_dev;
 
-       for_each_cpu(cpuid, mask) {
-               if (is_cpufreq_valid(cpuid))
-                       cpufreq_update_policy(cpuid);
+       mutex_lock(&cooling_cpufreq_lock);
+       list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) {
+               if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) {
+                       mutex_unlock(&cooling_cpufreq_lock);
+                       return get_level(cpufreq_dev, freq);
+               }
        }
+       mutex_unlock(&cooling_cpufreq_lock);
 
-       return 0;
+       pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu);
+       return THERMAL_CSTATE_INVALID;
 }
+EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level);
 
 /**
  * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
@@ -323,11 +195,6 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
                                        &cpufreq_dev->allowed_cpus))
                        continue;
 
-               if (!cpufreq_dev->cpufreq_val)
-                       cpufreq_dev->cpufreq_val = get_cpu_frequency(
-                                       cpumask_any(&cpufreq_dev->allowed_cpus),
-                                       cpufreq_dev->cpufreq_state);
-
                max_freq = cpufreq_dev->cpufreq_val;
 
                if (policy->max != max_freq)
@@ -354,19 +221,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
 {
        struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
-       struct cpumask *mask = &cpufreq_device->allowed_cpus;
-       unsigned int cpu;
-       unsigned int count = 0;
-       int ret;
-
-       cpu = cpumask_any(mask);
-
-       ret = get_property(cpu, 0, &count, GET_MAXL);
 
-       if (count > 0)
-               *state = count;
-
-       return ret;
+       *state = cpufreq_device->max_level;
+       return 0;
 }
 
 /**
@@ -403,8 +260,24 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
                                 unsigned long state)
 {
        struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+       unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
+       unsigned int clip_freq;
+
+       /* Request state should be less than max_level */
+       if (WARN_ON(state > cpufreq_device->max_level))
+               return -EINVAL;
+
+       /* Check if the old cooling action is same as new cooling action */
+       if (cpufreq_device->cpufreq_state == state)
+               return 0;
 
-       return cpufreq_apply_cooling(cpufreq_device, state);
+       clip_freq = cpufreq_device->freq_table[state];
+       cpufreq_device->cpufreq_state = state;
+       cpufreq_device->cpufreq_val = clip_freq;
+
+       cpufreq_update_policy(cpu);
+
+       return 0;
 }
 
 /* Bind cpufreq callbacks to thermal cooling device ops */
@@ -419,10 +292,25 @@ static struct notifier_block thermal_cpufreq_notifier_block = {
        .notifier_call = cpufreq_thermal_notifier,
 };
 
+static unsigned int find_next_max(struct cpufreq_frequency_table *table,
+                                 unsigned int prev_max)
+{
+       struct cpufreq_frequency_table *pos;
+       unsigned int max = 0;
+
+       cpufreq_for_each_valid_entry(pos, table) {
+               if (pos->frequency > max && pos->frequency < prev_max)
+                       max = pos->frequency;
+       }
+
+       return max;
+}
+
 /**
  * __cpufreq_cooling_register - helper function to create cpufreq cooling device
  * @np: a valid struct device_node to the cooling device device tree node
  * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
+ * Normally this should be same as cpufreq policy->related_cpus.
  *
  * This interface function registers the cpufreq cooling device with the name
  * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
@@ -437,37 +325,42 @@ __cpufreq_cooling_register(struct device_node *np,
                           const struct cpumask *clip_cpus)
 {
        struct thermal_cooling_device *cool_dev;
-       struct cpufreq_cooling_device *cpufreq_dev = NULL;
-       unsigned int min = 0, max = 0;
+       struct cpufreq_cooling_device *cpufreq_dev;
        char dev_name[THERMAL_NAME_LENGTH];
-       int ret = 0, i;
-       struct cpufreq_policy policy;
+       struct cpufreq_frequency_table *pos, *table;
+       unsigned int freq, i;
+       int ret;
 
-       /* Verify that all the clip cpus have same freq_min, freq_max limit */
-       for_each_cpu(i, clip_cpus) {
-               /* continue if cpufreq policy not found and not return error */
-               if (!cpufreq_get_policy(&policy, i))
-                       continue;
-               if (min == 0 && max == 0) {
-                       min = policy.cpuinfo.min_freq;
-                       max = policy.cpuinfo.max_freq;
-               } else {
-                       if (min != policy.cpuinfo.min_freq ||
-                           max != policy.cpuinfo.max_freq)
-                               return ERR_PTR(-EINVAL);
-               }
+       table = cpufreq_frequency_get_table(cpumask_first(clip_cpus));
+       if (!table) {
+               pr_debug("%s: CPUFreq table not found\n", __func__);
+               return ERR_PTR(-EPROBE_DEFER);
        }
-       cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device),
-                             GFP_KERNEL);
+
+       cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL);
        if (!cpufreq_dev)
                return ERR_PTR(-ENOMEM);
 
+       /* Find max levels */
+       cpufreq_for_each_valid_entry(pos, table)
+               cpufreq_dev->max_level++;
+
+       cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) *
+                                         cpufreq_dev->max_level, GFP_KERNEL);
+       if (!cpufreq_dev->freq_table) {
+               cool_dev = ERR_PTR(-ENOMEM);
+               goto free_cdev;
+       }
+
+       /* max_level is an index, not a counter */
+       cpufreq_dev->max_level--;
+
        cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus);
 
        ret = get_idr(&cpufreq_idr, &cpufreq_dev->id);
        if (ret) {
-               kfree(cpufreq_dev);
-               return ERR_PTR(-EINVAL);
+               cool_dev = ERR_PTR(ret);
+               goto free_table;
        }
 
        snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
@@ -475,24 +368,43 @@ __cpufreq_cooling_register(struct device_node *np,
 
        cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
                                                      &cpufreq_cooling_ops);
-       if (IS_ERR(cool_dev)) {
-               release_idr(&cpufreq_idr, cpufreq_dev->id);
-               kfree(cpufreq_dev);
-               return cool_dev;
+       if (IS_ERR(cool_dev))
+               goto remove_idr;
+
+       /* Fill freq-table in descending order of frequencies */
+       for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) {
+               freq = find_next_max(table, freq);
+               cpufreq_dev->freq_table[i] = freq;
+
+               /* Warn for duplicate entries */
+               if (!freq)
+                       pr_warn("%s: table has duplicate entries\n", __func__);
+               else
+                       pr_debug("%s: freq:%u KHz\n", __func__, freq);
        }
+
+       cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0];
        cpufreq_dev->cool_dev = cool_dev;
-       cpufreq_dev->cpufreq_state = 0;
+
        mutex_lock(&cooling_cpufreq_lock);
 
        /* Register the notifier for first cpufreq cooling device */
-       if (cpufreq_dev_count == 0)
+       if (list_empty(&cpufreq_dev_list))
                cpufreq_register_notifier(&thermal_cpufreq_notifier_block,
                                          CPUFREQ_POLICY_NOTIFIER);
-       cpufreq_dev_count++;
        list_add(&cpufreq_dev->node, &cpufreq_dev_list);
 
        mutex_unlock(&cooling_cpufreq_lock);
 
+       return cool_dev;
+
+remove_idr:
+       release_idr(&cpufreq_idr, cpufreq_dev->id);
+free_table:
+       kfree(cpufreq_dev->freq_table);
+free_cdev:
+       kfree(cpufreq_dev);
+
        return cool_dev;
 }
 
@@ -554,16 +466,16 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
        cpufreq_dev = cdev->devdata;
        mutex_lock(&cooling_cpufreq_lock);
        list_del(&cpufreq_dev->node);
-       cpufreq_dev_count--;
 
        /* Unregister the notifier for the last cpufreq cooling device */
-       if (cpufreq_dev_count == 0)
+       if (list_empty(&cpufreq_dev_list))
                cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
                                            CPUFREQ_POLICY_NOTIFIER);
        mutex_unlock(&cooling_cpufreq_lock);
 
        thermal_cooling_device_unregister(cpufreq_dev->cool_dev);
        release_idr(&cpufreq_idr, cpufreq_dev->id);
+       kfree(cpufreq_dev->freq_table);
        kfree(cpufreq_dev);
 }
 EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister);
index 000d53e934a0600b7570de851dc08510240208d1..607b62c7e6114cc005ccf597e4f0ccb804e0e99b 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/cpu_cooling.h>
-#include <linux/cpufreq.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/of.h>
 static int db8500_cpufreq_cooling_probe(struct platform_device *pdev)
 {
        struct thermal_cooling_device *cdev;
-       struct cpumask mask_val;
-
-       /* make sure cpufreq driver has been initialized */
-       if (!cpufreq_frequency_get_table(0))
-               return -EPROBE_DEFER;
-
-       cpumask_set_cpu(0, &mask_val);
-       cdev = cpufreq_cooling_register(&mask_val);
 
+       cdev = cpufreq_cooling_register(cpu_present_mask);
        if (IS_ERR(cdev)) {
-               dev_err(&pdev->dev, "Failed to register cooling device\n");
-               return PTR_ERR(cdev);
+               int ret = PTR_ERR(cdev);
+
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "Failed to register cooling device %d\n",
+                               ret);
+                               
+               return ret;
        }
 
        platform_set_drvdata(pdev, cdev);
index 88b32f942dcf72839304dc32db3c10ccf681ee73..2ccbc0788353e9488e3f730de80d52ecafaf9082 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <linux/clk.h>
 #include <linux/cpu_cooling.h>
-#include <linux/cpufreq.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -454,15 +453,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
        const struct of_device_id *of_id =
                of_match_device(of_imx_thermal_match, &pdev->dev);
        struct imx_thermal_data *data;
-       struct cpumask clip_cpus;
        struct regmap *map;
        int measure_freq;
        int ret;
 
-       if (!cpufreq_get_current_driver()) {
-               dev_dbg(&pdev->dev, "no cpufreq driver!");
-               return -EPROBE_DEFER;
-       }
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
@@ -516,12 +510,13 @@ static int imx_thermal_probe(struct platform_device *pdev)
        regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
 
-       cpumask_set_cpu(0, &clip_cpus);
-       data->cdev = cpufreq_cooling_register(&clip_cpus);
+       data->cdev = cpufreq_cooling_register(cpu_present_mask);
        if (IS_ERR(data->cdev)) {
                ret = PTR_ERR(data->cdev);
-               dev_err(&pdev->dev,
-                       "failed to register cpufreq cooling device: %d\n", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "failed to register cpufreq cooling device: %d\n",
+                               ret);
                return ret;
        }
 
@@ -613,6 +608,7 @@ static int imx_thermal_suspend(struct device *dev)
        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
        data->mode = THERMAL_DEVICE_DISABLED;
+       clk_disable_unprepare(data->thermal_clk);
 
        return 0;
 }
@@ -622,6 +618,7 @@ static int imx_thermal_resume(struct device *dev)
        struct imx_thermal_data *data = dev_get_drvdata(dev);
        struct regmap *map = data->tempmon;
 
+       clk_prepare_enable(data->thermal_clk);
        /* Enabled thermal sensor after resume */
        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
        regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
index ffe40bffaf1a2e88acf818b4f611ca7a9e57f42f..d4413698a85f9738d226d5f82793e9d3c6f46abe 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_INT340X_THERMAL)  += int3400_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)  += int3402_thermal.o
 obj-$(CONFIG_INT340X_THERMAL)  += int3403_thermal.o
+obj-$(CONFIG_INT340X_THERMAL)  += processor_thermal_device.o
 obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o
index e4e61b3fb11e8b101abbf86cd1b58f0ed5ffb235..2c2ec7666eb182c44c24225609ab9ecd723ea04a 100644 (file)
@@ -82,7 +82,7 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
        struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" };
 
        if (!acpi_has_method(handle, "_TRT"))
-               return 0;
+               return -ENODEV;
 
        status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer);
        if (ACPI_FAILURE(status))
@@ -119,15 +119,11 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
                        continue;
 
                result = acpi_bus_get_device(trt->source, &adev);
-               if (!result)
-                       acpi_create_platform_device(adev);
-               else
+               if (result)
                        pr_warn("Failed to get source ACPI device\n");
 
                result = acpi_bus_get_device(trt->target, &adev);
-               if (!result)
-                       acpi_create_platform_device(adev);
-               else
+               if (result)
                        pr_warn("Failed to get target ACPI device\n");
        }
 
@@ -167,7 +163,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
                sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" };
 
        if (!acpi_has_method(handle, "_ART"))
-               return 0;
+               return -ENODEV;
 
        status = acpi_evaluate_object(handle, "_ART", NULL, &buffer);
        if (ACPI_FAILURE(status))
@@ -206,16 +202,12 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
 
                if (art->source) {
                        result = acpi_bus_get_device(art->source, &adev);
-                       if (!result)
-                               acpi_create_platform_device(adev);
-                       else
+                       if (result)
                                pr_warn("Failed to get source ACPI device\n");
                }
                if (art->target) {
                        result = acpi_bus_get_device(art->target, &adev);
-                       if (!result)
-                               acpi_create_platform_device(adev);
-                       else
+                       if (result)
                                pr_warn("Failed to get source ACPI device\n");
                }
        }
@@ -321,8 +313,8 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
        unsigned long length = 0;
        int count = 0;
        char __user *arg = (void __user *)__arg;
-       struct trt *trts;
-       struct art *arts;
+       struct trt *trts = NULL;
+       struct art *arts = NULL;
 
        switch (cmd) {
        case ACPI_THERMAL_GET_TRT_COUNT:
index dcb306ea14a49008be5df0e3abb521e896d9195e..65a98a97df071cdf343776bc1e959dc9808dbbc4 100644 (file)
@@ -335,7 +335,6 @@ static struct platform_driver int3400_thermal_driver = {
        .remove = int3400_thermal_remove,
        .driver = {
                   .name = "int3400 thermal",
-                  .owner = THIS_MODULE,
                   .acpi_match_table = ACPI_PTR(int3400_thermal_match),
                   },
 };
index a5d08c14ba24a79654fdd1445c90cbcc00db63b9..c5cbc3af3a0539260218492bc5aaa6199d8d5307 100644 (file)
@@ -231,7 +231,6 @@ static struct platform_driver int3402_thermal_driver = {
        .remove = int3402_thermal_remove,
        .driver = {
                   .name = "int3402 thermal",
-                  .owner = THIS_MODULE,
                   .acpi_match_table = int3402_thermal_match,
                   },
 };
index 1bfa6a69e77a15a8d021cb3ed33760b212ba9ce9..0faf500d8a77874d7c1b6c8a1b3e1195fc9e8065 100644 (file)
@@ -301,6 +301,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv)
 {
        struct int3403_sensor *obj = priv->priv;
 
+       acpi_remove_notify_handler(priv->adev->handle,
+                                  ACPI_DEVICE_NOTIFY, int3403_notify);
        thermal_zone_device_unregister(obj->tzone);
        return 0;
 }
@@ -369,6 +371,7 @@ static int int3403_cdev_add(struct int3403_priv *priv)
        p = buf.pointer;
        if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
                printk(KERN_WARNING "Invalid PPSS data\n");
+               kfree(buf.pointer);
                return -EFAULT;
        }
 
@@ -381,6 +384,7 @@ static int int3403_cdev_add(struct int3403_priv *priv)
 
        priv->priv = obj;
 
+       kfree(buf.pointer);
        /* TODO: add ACPI notification support */
 
        return result;
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
new file mode 100644 (file)
index 0000000..0fe5dbb
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * processor_thermal_device.c
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+
+/* Broadwell-U/HSB thermal reporting device */
+#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603
+#define PCI_DEVICE_ID_PROC_HSB_THERMAL 0x0A03
+
+/* Braswell thermal reporting device */
+#define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC
+
+struct power_config {
+       u32     index;
+       u32     min_uw;
+       u32     max_uw;
+       u32     tmin_us;
+       u32     tmax_us;
+       u32     step_uw;
+};
+
+struct proc_thermal_device {
+       struct device *dev;
+       struct acpi_device *adev;
+       struct power_config power_limits[2];
+};
+
+enum proc_thermal_emum_mode_type {
+       PROC_THERMAL_NONE,
+       PROC_THERMAL_PCI,
+       PROC_THERMAL_PLATFORM_DEV
+};
+
+/*
+ * We can have only one type of enumeration, PCI or Platform,
+ * not both. So we don't need instance specific data.
+ */
+static enum proc_thermal_emum_mode_type proc_thermal_emum_mode =
+                                                       PROC_THERMAL_NONE;
+
+#define POWER_LIMIT_SHOW(index, suffix) \
+static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
+                                       struct device_attribute *attr, \
+                                       char *buf) \
+{ \
+       struct pci_dev *pci_dev; \
+       struct platform_device *pdev; \
+       struct proc_thermal_device *proc_dev; \
+\
+       if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { \
+               pdev = to_platform_device(dev); \
+               proc_dev = platform_get_drvdata(pdev); \
+       } else { \
+               pci_dev = to_pci_dev(dev); \
+               proc_dev = pci_get_drvdata(pci_dev); \
+       } \
+       return sprintf(buf, "%lu\n",\
+       (unsigned long)proc_dev->power_limits[index].suffix * 1000); \
+}
+
+POWER_LIMIT_SHOW(0, min_uw)
+POWER_LIMIT_SHOW(0, max_uw)
+POWER_LIMIT_SHOW(0, step_uw)
+POWER_LIMIT_SHOW(0, tmin_us)
+POWER_LIMIT_SHOW(0, tmax_us)
+
+POWER_LIMIT_SHOW(1, min_uw)
+POWER_LIMIT_SHOW(1, max_uw)
+POWER_LIMIT_SHOW(1, step_uw)
+POWER_LIMIT_SHOW(1, tmin_us)
+POWER_LIMIT_SHOW(1, tmax_us)
+
+static DEVICE_ATTR_RO(power_limit_0_min_uw);
+static DEVICE_ATTR_RO(power_limit_0_max_uw);
+static DEVICE_ATTR_RO(power_limit_0_step_uw);
+static DEVICE_ATTR_RO(power_limit_0_tmin_us);
+static DEVICE_ATTR_RO(power_limit_0_tmax_us);
+
+static DEVICE_ATTR_RO(power_limit_1_min_uw);
+static DEVICE_ATTR_RO(power_limit_1_max_uw);
+static DEVICE_ATTR_RO(power_limit_1_step_uw);
+static DEVICE_ATTR_RO(power_limit_1_tmin_us);
+static DEVICE_ATTR_RO(power_limit_1_tmax_us);
+
+static struct attribute *power_limit_attrs[] = {
+       &dev_attr_power_limit_0_min_uw.attr,
+       &dev_attr_power_limit_1_min_uw.attr,
+       &dev_attr_power_limit_0_max_uw.attr,
+       &dev_attr_power_limit_1_max_uw.attr,
+       &dev_attr_power_limit_0_step_uw.attr,
+       &dev_attr_power_limit_1_step_uw.attr,
+       &dev_attr_power_limit_0_tmin_us.attr,
+       &dev_attr_power_limit_1_tmin_us.attr,
+       &dev_attr_power_limit_0_tmax_us.attr,
+       &dev_attr_power_limit_1_tmax_us.attr,
+       NULL
+};
+
+static struct attribute_group power_limit_attribute_group = {
+       .attrs = power_limit_attrs,
+       .name = "power_limits"
+};
+
+static int proc_thermal_add(struct device *dev,
+                           struct proc_thermal_device **priv)
+{
+       struct proc_thermal_device *proc_priv;
+       struct acpi_device *adev;
+       acpi_status status;
+       struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *elements, *ppcc;
+       union acpi_object *p;
+       int i;
+       int ret;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               return -ENODEV;
+
+       status = acpi_evaluate_object(adev->handle, "PPCC", NULL, &buf);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       p = buf.pointer;
+       if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
+               dev_err(dev, "Invalid PPCC data\n");
+               ret = -EFAULT;
+               goto free_buffer;
+       }
+       if (!p->package.count) {
+               dev_err(dev, "Invalid PPCC package size\n");
+               ret = -EFAULT;
+               goto free_buffer;
+       }
+
+       proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL);
+       if (!proc_priv) {
+               ret = -ENOMEM;
+               goto free_buffer;
+       }
+
+       proc_priv->dev = dev;
+       proc_priv->adev = adev;
+
+       for (i = 0; i < min((int)p->package.count - 1, 2); ++i) {
+               elements = &(p->package.elements[i+1]);
+               if (elements->type != ACPI_TYPE_PACKAGE ||
+                   elements->package.count != 6) {
+                       ret = -EFAULT;
+                       goto free_buffer;
+               }
+               ppcc = elements->package.elements;
+               proc_priv->power_limits[i].index = ppcc[0].integer.value;
+               proc_priv->power_limits[i].min_uw = ppcc[1].integer.value;
+               proc_priv->power_limits[i].max_uw = ppcc[2].integer.value;
+               proc_priv->power_limits[i].tmin_us = ppcc[3].integer.value;
+               proc_priv->power_limits[i].tmax_us = ppcc[4].integer.value;
+               proc_priv->power_limits[i].step_uw = ppcc[5].integer.value;
+       }
+
+       *priv = proc_priv;
+
+       ret = sysfs_create_group(&dev->kobj,
+                                &power_limit_attribute_group);
+
+free_buffer:
+       kfree(buf.pointer);
+
+       return ret;
+}
+
+void proc_thermal_remove(struct proc_thermal_device *proc_priv)
+{
+       sysfs_remove_group(&proc_priv->dev->kobj,
+                          &power_limit_attribute_group);
+}
+
+static int int3401_add(struct platform_device *pdev)
+{
+       struct proc_thermal_device *proc_priv;
+       int ret;
+
+       if (proc_thermal_emum_mode == PROC_THERMAL_PCI) {
+               dev_err(&pdev->dev, "error: enumerated as PCI dev\n");
+               return -ENODEV;
+       }
+
+       ret = proc_thermal_add(&pdev->dev, &proc_priv);
+       if (ret)
+               return ret;
+
+       platform_set_drvdata(pdev, proc_priv);
+       proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV;
+
+       return 0;
+}
+
+static int int3401_remove(struct platform_device *pdev)
+{
+       proc_thermal_remove(platform_get_drvdata(pdev));
+
+       return 0;
+}
+
+static int  proc_thermal_pci_probe(struct pci_dev *pdev,
+                                  const struct pci_device_id *unused)
+{
+       struct proc_thermal_device *proc_priv;
+       int ret;
+
+       if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) {
+               dev_err(&pdev->dev, "error: enumerated as platform dev\n");
+               return -ENODEV;
+       }
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "error: could not enable device\n");
+               return ret;
+       }
+
+       ret = proc_thermal_add(&pdev->dev, &proc_priv);
+       if (ret) {
+               pci_disable_device(pdev);
+               return ret;
+       }
+
+       pci_set_drvdata(pdev, proc_priv);
+       proc_thermal_emum_mode = PROC_THERMAL_PCI;
+
+       return 0;
+}
+
+static void  proc_thermal_pci_remove(struct pci_dev *pdev)
+{
+       proc_thermal_remove(pci_get_drvdata(pdev));
+       pci_disable_device(pdev);
+}
+
+static const struct pci_device_id proc_thermal_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)},
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)},
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)},
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids);
+
+static struct pci_driver proc_thermal_pci_driver = {
+       .name           = "proc_thermal",
+       .probe          = proc_thermal_pci_probe,
+       .remove         = proc_thermal_pci_remove,
+       .id_table       = proc_thermal_pci_ids,
+};
+
+static const struct acpi_device_id int3401_device_ids[] = {
+       {"INT3401", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, int3401_device_ids);
+
+static struct platform_driver int3401_driver = {
+       .probe = int3401_add,
+       .remove = int3401_remove,
+       .driver = {
+               .name = "int3401 thermal",
+               .acpi_match_table = int3401_device_ids,
+       },
+};
+
+static int __init proc_thermal_init(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&int3401_driver);
+       if (ret)
+               return ret;
+
+       ret = pci_register_driver(&proc_thermal_pci_driver);
+
+       return ret;
+}
+
+static void __exit proc_thermal_exit(void)
+{
+       platform_driver_unregister(&int3401_driver);
+       pci_unregister_driver(&proc_thermal_pci_driver);
+}
+
+module_init(proc_thermal_init);
+module_exit(proc_thermal_exit);
+
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
+MODULE_LICENSE("GPL v2");
index e98b4249187c3eaec106fc3602fe520fa710c95d..6ceebd659dd400423c0640b1d0911da36b441b74 100644 (file)
@@ -688,6 +688,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = {
        { X86_VENDOR_INTEL, 6, 0x45},
        { X86_VENDOR_INTEL, 6, 0x46},
        { X86_VENDOR_INTEL, 6, 0x4c},
+       { X86_VENDOR_INTEL, 6, 0x56},
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids);
index e145b66df444e65bb5cc4f9d7e7ed4dce7f76435..d717f3dab6f1410fc955daefb0497c2096298b56 100644 (file)
@@ -149,7 +149,7 @@ EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
  *
  * Return: pointer to trip points table, NULL otherwise
  */
-const struct thermal_trip * const
+const struct thermal_trip *
 of_thermal_get_trip_points(struct thermal_zone_device *tz)
 {
        struct __thermal_zone *data = tz->devdata;
index 8803e693fe6868a620b76abda347e0e27645d6d3..2580a4872f90febeb5af00136e16054bb59e4903 100644 (file)
@@ -63,7 +63,7 @@ struct rcar_thermal_priv {
        struct mutex lock;
        struct list_head list;
        int id;
-       int ctemp;
+       u32 ctemp;
 };
 
 #define rcar_thermal_for_each_priv(pos, common)        \
@@ -145,7 +145,7 @@ static int rcar_thermal_update_temp(struct rcar_thermal_priv *priv)
 {
        struct device *dev = rcar_priv_to_dev(priv);
        int i;
-       int ctemp, old, new;
+       u32 ctemp, old, new;
        int ret = -EINVAL;
 
        mutex_lock(&priv->lock);
@@ -372,6 +372,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        int i;
        int ret = -ENODEV;
        int idle = IDLE_INTERVAL;
+       u32 enr_bits = 0;
 
        common = devm_kzalloc(dev, sizeof(*common), GFP_KERNEL);
        if (!common)
@@ -390,7 +391,7 @@ static int rcar_thermal_probe(struct platform_device *pdev)
 
                /*
                 * platform has IRQ support.
-                * Then, drier use common register
+                * Then, driver uses common registers
                 */
 
                ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0,
@@ -408,9 +409,6 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                if (IS_ERR(common->base))
                        return PTR_ERR(common->base);
 
-               /* enable temperature comparation */
-               rcar_thermal_common_write(common, ENR, 0x00030303);
-
                idle = 0; /* polling delay is not needed */
        }
 
@@ -452,8 +450,15 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                        rcar_thermal_irq_enable(priv);
 
                list_move_tail(&priv->list, &common->head);
+
+               /* update ENR bits */
+               enr_bits |= 3 << (i * 8);
        }
 
+       /* enable temperature comparation */
+       if (irq)
+               rcar_thermal_common_write(common, ENR, enr_bits);
+
        platform_set_drvdata(pdev, common);
 
        dev_info(dev, "%d sensor probed\n", i);
index 1bcddfc60e915e9e6f97594671076330af4adb5a..9c6ce548e36312f95ca49f6352cf4999a1ab0fe0 100644 (file)
@@ -677,7 +677,6 @@ static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops,
 static struct platform_driver rockchip_thermal_driver = {
        .driver = {
                .name = "rockchip-thermal",
-               .owner = THIS_MODULE,
                .pm = &rockchip_thermal_pm_ops,
                .of_match_table = of_rockchip_thermal_match,
        },
index f760389a204c673738e933c91ace4e742b735811..c43306ecc0abbb111dc4c6bfdda5201b64ae1738 100644 (file)
@@ -1,6 +1,6 @@
 config EXYNOS_THERMAL
        tristate "Exynos thermal management unit driver"
-       depends on ARCH_HAS_BANDGAP && OF
+       depends on OF
        help
          If you say yes here you get support for the TMU (Thermal Management
          Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
index b6be572704a4c7ff97055f1cb273ff3016399469..6dc3815cc73f514c71d16fab40552609fa12ba6d 100644 (file)
@@ -347,7 +347,6 @@ void exynos_report_trigger(struct thermal_sensor_conf *conf)
 int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
 {
        int ret;
-       struct cpumask mask_val;
        struct exynos_thermal_zone *th_zone;
 
        if (!sensor_conf || !sensor_conf->read_temperature) {
@@ -367,13 +366,14 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
         *       sensor
         */
        if (sensor_conf->cooling_data.freq_clip_count > 0) {
-               cpumask_set_cpu(0, &mask_val);
                th_zone->cool_dev[th_zone->cool_dev_size] =
-                                       cpufreq_cooling_register(&mask_val);
+                               cpufreq_cooling_register(cpu_present_mask);
                if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) {
-                       dev_err(sensor_conf->dev,
-                               "Failed to register cpufreq cooling device\n");
-                       ret = -EINVAL;
+                       ret = PTR_ERR(th_zone->cool_dev[th_zone->cool_dev_size]);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(sensor_conf->dev,
+                                       "Failed to register cpufreq cooling device: %d\n",
+                                       ret);
                        goto err_unregister;
                }
                th_zone->cool_dev_size++;
index d44d91d681d4333055526c28ff461e73ed709d0c..d2f1e62a42328095a35efb25ca461875e9f87c9f 100644 (file)
@@ -927,7 +927,10 @@ static int exynos_tmu_probe(struct platform_device *pdev)
        /* Register the sensor with thermal management interface */
        ret = exynos_register_thermal(sensor_conf);
        if (ret) {
-               dev_err(&pdev->dev, "Failed to register thermal interface\n");
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev,
+                               "Failed to register thermal interface: %d\n",
+                               ret);
                goto err_clk;
        }
        data->reg_conf = sensor_conf;
index 84fdf0792e27cf57c979288a6a9b79543628495f..87e0b0782023cb37696a92150d9f0c10bd09b198 100644 (file)
@@ -930,7 +930,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        struct thermal_zone_device *pos1;
        struct thermal_cooling_device *pos2;
        unsigned long max_state;
-       int result;
+       int result, ret;
 
        if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
                return -EINVAL;
@@ -947,7 +947,9 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        if (tz != pos1 || cdev != pos2)
                return -EINVAL;
 
-       cdev->ops->get_max_state(cdev, &max_state);
+       ret = cdev->ops->get_max_state(cdev, &max_state);
+       if (ret)
+               return ret;
 
        /* lower default 0, upper default max_state */
        lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
index 9083e75206236c1953e4ad5d7858fbc5f164fad0..0531c752fbbb6680c40e939ad2a14fdc1830f357 100644 (file)
@@ -91,7 +91,7 @@ int of_parse_thermal_zones(void);
 void of_thermal_destroy_zones(void);
 int of_thermal_get_ntrips(struct thermal_zone_device *);
 bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
-const struct thermal_trip * const
+const struct thermal_trip *
 of_thermal_get_trip_points(struct thermal_zone_device *);
 #else
 static inline int of_parse_thermal_zones(void) { return 0; }
@@ -105,7 +105,7 @@ static inline bool of_thermal_is_trip_valid(struct thermal_zone_device *tz,
 {
        return 0;
 }
-static inline const struct thermal_trip * const
+static inline const struct thermal_trip *
 of_thermal_get_trip_points(struct thermal_zone_device *tz)
 {
        return NULL;
index 5fd03865e396e373d20e3c8e2dd54c79a26955ee..3fb054a10f6a0fde450e29a98ee4cdf90e18f6c7 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/kernel.h>
 #include <linux/workqueue.h>
 #include <linux/thermal.h>
-#include <linux/cpufreq.h>
 #include <linux/cpumask.h>
 #include <linux/cpu_cooling.h>
 #include <linux/of.h>
@@ -407,17 +406,17 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
        if (!data)
                return -EINVAL;
 
-       if (!cpufreq_get_current_driver()) {
-               dev_dbg(bgp->dev, "no cpufreq driver yet\n");
-               return -EPROBE_DEFER;
-       }
-
        /* Register cooling device */
        data->cool_dev = cpufreq_cooling_register(cpu_present_mask);
        if (IS_ERR(data->cool_dev)) {
-               dev_err(bgp->dev,
-                       "Failed to register cpufreq cooling device\n");
-               return PTR_ERR(data->cool_dev);
+               int ret = PTR_ERR(data->cool_dev);
+
+               if (ret != -EPROBE_DEFER)
+                       dev_err(bgp->dev,
+                               "Failed to register cpu cooling device %d\n",
+                               ret);
+
+               return ret;
        }
        ti_bandgap_set_sensor_data(bgp, id, data);
 
index d2b496750d590c1e06d755b0b563f40c30f8d165..4ddfa60c922205513d16ed74a770eefd111fda83 100644 (file)
@@ -2399,17 +2399,12 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 
        poll_wait(file, &tty->read_wait, wait);
        poll_wait(file, &tty->write_wait, wait);
-       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
-               mask |= POLLHUP;
        if (input_available_p(tty, 1))
                mask |= POLLIN | POLLRDNORM;
-       else if (mask & POLLHUP) {
-               tty_flush_to_ldisc(tty);
-               if (input_available_p(tty, 1))
-                       mask |= POLLIN | POLLRDNORM;
-       }
        if (tty->packet && tty->link->ctrl_status)
                mask |= POLLPRI | POLLIN | POLLRDNORM;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               mask |= POLLHUP;
        if (tty_hung_up_p(file))
                mask |= POLLHUP;
        if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
index 31feeb2d0a6688513e1dccf82521f281d9842b03..d1f8dc6aabcbe5bca9b6b6bbfc14e6f3f75e60c5 100644 (file)
@@ -1815,7 +1815,7 @@ pci_wch_ch353_setup(struct serial_private *priv,
 }
 
 static int
-pci_wch_ch382_setup(struct serial_private *priv,
+pci_wch_ch38x_setup(struct serial_private *priv,
                     const struct pciserial_board *board,
                     struct uart_8250_port *port, int idx)
 {
@@ -1880,6 +1880,7 @@ pci_wch_ch382_setup(struct serial_private *priv,
 
 #define PCIE_VENDOR_ID_WCH             0x1c00
 #define PCIE_DEVICE_ID_WCH_CH382_2S1P  0x3250
+#define PCIE_DEVICE_ID_WCH_CH384_4S    0x3470
 
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
@@ -2571,13 +2572,21 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_wch_ch353_setup,
        },
-       /* WCH CH382 2S1P card (16750 clone) */
+       /* WCH CH382 2S1P card (16850 clone) */
        {
                .vendor         = PCIE_VENDOR_ID_WCH,
                .device         = PCIE_DEVICE_ID_WCH_CH382_2S1P,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
-               .setup          = pci_wch_ch382_setup,
+               .setup          = pci_wch_ch38x_setup,
+       },
+       /* WCH CH384 4S card (16850 clone) */
+       {
+               .vendor         = PCIE_VENDOR_ID_WCH,
+               .device         = PCIE_DEVICE_ID_WCH_CH384_4S,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_wch_ch38x_setup,
        },
        /*
         * ASIX devices with FIFO bug
@@ -2876,6 +2885,7 @@ enum pci_board_num_t {
        pbn_fintek_4,
        pbn_fintek_8,
        pbn_fintek_12,
+       pbn_wch384_4,
 };
 
 /*
@@ -3675,6 +3685,14 @@ static struct pciserial_board pci_boards[] = {
                .base_baud      = 115200,
                .first_offset   = 0x40,
        },
+
+       [pbn_wch384_4] = {
+               .flags          = FL_BASE0,
+               .num_ports      = 4,
+               .base_baud      = 115200,
+               .uart_offset    = 8,
+               .first_offset   = 0xC0,
+       },
 };
 
 static const struct pci_device_id blacklist[] = {
@@ -3687,6 +3705,7 @@ static const struct pci_device_id blacklist[] = {
        { PCI_DEVICE(0x4348, 0x7053), }, /* WCH CH353 2S1P */
        { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */
        { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */
+       { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */
 };
 
 /*
@@ -5400,6 +5419,10 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID,
                0, 0, pbn_b0_bt_2_115200 },
 
+       {       PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0, pbn_wch384_4 },
+
        /*
         * Commtech, Inc. Fastcom adapters
         */
index 19273e31d22426071cc445e0c76655cc6394dbb2..107e807225752623c7f8cae56b17f00d4d003d37 100644 (file)
@@ -1757,32 +1757,43 @@ static struct s3c24xx_serial_drv_data s5pv210_serial_drv_data = {
 #endif
 
 #if defined(CONFIG_ARCH_EXYNOS)
+#define EXYNOS_COMMON_SERIAL_DRV_DATA                          \
+       .info = &(struct s3c24xx_uart_info) {                   \
+               .name           = "Samsung Exynos UART",        \
+               .type           = PORT_S3C6400,                 \
+               .has_divslot    = 1,                            \
+               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,        \
+               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,       \
+               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,        \
+               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,        \
+               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,        \
+               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,       \
+               .def_clk_sel    = S3C2410_UCON_CLKSEL0,         \
+               .num_clks       = 1,                            \
+               .clksel_mask    = 0,                            \
+               .clksel_shift   = 0,                            \
+       },                                                      \
+       .def_cfg = &(struct s3c2410_uartcfg) {                  \
+               .ucon           = S5PV210_UCON_DEFAULT,         \
+               .ufcon          = S5PV210_UFCON_DEFAULT,        \
+               .has_fracval    = 1,                            \
+       }                                                       \
+
 static struct s3c24xx_serial_drv_data exynos4210_serial_drv_data = {
-       .info = &(struct s3c24xx_uart_info) {
-               .name           = "Samsung Exynos4 UART",
-               .type           = PORT_S3C6400,
-               .has_divslot    = 1,
-               .rx_fifomask    = S5PV210_UFSTAT_RXMASK,
-               .rx_fifoshift   = S5PV210_UFSTAT_RXSHIFT,
-               .rx_fifofull    = S5PV210_UFSTAT_RXFULL,
-               .tx_fifofull    = S5PV210_UFSTAT_TXFULL,
-               .tx_fifomask    = S5PV210_UFSTAT_TXMASK,
-               .tx_fifoshift   = S5PV210_UFSTAT_TXSHIFT,
-               .def_clk_sel    = S3C2410_UCON_CLKSEL0,
-               .num_clks       = 1,
-               .clksel_mask    = 0,
-               .clksel_shift   = 0,
-       },
-       .def_cfg = &(struct s3c2410_uartcfg) {
-               .ucon           = S5PV210_UCON_DEFAULT,
-               .ufcon          = S5PV210_UFCON_DEFAULT,
-               .has_fracval    = 1,
-       },
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
        .fifosize = { 256, 64, 16, 16 },
 };
+
+static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = {
+       EXYNOS_COMMON_SERIAL_DRV_DATA,
+       .fifosize = { 64, 256, 16, 256 },
+};
+
 #define EXYNOS4210_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos4210_serial_drv_data)
+#define EXYNOS5433_SERIAL_DRV_DATA ((kernel_ulong_t)&exynos5433_serial_drv_data)
 #else
 #define EXYNOS4210_SERIAL_DRV_DATA (kernel_ulong_t)NULL
+#define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL
 #endif
 
 static struct platform_device_id s3c24xx_serial_driver_ids[] = {
@@ -1804,6 +1815,9 @@ static struct platform_device_id s3c24xx_serial_driver_ids[] = {
        }, {
                .name           = "exynos4210-uart",
                .driver_data    = EXYNOS4210_SERIAL_DRV_DATA,
+       }, {
+               .name           = "exynos5433-uart",
+               .driver_data    = EXYNOS5433_SERIAL_DRV_DATA,
        },
        { },
 };
@@ -1823,6 +1837,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
                .data = (void *)S5PV210_SERIAL_DRV_DATA },
        { .compatible = "samsung,exynos4210-uart",
                .data = (void *)EXYNOS4210_SERIAL_DRV_DATA },
+       { .compatible = "samsung,exynos5433-uart",
+               .data = (void *)EXYNOS5433_SERIAL_DRV_DATA },
        {},
 };
 MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
index 57ca61b14670f1a540c3f82a24328a390edcfb3c..984605bb5bf1d593087bfffe485323538144b2c5 100644 (file)
@@ -2164,7 +2164,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
                break;
        }
 
-       dev_info(port->dev, "%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
+       printk(KERN_INFO "%s%s%s%d at %s (irq = %d, base_baud = %d) is a %s\n",
+              port->dev ? dev_name(port->dev) : "",
+              port->dev ? ": " : "",
               drv->dev_name,
               drv->tty_driver->name_base + port->line,
               address, port->irq, port->uartclk / 16, uart_type(port));
index 4f35b43e24759c5ab2ae5bcfd7a0fd49672ed3d8..51f066aa375e64789e03b9a527679e3a0a7e1c8d 100644 (file)
@@ -1464,6 +1464,9 @@ static int tty_reopen(struct tty_struct *tty)
            driver->subtype == PTY_TYPE_MASTER)
                return -EIO;
 
+       if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
+               return -EBUSY;
+
        tty->count++;
 
        WARN_ON(!tty->ldisc);
@@ -2106,10 +2109,6 @@ retry_open:
                retval = -ENODEV;
        filp->f_flags = saved_flags;
 
-       if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
-                                               !capable(CAP_SYS_ADMIN))
-               retval = -EBUSY;
-
        if (retval) {
 #ifdef TTY_DEBUG_HANGUP
                printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
index 5b9825a4538a67740a3ccf0d1ceea28d08f5d5c5..a57dc8866fc5ff938641686f7945916074723fe8 100644 (file)
@@ -669,7 +669,6 @@ static int ci_hdrc_probe(struct platform_device *pdev)
        if (!ci)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, ci);
        ci->dev = dev;
        ci->platdata = dev_get_platdata(dev);
        ci->imx28_write_fix = !!(ci->platdata->flags &
@@ -783,6 +782,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
                }
        }
 
+       platform_set_drvdata(pdev, ci);
        ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
                        ci->platdata->name, ci);
        if (ret)
index c1694cff1eafd287c600435a45c861a4406e6514..48731d0bab357a75232fdbd7b4063fe29af3ad4e 100644 (file)
@@ -91,6 +91,7 @@ static int host_start(struct ci_hdrc *ci)
        if (!hcd)
                return -ENOMEM;
 
+       dev_set_drvdata(ci->dev, ci);
        hcd->rsrc_start = ci->hw_bank.phys;
        hcd->rsrc_len = ci->hw_bank.size;
        hcd->regs = ci->hw_bank.abs;
index de0c9c9d7091903af17a388a99ac7da963374a21..a6315abe7b7cec272f28265157f1e65a24f71ddb 100644 (file)
@@ -55,6 +55,11 @@ static int is_targeted(struct usb_device *dev)
             le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
                return 0;
 
+       /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+       if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+            le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+               return 1;
+
        /* NOTE: can't use usb_match_id() since interface caches
         * aren't set up yet. this is cut/paste from that code.
         */
index 0ffb4ed0a9451af2465beed78e0e30e560299f06..41e510ae8c837ea337135c4ec8ddbe26fccac275 100644 (file)
@@ -179,6 +179,10 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x0b05, 0x17e0), .driver_info =
                        USB_QUIRK_IGNORE_REMOTE_WAKEUP },
 
+       /* Protocol and OTG Electrical Test Device */
+       { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
+                       USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+
        { }  /* terminating entry must be last */
 };
 
index ad43c5bc1ef19eadfc074f42690183fcbcf37cef..02e3e2d4ea5658c0ddd6de8b1cb1729425a3c0ab 100644 (file)
@@ -476,13 +476,13 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
        u32 gintsts;
        irqreturn_t retval = IRQ_NONE;
 
+       spin_lock(&hsotg->lock);
+
        if (!dwc2_is_controller_alive(hsotg)) {
                dev_warn(hsotg->dev, "Controller is dead\n");
                goto out;
        }
 
-       spin_lock(&hsotg->lock);
-
        gintsts = dwc2_read_common_intr(hsotg);
        if (gintsts & ~GINTSTS_PRTINT)
                retval = IRQ_HANDLED;
@@ -515,8 +515,8 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
                }
        }
 
-       spin_unlock(&hsotg->lock);
 out:
+       spin_unlock(&hsotg->lock);
        return retval;
 }
 EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
index 200168ec2d7567e63ce9b8a8fa4afb0009b85831..79242008085bbed84a9e7caf142077215d89aab7 100644 (file)
@@ -2567,7 +2567,7 @@ error:
  * s3c_hsotg_ep_disable - disable given endpoint
  * @ep: The endpoint to disable.
  */
-static int s3c_hsotg_ep_disable(struct usb_ep *ep)
+static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
 {
        struct s3c_hsotg_ep *hs_ep = our_ep(ep);
        struct dwc2_hsotg *hsotg = hs_ep->parent;
@@ -2588,7 +2588,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
 
        spin_lock_irqsave(&hsotg->lock, flags);
        /* terminate all requests with shutdown */
-       kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);
+       kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, force);
 
        hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
        hs_ep->fifo_index = 0;
@@ -2609,6 +2609,10 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
        return 0;
 }
 
+static int s3c_hsotg_ep_disable(struct usb_ep *ep)
+{
+       return s3c_hsotg_ep_disable_force(ep, false);
+}
 /**
  * on_list - check request is on the given endpoint
  * @ep: The endpoint to check.
@@ -2924,7 +2928,7 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget)
 
        /* all endpoints should be shutdown */
        for (ep = 1; ep < hsotg->num_of_eps; ep++)
-               s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
+               s3c_hsotg_ep_disable_force(&hsotg->eps[ep].ep, true);
 
        spin_lock_irqsave(&hsotg->lock, flags);
 
index 7c4faf738747bdab2bf5a73e39297f8ae437aeb7..b642a2f998f9eaf8079b36e1b22612042e353288 100644 (file)
@@ -33,6 +33,8 @@
 #define PCI_DEVICE_ID_INTEL_BYT                0x0f37
 #define PCI_DEVICE_ID_INTEL_MRFLD      0x119e
 #define PCI_DEVICE_ID_INTEL_BSW                0x22B7
+#define PCI_DEVICE_ID_INTEL_SPTLP      0x9d30
+#define PCI_DEVICE_ID_INTEL_SPTH       0xa130
 
 struct dwc3_pci {
        struct device           *dev;
@@ -219,6 +221,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
        {  }    /* Terminating Entry */
 };
index f03b136ecfce33b3b6936314d1fdebabb4ce936d..8f65ab3a3b928f3872dcc42b1ddfef38d4ba5d26 100644 (file)
@@ -882,8 +882,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 
                                if (i == (request->num_mapped_sgs - 1) ||
                                                sg_is_last(s)) {
-                                       if (list_is_last(&req->list,
-                                                       &dep->request_list))
+                                       if (list_empty(&dep->request_list))
                                                last_one = true;
                                        chain = false;
                                }
@@ -901,6 +900,9 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
                                if (last_one)
                                        break;
                        }
+
+                       if (last_one)
+                               break;
                } else {
                        dma = req->request.dma;
                        length = req->request.length;
index 6e04e302dc3a85b0dba95cc90c12e97323fa635c..a1bc3e3a0b09f740342e949024db337e030e9ed9 100644 (file)
@@ -399,8 +399,9 @@ static int hidg_setup(struct usb_function *f,
        value   = __le16_to_cpu(ctrl->wValue);
        length  = __le16_to_cpu(ctrl->wLength);
 
-       VDBG(cdev, "hid_setup crtl_request : bRequestType:0x%x bRequest:0x%x "
-               "Value:0x%x\n", ctrl->bRequestType, ctrl->bRequest, value);
+       VDBG(cdev,
+            "%s crtl_request : bRequestType:0x%x bRequest:0x%x Value:0x%x\n",
+            __func__, ctrl->bRequestType, ctrl->bRequest, value);
 
        switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
        case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8
index a90440300735fecaa9502c0234e7abbb81db860b..259b656c0b3ec7bde9e119488f46ded351bb7300 100644 (file)
@@ -520,7 +520,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
                req = midi_alloc_ep_req(ep, midi->buflen);
 
        if (!req) {
-               ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n");
+               ERROR(midi, "%s: alloc_ep_request failed\n", __func__);
                return;
        }
        req->length = 0;
index f7b20329320583d05c096882d8e04cec7d905097..e9715845f82e1dc825690c05f8cc08c2d8e41df7 100644 (file)
@@ -897,7 +897,6 @@ static void f_audio_free_inst(struct usb_function_instance *f)
        struct f_uac1_opts *opts;
 
        opts = container_of(f, struct f_uac1_opts, func_inst);
-       gaudio_cleanup(opts->card);
        if (opts->fn_play_alloc)
                kfree(opts->fn_play);
        if (opts->fn_cap_alloc)
@@ -935,6 +934,7 @@ static void f_audio_free(struct usb_function *f)
        struct f_audio *audio = func_to_audio(f);
        struct f_uac1_opts *opts;
 
+       gaudio_cleanup(&audio->card);
        opts = container_of(f->fi, struct f_uac1_opts, func_inst);
        kfree(audio);
        mutex_lock(&opts->lock);
index c744e4975d744c4fb710a429ec055616fffd4833..db49ec4c748e9469bd694645c8cfc22df7c829fa 100644 (file)
@@ -441,6 +441,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        kbuf = memdup_user(buf, len);
        if (IS_ERR(kbuf)) {
                value = PTR_ERR(kbuf);
+               kbuf = NULL;
                goto free1;
        }
 
@@ -449,6 +450,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                data->name, len, (int) value);
 free1:
        mutex_unlock(&data->lock);
+       kfree (kbuf);
        return value;
 }
 
index ce882371786b184d7b02f4a451d6c8c1b7a80efa..9f93bed42052cb5c910d5f34218287e58a558c6b 100644 (file)
@@ -716,10 +716,10 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
        req->using_dma = 1;
        req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
                        | USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
-                       | USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+                       | USBA_DMA_END_BUF_EN;
 
-       if (ep->is_in)
-               req->ctrl |= USBA_DMA_END_BUF_EN;
+       if (!ep->is_in)
+               req->ctrl |= USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
 
        /*
         * Add this request to the queue and submit for DMA if
@@ -828,7 +828,7 @@ static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 {
        struct usba_ep *ep = to_usba_ep(_ep);
        struct usba_udc *udc = ep->udc;
-       struct usba_request *req = to_usba_req(_req);
+       struct usba_request *req;
        unsigned long flags;
        u32 status;
 
@@ -837,6 +837,16 @@ static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 
        spin_lock_irqsave(&udc->lock, flags);
 
+       list_for_each_entry(req, &ep->queue, queue) {
+               if (&req->req == _req)
+                       break;
+       }
+
+       if (&req->req != _req) {
+               spin_unlock_irqrestore(&udc->lock, flags);
+               return -EINVAL;
+       }
+
        if (req->using_dma) {
                /*
                 * If this request is currently being transferred,
@@ -1563,7 +1573,6 @@ static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
        if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
                DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
                receive_data(ep);
-               usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
        }
 }
 
index ff67ceac77c410a8f6a9ab27fc63f63afd9dc01b..d4fe8d769bd673c384707fae714944885061911d 100644 (file)
@@ -718,10 +718,11 @@ static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
        struct bdc *bdc;
        int ret = 0;
 
-       bdc = ep->bdc;
        if (!req || !ep || !ep->usb_ep.desc)
                return -EINVAL;
 
+       bdc = ep->bdc;
+
        req->usb_req.actual = 0;
        req->usb_req.status = -EINPROGRESS;
        req->epnum = ep->ep_num;
index e113fd73aeae7148b0cbcd0d424aebb16d84a694..f9a332775c4781e57faf7bd584d5d58cbf5397e3 100644 (file)
@@ -1581,6 +1581,10 @@ iso_stream_schedule (
        else
                next = (now + 2 + 7) & ~0x07;   /* full frame cache */
 
+       /* If needed, initialize last_iso_frame so that this URB will be seen */
+       if (ehci->isoc_count == 0)
+               ehci->last_iso_frame = now >> 3;
+
        /*
         * Use ehci->last_iso_frame as the base.  There can't be any
         * TDs scheduled for earlier than that.
@@ -1600,11 +1604,11 @@ iso_stream_schedule (
         */
        now2 = (now - base) & (mod - 1);
 
-       /* Is the schedule already full? */
+       /* Is the schedule about to wrap around? */
        if (unlikely(!empty && start < period)) {
-               ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n",
+               ehci_dbg(ehci, "request %p would overflow (%u-%u < %u mod %u)\n",
                                urb, stream->next_uframe, base, period, mod);
-               status = -ENOSPC;
+               status = -EFBIG;
                goto fail;
        }
 
@@ -1671,10 +1675,6 @@ iso_stream_schedule (
        urb->start_frame = start & (mod - 1);
        if (!stream->highspeed)
                urb->start_frame >>= 3;
-
-       /* Make sure scan_isoc() sees these */
-       if (ehci->isoc_count == 0)
-               ehci->last_iso_frame = now >> 3;
        return status;
 
  fail:
index 19a9af1b4d749cd577e1215a200679f9a1c8b37d..ff9af29b4e9f6b0ea4bfa1decd8050fcbede061d 100644 (file)
@@ -451,7 +451,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
        u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);
        if (IS_ERR(u_phy)) {
-               err = PTR_ERR(u_phy);
+               err = -EPROBE_DEFER;
                goto cleanup_clk_en;
        }
        hcd->usb_phy = u_phy;
index dd483c13565bb7bbedc561d6e39fccee1477c279..ce636466edb7a390efb346d3b0f511b9d4eb5404 100644 (file)
@@ -567,7 +567,8 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
 {
        void __iomem *base;
        u32 control;
-       u32 fminterval;
+       u32 fminterval = 0;
+       bool no_fminterval = false;
        int cnt;
 
        if (!mmio_resource_enabled(pdev, 0))
@@ -577,6 +578,13 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
        if (base == NULL)
                return;
 
+       /*
+        * ULi M5237 OHCI controller locks the whole system when accessing
+        * the OHCI_FMINTERVAL offset.
+        */
+       if (pdev->vendor == PCI_VENDOR_ID_AL && pdev->device == 0x5237)
+               no_fminterval = true;
+
        control = readl(base + OHCI_CONTROL);
 
 /* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
@@ -615,7 +623,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
        }
 
        /* software reset of the controller, preserving HcFmInterval */
-       fminterval = readl(base + OHCI_FMINTERVAL);
+       if (!no_fminterval)
+               fminterval = readl(base + OHCI_FMINTERVAL);
+
        writel(OHCI_HCR, base + OHCI_CMDSTATUS);
 
        /* reset requires max 10 us delay */
@@ -624,7 +634,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
                        break;
                udelay(1);
        }
-       writel(fminterval, base + OHCI_FMINTERVAL);
+
+       if (!no_fminterval)
+               writel(fminterval, base + OHCI_FMINTERVAL);
 
        /* Now the controller is safely in SUSPEND and nothing can wake it up */
        iounmap(base);
index 142b601f95636fdff622bca8c4fb1a9aef87093b..7f76c8a12f89db425e19c4f3a2a5200de542dbd7 100644 (file)
@@ -82,6 +82,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                                "must be suspended extra slowly",
                                pdev->revision);
                }
+               if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK)
+                       xhci->quirks |= XHCI_BROKEN_STREAMS;
                /* Fresco Logic confirms: all revisions of this chip do not
                 * support MSI, even though some of them claim to in their PCI
                 * capabilities.
index 01fcbb5eb06e7ec3d03bcd81d90941f889c5654a..c50d8d202618521793b37a8bd57d7b343cd757fd 100644 (file)
@@ -3803,6 +3803,15 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
                return -EINVAL;
        }
 
+       if (setup == SETUP_CONTEXT_ONLY) {
+               slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
+               if (GET_SLOT_STATE(le32_to_cpu(slot_ctx->dev_state)) ==
+                   SLOT_STATE_DEFAULT) {
+                       xhci_dbg(xhci, "Slot already in default state\n");
+                       return 0;
+               }
+       }
+
        command = xhci_alloc_command(xhci, false, false, GFP_KERNEL);
        if (!command)
                return -ENOMEM;
index 9d68372dd9aaa01d72b3a192959b3bccc2b2de93..b005010240e5b30df0823d220664f5829855ac81 100644 (file)
@@ -72,6 +72,8 @@ config USB_MUSB_DA8XX
 
 config USB_MUSB_TUSB6010
        tristate "TUSB6010"
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
+       depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
@@ -85,6 +87,7 @@ config USB_MUSB_AM35X
 config USB_MUSB_DSPS
        tristate "TI DSPS platforms"
        select USB_MUSB_AM335X_CHILD
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
        depends on OF_IRQ
 
 config USB_MUSB_BLACKFIN
@@ -93,6 +96,7 @@ config USB_MUSB_BLACKFIN
 
 config USB_MUSB_UX500
        tristate "Ux500 platforms"
+       depends on ARCH_U8500 || COMPILE_TEST
 
 config USB_MUSB_JZ4740
        tristate "JZ4740"
index a441a2de8619e51d5f639e47332f3ec120d2a4f2..1782501456139aeb8f970fa51311a215a909d555 100644 (file)
@@ -63,7 +63,7 @@ static void bfin_writew(void __iomem *addr, unsigned offset, u16 data)
        bfin_write16(addr + offset, data);
 }
 
-static void binf_writel(void __iomem *addr, unsigned offset, u32 data)
+static void bfin_writel(void __iomem *addr, unsigned offset, u32 data)
 {
        bfin_write16(addr + offset, (u16)data);
 }
index f64fd964dc6d544b0fecee86a1fd9bd85993862a..c39a16ad78329194e78135464283dea4e760a4cc 100644 (file)
@@ -628,9 +628,9 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
                ret = of_property_read_string_index(np, "dma-names", i, &str);
                if (ret)
                        goto err;
-               if (!strncmp(str, "tx", 2))
+               if (strstarts(str, "tx"))
                        is_tx = 1;
-               else if (!strncmp(str, "rx", 2))
+               else if (strstarts(str, "rx"))
                        is_tx = 0;
                else {
                        dev_err(dev, "Wrong dmatype %s\n", str);
index ad3701a9738964d5f7846e76ec69a31660badda1..48131aa8472cfef70b19d6a2a72db0a8d6b2db85 100644 (file)
@@ -59,20 +59,12 @@ static const struct musb_register_map musb_regmap[] = {
        { "RxMaxPp",    MUSB_RXMAXP,    16 },
        { "RxCSR",      MUSB_RXCSR,     16 },
        { "RxCount",    MUSB_RXCOUNT,   16 },
-       { "ConfigData", MUSB_CONFIGDATA,8 },
        { "IntrRxE",    MUSB_INTRRXE,   16 },
        { "IntrTxE",    MUSB_INTRTXE,   16 },
        { "IntrUsbE",   MUSB_INTRUSBE,  8 },
        { "DevCtl",     MUSB_DEVCTL,    8 },
-       { "BabbleCtl",  MUSB_BABBLE_CTL,8 },
-       { "TxFIFOsz",   MUSB_TXFIFOSZ,  8 },
-       { "RxFIFOsz",   MUSB_RXFIFOSZ,  8 },
-       { "TxFIFOadd",  MUSB_TXFIFOADD, 16 },
-       { "RxFIFOadd",  MUSB_RXFIFOADD, 16 },
        { "VControl",   0x68,           32 },
        { "HWVers",     0x69,           16 },
-       { "EPInfo",     MUSB_EPINFO,    8 },
-       { "RAMInfo",    MUSB_RAMINFO,   8 },
        { "LinkInfo",   MUSB_LINKINFO,  8 },
        { "VPLen",      MUSB_VPLEN,     8 },
        { "HS_EOF1",    MUSB_HS_EOF1,   8 },
@@ -103,6 +95,16 @@ static const struct musb_register_map musb_regmap[] = {
        { "DMA_CNTLch7",        0x274,  16 },
        { "DMA_ADDRch7",        0x278,  32 },
        { "DMA_COUNTch7",       0x27C,  32 },
+#ifndef CONFIG_BLACKFIN
+       { "ConfigData", MUSB_CONFIGDATA,8 },
+       { "BabbleCtl",  MUSB_BABBLE_CTL,8 },
+       { "TxFIFOsz",   MUSB_TXFIFOSZ,  8 },
+       { "RxFIFOsz",   MUSB_RXFIFOSZ,  8 },
+       { "TxFIFOadd",  MUSB_TXFIFOADD, 16 },
+       { "RxFIFOadd",  MUSB_RXFIFOADD, 16 },
+       { "EPInfo",     MUSB_EPINFO,    8 },
+       { "RAMInfo",    MUSB_RAMINFO,   8 },
+#endif
        {  }    /* Terminating Entry */
 };
 
@@ -197,30 +199,30 @@ static ssize_t musb_test_mode_write(struct file *file,
        if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
                return -EFAULT;
 
-       if (!strncmp(buf, "force host", 9))
+       if (strstarts(buf, "force host"))
                test = MUSB_TEST_FORCE_HOST;
 
-       if (!strncmp(buf, "fifo access", 11))
+       if (strstarts(buf, "fifo access"))
                test = MUSB_TEST_FIFO_ACCESS;
 
-       if (!strncmp(buf, "force full-speed", 15))
+       if (strstarts(buf, "force full-speed"))
                test = MUSB_TEST_FORCE_FS;
 
-       if (!strncmp(buf, "force high-speed", 15))
+       if (strstarts(buf, "force high-speed"))
                test = MUSB_TEST_FORCE_HS;
 
-       if (!strncmp(buf, "test packet", 10)) {
+       if (strstarts(buf, "test packet")) {
                test = MUSB_TEST_PACKET;
                musb_load_testpacket(musb);
        }
 
-       if (!strncmp(buf, "test K", 6))
+       if (strstarts(buf, "test K"))
                test = MUSB_TEST_K;
 
-       if (!strncmp(buf, "test J", 6))
+       if (strstarts(buf, "test J"))
                test = MUSB_TEST_J;
 
-       if (!strncmp(buf, "test SE0 NAK", 12))
+       if (strstarts(buf, "test SE0 NAK"))
                test = MUSB_TEST_SE0_NAK;
 
        musb_writeb(musb->mregs, MUSB_TESTMODE, test);
index 23d474d3d7f466188bcf4cee8c8f974e4274d22f..883a9adfdfff5f0c1643036e0be7d7d22d1e73a8 100644 (file)
@@ -2663,7 +2663,6 @@ void musb_host_cleanup(struct musb *musb)
        if (musb->port_mode == MUSB_PORT_MODE_GADGET)
                return;
        usb_remove_hcd(musb->hcd);
-       musb->hcd = NULL;
 }
 
 void musb_host_free(struct musb *musb)
index 699e38c73d82c2ae76feddfe07f85a54ca76dd73..697a741a0cb1ed36ff336af31d8c3cd7d2fd32a5 100644 (file)
@@ -338,7 +338,6 @@ static void mv_otg_update_inputs(struct mv_otg *mvotg)
 static void mv_otg_update_state(struct mv_otg *mvotg)
 {
        struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
-       struct usb_phy *phy = &mvotg->phy;
        int old_state = mvotg->phy.otg->state;
 
        switch (old_state) {
@@ -858,10 +857,10 @@ static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct mv_otg *mvotg = platform_get_drvdata(pdev);
 
-       if (mvotg->phy.state != OTG_STATE_B_IDLE) {
+       if (mvotg->phy.otg->state != OTG_STATE_B_IDLE) {
                dev_info(&pdev->dev,
                         "OTG state is not B_IDLE, it is %d!\n",
-                        mvotg->phy.state);
+                        mvotg->phy.otg->state);
                return -EAGAIN;
        }
 
index b4066a001ba01573f9546749b7d4978180c48dc5..2f9735b3533891c85dc907d8b1cc95a1e50d2559 100644 (file)
@@ -59,6 +59,9 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
 {
        struct usb_phy  *phy;
 
+       if (!of_device_is_available(node))
+               return ERR_PTR(-ENODEV);
+
        list_for_each_entry(phy, &phy_list, head) {
                if (node != phy->dev->of_node)
                        continue;
@@ -66,7 +69,7 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)
                return phy;
        }
 
-       return ERR_PTR(-ENODEV);
+       return ERR_PTR(-EPROBE_DEFER);
 }
 
 static void devm_usb_phy_release(struct device *dev, void *res)
@@ -190,10 +193,13 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,
        spin_lock_irqsave(&phy_lock, flags);
 
        phy = __of_usb_find_phy(node);
-       if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) {
-               if (!IS_ERR(phy))
-                       phy = ERR_PTR(-EPROBE_DEFER);
+       if (IS_ERR(phy)) {
+               devres_free(ptr);
+               goto err1;
+       }
 
+       if (!try_module_get(phy->dev->driver->owner)) {
+               phy = ERR_PTR(-ENODEV);
                devres_free(ptr);
                goto err1;
        }
index 8d7fc48b1f307efffa1e5ec40a6e3250b852a54c..29fa1c3d0089bee738ed4f54a8b65d4f82dd0c03 100644 (file)
@@ -46,6 +46,8 @@ static struct console usbcons;
  * ------------------------------------------------------------
  */
 
+static const struct tty_operations usb_console_fake_tty_ops = {
+};
 
 /*
  * The parsing of the command line works exactly like the
@@ -137,13 +139,17 @@ static int usb_console_setup(struct console *co, char *options)
                                goto reset_open_count;
                        }
                        kref_init(&tty->kref);
-                       tty_port_tty_set(&port->port, tty);
                        tty->driver = usb_serial_tty_driver;
                        tty->index = co->index;
+                       init_ldsem(&tty->ldisc_sem);
+                       INIT_LIST_HEAD(&tty->tty_files);
+                       kref_get(&tty->driver->kref);
+                       tty->ops = &usb_console_fake_tty_ops;
                        if (tty_init_termios(tty)) {
                                retval = -ENOMEM;
-                               goto free_tty;
+                               goto put_tty;
                        }
+                       tty_port_tty_set(&port->port, tty);
                }
 
                /* only call the device specific open if this
@@ -161,7 +167,7 @@ static int usb_console_setup(struct console *co, char *options)
                        serial->type->set_termios(tty, port, &dummy);
 
                        tty_port_tty_set(&port->port, NULL);
-                       kfree(tty);
+                       tty_kref_put(tty);
                }
                set_bit(ASYNCB_INITIALIZED, &port->port.flags);
        }
@@ -177,8 +183,8 @@ static int usb_console_setup(struct console *co, char *options)
 
  fail:
        tty_port_tty_set(&port->port, NULL);
free_tty:
-       kfree(tty);
put_tty:
+       tty_kref_put(tty);
  reset_open_count:
        port->port.count = 0;
        usb_autopm_put_interface(serial->interface);
index 6c4eb3cf5efd599653641e5d96d20b05610a6ed5..f4c56fc1a9f64dd32fae247c351c1b34e0d6400e 100644 (file)
@@ -120,10 +120,12 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */
        { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */
        { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
-       { USB_DEVICE(0x10C4, 0x8875) }, /* CEL MeshConnect USB Stick */
+       { USB_DEVICE(0x10C4, 0x8856) }, /* CEL EM357 ZigBee USB Stick - LR */
+       { USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */
        { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */
        { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */
+       { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */
        { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
        { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
index 1bd192290b08df0fb697fa91f2517b6756680012..ccf1df7c4b80f3f7a596fa3d1d8904eb64a78db6 100644 (file)
@@ -286,7 +286,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
 
        res = usb_submit_urb(port->read_urbs[index], mem_flags);
        if (res) {
-               if (res != -EPERM) {
+               if (res != -EPERM && res != -ENODEV) {
                        dev_err(&port->dev,
                                        "%s - usb_submit_urb failed: %d\n",
                                        __func__, res);
@@ -373,7 +373,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
                                                        __func__, urb->status);
                return;
        default:
-               dev_err(&port->dev, "%s - nonzero urb status: %d\n",
+               dev_dbg(&port->dev, "%s - nonzero urb status: %d\n",
                                                        __func__, urb->status);
                goto resubmit;
        }
index 077c714f1285171ee3b9e4c418e0df42f60cd42c..e07b15ed58148698d939370ac8bf73b20141669a 100644 (file)
@@ -410,6 +410,8 @@ static void usa26_instat_callback(struct urb *urb)
        }
        port = serial->port[msg->port];
        p_priv = usb_get_serial_port_data(port);
+       if (!p_priv)
+               goto resubmit;
 
        /* Update handshaking pin state information */
        old_dcd_state = p_priv->dcd_state;
@@ -420,7 +422,7 @@ static void usa26_instat_callback(struct urb *urb)
 
        if (old_dcd_state != p_priv->dcd_state)
                tty_port_tty_hangup(&port->port, true);
-
+resubmit:
        /* Resubmit urb so we continue receiving */
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
@@ -527,6 +529,8 @@ static void usa28_instat_callback(struct urb *urb)
        }
        port = serial->port[msg->port];
        p_priv = usb_get_serial_port_data(port);
+       if (!p_priv)
+               goto resubmit;
 
        /* Update handshaking pin state information */
        old_dcd_state = p_priv->dcd_state;
@@ -537,7 +541,7 @@ static void usa28_instat_callback(struct urb *urb)
 
        if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
                tty_port_tty_hangup(&port->port, true);
-
+resubmit:
                /* Resubmit urb so we continue receiving */
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
@@ -607,6 +611,8 @@ static void usa49_instat_callback(struct urb *urb)
        }
        port = serial->port[msg->portNumber];
        p_priv = usb_get_serial_port_data(port);
+       if (!p_priv)
+               goto resubmit;
 
        /* Update handshaking pin state information */
        old_dcd_state = p_priv->dcd_state;
@@ -617,7 +623,7 @@ static void usa49_instat_callback(struct urb *urb)
 
        if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
                tty_port_tty_hangup(&port->port, true);
-
+resubmit:
        /* Resubmit urb so we continue receiving */
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
@@ -855,6 +861,8 @@ static void usa90_instat_callback(struct urb *urb)
 
        port = serial->port[0];
        p_priv = usb_get_serial_port_data(port);
+       if (!p_priv)
+               goto resubmit;
 
        /* Update handshaking pin state information */
        old_dcd_state = p_priv->dcd_state;
@@ -865,7 +873,7 @@ static void usa90_instat_callback(struct urb *urb)
 
        if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
                tty_port_tty_hangup(&port->port, true);
-
+resubmit:
        /* Resubmit urb so we continue receiving */
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
@@ -926,6 +934,8 @@ static void usa67_instat_callback(struct urb *urb)
 
        port = serial->port[msg->port];
        p_priv = usb_get_serial_port_data(port);
+       if (!p_priv)
+               goto resubmit;
 
        /* Update handshaking pin state information */
        old_dcd_state = p_priv->dcd_state;
@@ -934,7 +944,7 @@ static void usa67_instat_callback(struct urb *urb)
 
        if (old_dcd_state != p_priv->dcd_state && old_dcd_state)
                tty_port_tty_hangup(&port->port, true);
-
+resubmit:
        /* Resubmit urb so we continue receiving */
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
index 7a4c21b4f67613f7bf64839b4cf4faf09804355e..efdcee15b52030e455ce3c6e17d401d4a5e2660d 100644 (file)
@@ -234,6 +234,8 @@ static void option_instat_callback(struct urb *urb);
 
 #define QUALCOMM_VENDOR_ID                     0x05C6
 
+#define SIERRA_VENDOR_ID                       0x1199
+
 #define CMOTECH_VENDOR_ID                      0x16d8
 #define CMOTECH_PRODUCT_6001                   0x6001
 #define CMOTECH_PRODUCT_CMU_300                        0x6002
@@ -512,7 +514,7 @@ enum option_blacklist_reason {
                OPTION_BLACKLIST_RESERVED_IF = 2
 };
 
-#define MAX_BL_NUM  8
+#define MAX_BL_NUM  11
 struct option_blacklist_info {
        /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */
        const unsigned long sendsetup;
@@ -601,6 +603,11 @@ static const struct option_blacklist_info telit_le920_blacklist = {
        .reserved = BIT(1) | BIT(5),
 };
 
+static const struct option_blacklist_info sierra_mc73xx_blacklist = {
+       .sendsetup = BIT(0) | BIT(2),
+       .reserved = BIT(8) | BIT(10) | BIT(11),
+};
+
 static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -1098,6 +1105,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */
        { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */
+       { USB_DEVICE_INTERFACE_CLASS(SIERRA_VENDOR_ID, 0x68c0, 0xff),
+         .driver_info = (kernel_ulong_t)&sierra_mc73xx_blacklist }, /* MC73xx */
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
index cb3e14780a7e0c6182e5f9bf3ad505b61fa75684..9c63897b3a564012ea63f99b9e5e73bc48b93d36 100644 (file)
@@ -142,7 +142,6 @@ static const struct usb_device_id id_table[] = {
        {DEVICE_SWI(0x0f3d, 0x68a2)},   /* Sierra Wireless MC7700 */
        {DEVICE_SWI(0x114f, 0x68a2)},   /* Sierra Wireless MC7750 */
        {DEVICE_SWI(0x1199, 0x68a2)},   /* Sierra Wireless MC7710 */
-       {DEVICE_SWI(0x1199, 0x68c0)},   /* Sierra Wireless MC73xx */
        {DEVICE_SWI(0x1199, 0x901c)},   /* Sierra Wireless EM7700 */
        {DEVICE_SWI(0x1199, 0x901f)},   /* Sierra Wireless EM7355 */
        {DEVICE_SWI(0x1199, 0x9040)},   /* Sierra Wireless Modem */
index 8a6f371ed6e77e3ccdc99632c3cd41ebeb155213..9893d696fc973e9e4183b57b56b3ceb22570942f 100644 (file)
@@ -69,16 +69,39 @@ static int uas_use_uas_driver(struct usb_interface *intf,
                return 0;
 
        /*
-        * ASM1051 and older ASM1053 devices have the same usb-id, and UAS is
-        * broken on the ASM1051, use the number of streams to differentiate.
-        * New ASM1053-s also support 32 streams, but have a different prod-id.
+        * ASMedia has a number of usb3 to sata bridge chips, at the time of
+        * this writing the following versions exist:
+        * ASM1051 - no uas support version
+        * ASM1051 - with broken (*) uas support
+        * ASM1053 - with working uas support
+        * ASM1153 - with working uas support
+        *
+        * Devices with these chips re-use a number of device-ids over the
+        * entire line, so the device-id is useless to determine if we're
+        * dealing with an ASM1051 (which we want to avoid).
+        *
+        * The ASM1153 can be identified by config.MaxPower == 0,
+        * where as the ASM105x models have config.MaxPower == 36.
+        *
+        * Differentiating between the ASM1053 and ASM1051 is trickier, when
+        * connected over USB-3 we can look at the number of streams supported,
+        * ASM1051 supports 32 streams, where as early ASM1053 versions support
+        * 16 streams, newer ASM1053-s also support 32 streams, but have a
+        * different prod-id.
+        *
+        * (*) ASM1051 chips do work with UAS with some disks (with the
+        *     US_FL_NO_REPORT_OPCODES quirk), but are broken with other disks
         */
        if (le16_to_cpu(udev->descriptor.idVendor) == 0x174c &&
-                       le16_to_cpu(udev->descriptor.idProduct) == 0x55aa) {
-               if (udev->speed < USB_SPEED_SUPER) {
+                       (le16_to_cpu(udev->descriptor.idProduct) == 0x5106 ||
+                        le16_to_cpu(udev->descriptor.idProduct) == 0x55aa)) {
+               if (udev->actconfig->desc.bMaxPower == 0) {
+                       /* ASM1153, do nothing */
+               } else if (udev->speed < USB_SPEED_SUPER) {
                        /* No streams info, assume ASM1051 */
                        flags |= US_FL_IGNORE_UAS;
                } else if (usb_ss_max_streams(&eps[1]->ss_ep_comp) == 32) {
+                       /* Possibly an ASM1051, disable uas */
                        flags |= US_FL_IGNORE_UAS;
                }
        }
index 11c7a96764415c4c299c77ddd4a2bc7b0b911967..d684b4b8108ff34a5c4023088d9e927dcb378f6b 100644 (file)
@@ -507,7 +507,7 @@ UNUSUAL_DEV(  0x04e6, 0x000c, 0x0100, 0x0100,
 UNUSUAL_DEV(  0x04e6, 0x000f, 0x0000, 0x9999,
                "SCM Microsystems",
                "eUSB SCSI Adapter (Bus Powered)",
-               USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+               USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
                US_FL_SCM_MULT_TARG ),
 
 UNUSUAL_DEV(  0x04e6, 0x0101, 0x0200, 0x0200,
@@ -1995,6 +1995,13 @@ UNUSUAL_DEV(  0x152d, 0x2329, 0x0100, 0x0100,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
 
+/* Reported by Dmitry Nezhevenko <dion@dion.org.ua> */
+UNUSUAL_DEV(  0x152d, 0x2566, 0x0114, 0x0114,
+               "JMicron",
+               "USB to ATA/ATAPI Bridge",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_BROKEN_FUA ),
+
 /* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI)
  * and Mac USB Dock USB-SCSI */
 UNUSUAL_DEV(  0x1645, 0x0007, 0x0100, 0x0133,
index 18a283d6de1c8bd18663b57bbf7499510c49fa2d..dbc00e56c7f5c106a67028e1b6da7dfee2c39e5e 100644 (file)
  * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org>
  */
 
+/*
+ * Apricorn USB3 dongle sometimes returns "USBSUSBSUSBS" in response to SCSI
+ * commands in UAS mode.  Observed with the 1.28 firmware; are there others?
+ */
+UNUSUAL_DEV(0x0984, 0x0301, 0x0128, 0x0128,
+               "Apricorn",
+               "",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_IGNORE_UAS),
+
 /* https://bugzilla.kernel.org/show_bug.cgi?id=79511 */
 UNUSUAL_DEV(0x0bc2, 0x2312, 0x0000, 0x9999,
                "Seagate",
@@ -68,6 +78,20 @@ UNUSUAL_DEV(0x0bc2, 0xa003, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: Marcin ZajÄ…czkowski <mszpak@wp.pl> */
+UNUSUAL_DEV(0x0bc2, 0xa013, 0x0000, 0x9999,
+               "Seagate",
+               "Backup Plus",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
+/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
+UNUSUAL_DEV(0x0bc2, 0xa0a4, 0x0000, 0x9999,
+               "Seagate",
+               "Backup Plus Desk",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
 /* https://bbs.archlinux.org/viewtopic.php?id=183190 */
 UNUSUAL_DEV(0x0bc2, 0xab20, 0x0000, 0x9999,
                "Seagate",
@@ -82,6 +106,13 @@ UNUSUAL_DEV(0x0bc2, 0xab21, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: G. Richard Bellamy <rbellamy@pteradigm.com> */
+UNUSUAL_DEV(0x0bc2, 0xab2a, 0x0000, 0x9999,
+               "Seagate",
+               "BUP Fast HDD",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_ATA_1X),
+
 /* Reported-by: Claudio Bizzarri <claudio.bizzarri@gmail.com> */
 UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
                "JMicron",
@@ -89,14 +120,6 @@ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_REPORT_OPCODES),
 
-/* Most ASM1051 based devices have issues with uas, blacklist them all */
-/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
-UNUSUAL_DEV(0x174c, 0x5106, 0x0000, 0x9999,
-               "ASMedia",
-               "ASM1051",
-               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
-               US_FL_IGNORE_UAS),
-
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
                "VIA",
@@ -104,9 +127,23 @@ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_NO_ATA_1X),
 
+/* Reported-by: Takeo Nakayama <javhera@gmx.com> */
+UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999,
+               "JMicron",
+               "JMS566",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
+
 /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
 UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
                "Hitachi",
                "External HDD",
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_IGNORE_UAS),
+
+/* Reported-by: Richard Henderson <rth@redhat.com> */
+UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999,
+               "SimpleTech",
+               "External HDD",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_NO_REPORT_OPCODES),
index 255201f22126aabd9ea9178fe353cf5f42a82c68..7cc0122a18cecbb7ef45cf8e438112ec2fb4ff00 100644 (file)
@@ -840,13 +840,11 @@ static const struct vfio_device_ops vfio_pci_ops = {
 
 static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       u8 type;
        struct vfio_pci_device *vdev;
        struct iommu_group *group;
        int ret;
 
-       pci_read_config_byte(pdev, PCI_HEADER_TYPE, &type);
-       if ((type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL)
+       if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
                return -EINVAL;
 
        group = iommu_group_get(&pdev->dev);
index 14419a8ccbb6b138aa8bd38b7765166c1f4aa398..d415d69dc2378cbc7568bbcdcc53e601770ee761 100644 (file)
@@ -538,7 +538,7 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
                ++headcount;
                seg += in;
        }
-       heads[headcount - 1].len = cpu_to_vhost32(vq, len - datalen);
+       heads[headcount - 1].len = cpu_to_vhost32(vq, len + datalen);
        *iovcount = seg;
        if (unlikely(log))
                *log_num = nlogs;
index 01c01cb3933fdfc5bce7e9c457d128d2e8f460e4..d695b1673ae532d9ac873bdc5661ccab84995c04 100644 (file)
@@ -911,6 +911,23 @@ vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd,
        return 0;
 }
 
+static int vhost_scsi_to_tcm_attr(int attr)
+{
+       switch (attr) {
+       case VIRTIO_SCSI_S_SIMPLE:
+               return TCM_SIMPLE_TAG;
+       case VIRTIO_SCSI_S_ORDERED:
+               return TCM_ORDERED_TAG;
+       case VIRTIO_SCSI_S_HEAD:
+               return TCM_HEAD_TAG;
+       case VIRTIO_SCSI_S_ACA:
+               return TCM_ACA_TAG;
+       default:
+               break;
+       }
+       return TCM_SIMPLE_TAG;
+}
+
 static void tcm_vhost_submission_work(struct work_struct *work)
 {
        struct tcm_vhost_cmd *cmd =
@@ -936,9 +953,10 @@ static void tcm_vhost_submission_work(struct work_struct *work)
        rc = target_submit_cmd_map_sgls(se_cmd, tv_nexus->tvn_se_sess,
                        cmd->tvc_cdb, &cmd->tvc_sense_buf[0],
                        cmd->tvc_lun, cmd->tvc_exp_data_len,
-                       cmd->tvc_task_attr, cmd->tvc_data_direction,
-                       TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
-                       NULL, 0, sg_prot_ptr, cmd->tvc_prot_sgl_count);
+                       vhost_scsi_to_tcm_attr(cmd->tvc_task_attr),
+                       cmd->tvc_data_direction, TARGET_SCF_ACK_KREF,
+                       sg_ptr, cmd->tvc_sgl_count, NULL, 0, sg_prot_ptr,
+                       cmd->tvc_prot_sgl_count);
        if (rc < 0) {
                transport_send_check_condition_and_sense(se_cmd,
                                TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
index ed71b5347a766ee26c95039638a028ece31b53de..cb807d0ea498df3a197d0c3ed70d5548e57d97b7 100644 (file)
@@ -713,9 +713,13 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
                        r = -EFAULT;
                        break;
                }
-               if ((a.avail_user_addr & (sizeof *vq->avail->ring - 1)) ||
-                   (a.used_user_addr & (sizeof *vq->used->ring - 1)) ||
-                   (a.log_guest_addr & (sizeof *vq->used->ring - 1))) {
+
+               /* Make sure it's safe to cast pointers to vring types. */
+               BUILD_BUG_ON(__alignof__ *vq->avail > VRING_AVAIL_ALIGN_SIZE);
+               BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
+               if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
+                   (a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
+                   (a.log_guest_addr & (sizeof(u64) - 1))) {
                        r = -EINVAL;
                        break;
                }
index 1c29bd19e3d5fe9954153a8b821058a1be5ff6d5..0e5fde1d3ffbe5a152035f33063afa98bf84f33e 100644 (file)
@@ -636,7 +636,7 @@ static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
                err = broadsheet_spiflash_read_range(par, start_sector_addr,
                                                data_start_addr, sector_buffer);
                if (err)
-                       return err;
+                       goto out;
        }
 
        /* now we copy our data into the right place in the sector buffer */
@@ -657,7 +657,7 @@ static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
                err = broadsheet_spiflash_read_range(par, tail_start_addr,
                        tail_len, sector_buffer + tail_start_addr);
                if (err)
-                       return err;
+                       goto out;
        }
 
        /* if we got here we have the full sector that we want to rewrite. */
@@ -665,11 +665,13 @@ static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
        /* first erase the sector */
        err = broadsheet_spiflash_erase_sector(par, start_sector_addr);
        if (err)
-               return err;
+               goto out;
 
        /* now write it */
        err = broadsheet_spiflash_write_sector(par, start_sector_addr,
                                        sector_buffer, sector_size);
+out:
+       kfree(sector_buffer);
        return err;
 }
 
index 900aa4ecd617990c8ce0caf1c46fb2993c8233b5..d6cab1fd9a4795da2fe2348c2882bc3e04a6cf30 100644 (file)
@@ -83,9 +83,10 @@ int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasy
        cancel_delayed_work_sync(&info->deferred_work);
 
        /* Run it immediately */
-       err = schedule_delayed_work(&info->deferred_work, 0);
+       schedule_delayed_work(&info->deferred_work, 0);
        mutex_unlock(&inode->i_mutex);
-       return err;
+
+       return 0;
 }
 EXPORT_SYMBOL_GPL(fb_deferred_io_fsync);
 
index 87accdb59c81b5ed5686ad2c291c636fe541289a..ac83ef5cfd7d7f6a96848d546e3c7155dfdcd148 100644 (file)
@@ -132,7 +132,6 @@ static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
        .mX_max = 127,
        .fint_min = 500000,
        .fint_max = 2500000,
-       .clkdco_max = 1800000000,
 
        .clkdco_min = 500000000,
        .clkdco_low = 1000000000,
@@ -156,7 +155,6 @@ static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
        .mX_max = 127,
        .fint_min = 620000,
        .fint_max = 2500000,
-       .clkdco_max = 1800000000,
 
        .clkdco_min = 750000000,
        .clkdco_low = 1500000000,
index 50bc62c5d367f5586bf5431a16e2b4ec91599ca6..335ffac224b97a57b6abc043b74ae47601e27535 100644 (file)
@@ -97,7 +97,8 @@ int dss_pll_enable(struct dss_pll *pll)
        return 0;
 
 err_enable:
-       regulator_disable(pll->regulator);
+       if (pll->regulator)
+               regulator_disable(pll->regulator);
 err_reg:
        clk_disable_unprepare(pll->clkin);
        return r;
index d51a983075bc57a579664367214637f3aeb3e647..5c2ccab5a958f6d41a68cbab3a48e78e8514cbda 100644 (file)
@@ -342,6 +342,8 @@ static void sdi_init_output(struct platform_device *pdev)
        out->output_type = OMAP_DISPLAY_TYPE_SDI;
        out->name = "sdi.0";
        out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
+       /* We have SDI only on OMAP3, where it's on port 1 */
+       out->port_num = 1;
        out->ops.sdi = &sdi_ops;
        out->owner = THIS_MODULE;
 
index 92cac803dee3c2261655a34a45a6a0c2d170636f..1085c0432158c02038aba6f961ea7e300f7f950b 100644 (file)
@@ -402,7 +402,7 @@ static int __init simplefb_init(void)
        if (ret)
                return ret;
 
-       if (IS_ENABLED(CONFIG_OF) && of_chosen) {
+       if (IS_ENABLED(CONFIG_OF_ADDRESS) && of_chosen) {
                for_each_child_of_node(of_chosen, np) {
                        if (of_device_is_compatible(np, "simple-framebuffer"))
                                of_platform_device_create(np, NULL, NULL);
index 940cd196eef53ab6cc02bf44d2320f610e36685d..10fbfd8ab963f9e78905a5d932b13ae810639363 100644 (file)
@@ -21,6 +21,21 @@ static bool nologo;
 module_param(nologo, bool, 0);
 MODULE_PARM_DESC(nologo, "Disables startup logo");
 
+/*
+ * Logos are located in the initdata, and will be freed in kernel_init.
+ * Use late_init to mark the logos as freed to prevent any further use.
+ */
+
+static bool logos_freed;
+
+static int __init fb_logo_late_init(void)
+{
+       logos_freed = true;
+       return 0;
+}
+
+late_initcall(fb_logo_late_init);
+
 /* logo's are marked __initdata. Use __init_refok to tell
  * modpost that it is intended that this function uses data
  * marked __initdata.
@@ -29,7 +44,7 @@ const struct linux_logo * __init_refok fb_find_logo(int depth)
 {
        const struct linux_logo *logo = NULL;
 
-       if (nologo)
+       if (nologo || logos_freed)
                return NULL;
 
        if (depth >= 1) {
index 2ef9529809d8bd198455a1af19151c22fe4ca715..9756f21b809e080d1d1975b0734cb82cdea6e9e3 100644 (file)
@@ -282,6 +282,7 @@ void vp_del_vqs(struct virtio_device *vdev)
 
        vp_free_vectors(vdev);
        kfree(vp_dev->vqs);
+       vp_dev->vqs = NULL;
 }
 
 static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
@@ -421,15 +422,6 @@ int vp_set_vq_affinity(struct virtqueue *vq, int cpu)
        return 0;
 }
 
-void virtio_pci_release_dev(struct device *_d)
-{
-       /*
-        * No need for a release method as we allocate/free
-        * all devices together with the pci devices.
-        * Provide an empty one to avoid getting a warning from core.
-        */
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int virtio_pci_freeze(struct device *dev)
 {
index adddb647b21d826c76ce54dac8707828c0ba381c..5a497289b7e9c336d1478db41ca5c0f60fbbafb9 100644 (file)
@@ -126,7 +126,6 @@ const char *vp_bus_name(struct virtio_device *vdev);
  * - ignore the affinity request if we're using INTX
  */
 int vp_set_vq_affinity(struct virtqueue *vq, int cpu);
-void virtio_pci_release_dev(struct device *);
 
 int virtio_pci_legacy_probe(struct pci_dev *pci_dev,
                            const struct pci_device_id *id);
index 6c76f0f5658ccfcef86b865b9f9e2fa76334245c..a5486e65e04bd55d5c64a33d3dbeeadb27dd4857 100644 (file)
@@ -211,6 +211,17 @@ static const struct virtio_config_ops virtio_pci_config_ops = {
        .set_vq_affinity = vp_set_vq_affinity,
 };
 
+static void virtio_pci_release_dev(struct device *_d)
+{
+       struct virtio_device *vdev = dev_to_virtio(_d);
+       struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+       /* As struct device is a kobject, it's not safe to
+        * free the memory (including the reference counter itself)
+        * until it's release callback. */
+       kfree(vp_dev);
+}
+
 /* the PCI probing function */
 int virtio_pci_legacy_probe(struct pci_dev *pci_dev,
                            const struct pci_device_id *id)
@@ -302,5 +313,4 @@ void virtio_pci_legacy_remove(struct pci_dev *pci_dev)
        pci_iounmap(pci_dev, vp_dev->ioaddr);
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
-       kfree(vp_dev);
 }
index 5927c0a98a74b29cddac4d7894a71580590b7ff2..bcfd2a22208f34b621faf6922625e9e9fec83832 100644 (file)
@@ -503,7 +503,6 @@ static struct platform_driver cdns_wdt_driver = {
        .shutdown       = cdns_wdt_shutdown,
        .driver         = {
                .name   = "cdns-wdt",
-               .owner  = THIS_MODULE,
                .of_match_table = cdns_wdt_of_match,
                .pm     = &cdns_wdt_pm_ops,
        },
index d6add516a7a7635662e5c1cb12a10206b93c5544..5142bbabe0279f0b36c92c854f7daa407e2e32a5 100644 (file)
@@ -52,6 +52,8 @@
 #define IMX2_WDT_WRSR          0x04            /* Reset Status Register */
 #define IMX2_WDT_WRSR_TOUT     (1 << 1)        /* -> Reset due to Timeout */
 
+#define IMX2_WDT_WMCR          0x08            /* Misc Register */
+
 #define IMX2_WDT_MAX_TIME      128
 #define IMX2_WDT_DEFAULT_TIME  60              /* in seconds */
 
@@ -274,6 +276,13 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
 
        imx2_wdt_ping_if_active(wdog);
 
+       /*
+        * Disable the watchdog power down counter at boot. Otherwise the power
+        * down counter will pull down the #WDOG interrupt line for one clock
+        * cycle.
+        */
+       regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
+
        ret = watchdog_register_device(wdog);
        if (ret) {
                dev_err(&pdev->dev, "cannot register watchdog device\n");
@@ -327,18 +336,21 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM_SLEEP
-/* Disable watchdog if it is active during suspend */
+/* Disable watchdog if it is active or non-active but still running */
 static int imx2_wdt_suspend(struct device *dev)
 {
        struct watchdog_device *wdog = dev_get_drvdata(dev);
        struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-       imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
-       imx2_wdt_ping(wdog);
+       /* The watchdog IP block is running */
+       if (imx2_wdt_is_running(wdev)) {
+               imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+               imx2_wdt_ping(wdog);
 
-       /* Watchdog has been stopped but IP block is still running */
-       if (!watchdog_active(wdog) && imx2_wdt_is_running(wdev))
-               del_timer_sync(&wdev->timer);
+               /* The watchdog is not active */
+               if (!watchdog_active(wdog))
+                       del_timer_sync(&wdev->timer);
+       }
 
        clk_disable_unprepare(wdev->clk);
 
@@ -354,15 +366,25 @@ static int imx2_wdt_resume(struct device *dev)
        clk_prepare_enable(wdev->clk);
 
        if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
-               /* Resumes from deep sleep we need restart
-                * the watchdog again.
+               /*
+                * If the watchdog is still active and resumes
+                * from deep sleep state, need to restart the
+                * watchdog again.
                 */
                imx2_wdt_setup(wdog);
                imx2_wdt_set_timeout(wdog, wdog->timeout);
                imx2_wdt_ping(wdog);
        } else if (imx2_wdt_is_running(wdev)) {
+               /* Resuming from non-deep sleep state. */
+               imx2_wdt_set_timeout(wdog, wdog->timeout);
                imx2_wdt_ping(wdog);
-               mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
+               /*
+                * But the watchdog is not active, then start
+                * the timer again.
+                */
+               if (!watchdog_active(wdog))
+                       mod_timer(&wdev->timer,
+                                 jiffies + wdog->timeout * HZ / 2);
        }
 
        return 0;
index ef6a298e8c45833843097d51499333ff9a4ecfef..1f4155ee3404de97e4eee3988dc7823c9874ecbd 100644 (file)
@@ -215,7 +215,6 @@ static struct platform_driver meson_wdt_driver = {
        .remove         = meson_wdt_remove,
        .shutdown       = meson_wdt_shutdown,
        .driver         = {
-               .owner          = THIS_MODULE,
                .name           = DRV_NAME,
                .of_match_table = meson_wdt_dt_ids,
        },
index 2d3e32ebfd15510b8e97519a006486c83755121b..8729cf68d2fef5e41540283d74beba55285f59c5 100644 (file)
@@ -1552,7 +1552,6 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
 {
        int ret;
        int type;
-       struct btrfs_tree_block_info *info;
        struct btrfs_extent_inline_ref *eiref;
 
        if (*ptr == (unsigned long)-1)
@@ -1573,9 +1572,17 @@ int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb,
        }
 
        /* we can treat both ref types equally here */
-       info = (struct btrfs_tree_block_info *)(ei + 1);
        *out_root = btrfs_extent_inline_ref_offset(eb, eiref);
-       *out_level = btrfs_tree_block_level(eb, info);
+
+       if (key->type == BTRFS_EXTENT_ITEM_KEY) {
+               struct btrfs_tree_block_info *info;
+
+               info = (struct btrfs_tree_block_info *)(ei + 1);
+               *out_level = btrfs_tree_block_level(eb, info);
+       } else {
+               ASSERT(key->type == BTRFS_METADATA_ITEM_KEY);
+               *out_level = (u8)key->offset;
+       }
 
        if (ret == 1)
                *ptr = (unsigned long)-1;
index 7e607416755a880fef1a06d3a8a3482417c0b364..0b180708bf79d87a36c9dcc78bbd6d72772101df 100644 (file)
@@ -1171,6 +1171,7 @@ struct btrfs_space_info {
        struct percpu_counter total_bytes_pinned;
 
        struct list_head list;
+       /* Protected by the spinlock 'lock'. */
        struct list_head ro_bgs;
 
        struct rw_semaphore groups_sem;
index 054577bddaf27869d9a524a73d4df5a76072e4e1..de4e70fb3cbbd4a5c28d13f1fe3aec16733ed49f 100644 (file)
@@ -1857,6 +1857,14 @@ int btrfs_delayed_delete_inode_ref(struct inode *inode)
 {
        struct btrfs_delayed_node *delayed_node;
 
+       /*
+        * we don't do delayed inode updates during log recovery because it
+        * leads to enospc problems.  This means we also can't do
+        * delayed inode refs
+        */
+       if (BTRFS_I(inode)->root->fs_info->log_root_recovering)
+               return -EAGAIN;
+
        delayed_node = btrfs_get_or_create_delayed_node(inode);
        if (IS_ERR(delayed_node))
                return PTR_ERR(delayed_node);
index a80b97100d90b3162d7d3688ed6b3c459bb56bc8..a684086c3c8123702cc41caa4d4dfe085aa7db3b 100644 (file)
@@ -3139,9 +3139,11 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        struct extent_buffer *leaf;
 
        ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1);
-       if (ret < 0)
+       if (ret) {
+               if (ret > 0)
+                       ret = -ENOENT;
                goto fail;
-       BUG_ON(ret); /* Corruption */
+       }
 
        leaf = path->nodes[0];
        bi = btrfs_item_ptr_offset(leaf, path->slots[0]);
@@ -3149,11 +3151,9 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
        btrfs_release_path(path);
 fail:
-       if (ret) {
+       if (ret)
                btrfs_abort_transaction(trans, root, ret);
-               return ret;
-       }
-       return 0;
+       return ret;
 
 }
 
@@ -9422,7 +9422,6 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
         * are still on the list after taking the semaphore
         */
        list_del_init(&block_group->list);
-       list_del_init(&block_group->ro_list);
        if (list_empty(&block_group->space_info->block_groups[index])) {
                kobj = block_group->space_info->block_group_kobjs[index];
                block_group->space_info->block_group_kobjs[index] = NULL;
@@ -9464,6 +9463,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
        btrfs_remove_free_space_cache(block_group);
 
        spin_lock(&block_group->space_info->lock);
+       list_del_init(&block_group->ro_list);
        block_group->space_info->total_bytes -= block_group->key.offset;
        block_group->space_info->bytes_readonly -= block_group->key.offset;
        block_group->space_info->disk_total -= block_group->key.offset * factor;
index 4ebabd2371533788c496070122def464004328ac..790dbae3343c4f965eaa58e317c08d702ad0a7ff 100644 (file)
@@ -2190,7 +2190,7 @@ void btrfs_free_io_failure_record(struct inode *inode, u64 start, u64 end)
 
                next = next_state(state);
 
-               failrec = (struct io_failure_record *)state->private;
+               failrec = (struct io_failure_record *)(unsigned long)state->private;
                free_extent_state(state);
                kfree(failrec);
 
index e687bb0dc73a36724a921d40bc66c89473f7edac..8bf326affb944026a43bbc42a900d6f8355ce837 100644 (file)
@@ -6255,8 +6255,10 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
 
 out_fail:
        btrfs_end_transaction(trans, root);
-       if (drop_on_err)
+       if (drop_on_err) {
+               inode_dec_link_count(inode);
                iput(inode);
+       }
        btrfs_balance_delayed_items(root);
        btrfs_btree_balance_dirty(root);
        return err;
index f2bb13a23f860ea19d0403057395d38d8b9d2632..e427cb7ee12c7d848cd16402d78854e22db969dd 100644 (file)
@@ -2607,9 +2607,9 @@ static int scrub_extent_for_parity(struct scrub_parity *sparity,
                ret = scrub_pages_for_parity(sparity, logical, l, physical, dev,
                                             flags, gen, mirror_num,
                                             have_csum ? csum : NULL);
-skip:
                if (ret)
                        return ret;
+skip:
                len -= l;
                logical += l;
                physical += l;
@@ -3053,7 +3053,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 
        ppath = btrfs_alloc_path();
        if (!ppath) {
-               btrfs_free_path(ppath);
+               btrfs_free_path(path);
                return -ENOMEM;
        }
 
@@ -3065,6 +3065,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
        path->search_commit_root = 1;
        path->skip_locking = 1;
 
+       ppath->search_commit_root = 1;
+       ppath->skip_locking = 1;
        /*
         * trigger the readahead for extent tree csum tree and wait for
         * completion. During readahead, the scrub is officially paused
index 60f7cbe815e9c88362a1680f8e4259f51ca6f019..6f49b2872a6454330bac0ef912be3d0152e2ef4f 100644 (file)
@@ -1000,10 +1000,20 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
                         */
                        if (fs_info->pending_changes == 0)
                                return 0;
+                       /*
+                        * A non-blocking test if the fs is frozen. We must not
+                        * start a new transaction here otherwise a deadlock
+                        * happens. The pending operations are delayed to the
+                        * next commit after thawing.
+                        */
+                       if (__sb_start_write(sb, SB_FREEZE_WRITE, false))
+                               __sb_end_write(sb, SB_FREEZE_WRITE);
+                       else
+                               return 0;
                        trans = btrfs_start_transaction(root, 0);
-               } else {
-                       return PTR_ERR(trans);
                }
+               if (IS_ERR(trans))
+                       return PTR_ERR(trans);
        }
        return btrfs_commit_transaction(trans, root);
 }
index a605d4e2f2bca98e14c430c31514588c1b7982f1..e88b59d13439690f15810359ee7be343ad86b7a9 100644 (file)
@@ -2118,7 +2118,7 @@ void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info)
        unsigned long prev;
        unsigned long bit;
 
-       prev = cmpxchg(&fs_info->pending_changes, 0, 0);
+       prev = xchg(&fs_info->pending_changes, 0);
        if (!prev)
                return;
 
index f5013d92a7e6b73d9c4369683f6aac987afbd287..c81c0e004588b9e2ae03580ed6265096d6608d46 100644 (file)
@@ -1416,7 +1416,7 @@ void ceph_fill_inline_data(struct inode *inode, struct page *locked_page,
                }
        }
 
-       dout("fill_inline_data %p %llx.%llx len %lu locked_page %p\n",
+       dout("fill_inline_data %p %llx.%llx len %zu locked_page %p\n",
             inode, ceph_vinop(inode), len, locked_page);
 
        if (len > 0) {
index 6e139111fdb250cc85f28d96d7d26fe0508850a4..22b289a3b1c4d3e12727cc0a005456fa9b295a00 100644 (file)
@@ -661,16 +661,16 @@ set_credits(struct TCP_Server_Info *server, const int val)
        server->ops->set_credits(server, val);
 }
 
-static inline __u64
+static inline __le64
 get_next_mid64(struct TCP_Server_Info *server)
 {
-       return server->ops->get_next_mid(server);
+       return cpu_to_le64(server->ops->get_next_mid(server));
 }
 
 static inline __le16
 get_next_mid(struct TCP_Server_Info *server)
 {
-       __u16 mid = get_next_mid64(server);
+       __u16 mid = server->ops->get_next_mid(server);
        /*
         * The value in the SMB header should be little endian for easy
         * on-the-wire decoding.
index 45cb59bcc79188df595447ab93b56f9cf1a6f080..8b7898b7670f88c3ea9ec596129ef569eed183bd 100644 (file)
@@ -86,21 +86,16 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
        }
 
        src_inode = file_inode(src_file.file);
+       rc = -EINVAL;
+       if (S_ISDIR(src_inode->i_mode))
+               goto out_fput;
 
        /*
         * Note: cifs case is easier than btrfs since server responsible for
         * checks for proper open modes and file type and if it wants
         * server could even support copy of range where source = target
         */
-
-       /* so we do not deadlock racing two ioctls on same files */
-       if (target_inode < src_inode) {
-               mutex_lock_nested(&target_inode->i_mutex, I_MUTEX_PARENT);
-               mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
-       } else {
-               mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_PARENT);
-               mutex_lock_nested(&target_inode->i_mutex, I_MUTEX_CHILD);
-       }
+       lock_two_nondirectories(target_inode, src_inode);
 
        /* determine range to clone */
        rc = -EINVAL;
@@ -124,13 +119,7 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
 out_unlock:
        /* although unlocking in the reverse order from locking is not
           strictly necessary here it is a little cleaner to be consistent */
-       if (target_inode < src_inode) {
-               mutex_unlock(&src_inode->i_mutex);
-               mutex_unlock(&target_inode->i_mutex);
-       } else {
-               mutex_unlock(&target_inode->i_mutex);
-               mutex_unlock(&src_inode->i_mutex);
-       }
+       unlock_two_nondirectories(src_inode, target_inode);
 out_fput:
        fdput(src_file);
 out_drop_write:
index b333ff60781d295809d8fa8f23366f9bcf8d9285..abae6dd2c6b998816db830f40934c86ea8c33fff 100644 (file)
@@ -926,6 +926,7 @@ cifs_NTtimeToUnix(__le64 ntutc)
 
        /* Subtract the NTFS time offset, then convert to 1s intervals. */
        s64 t = le64_to_cpu(ntutc) - NTFS_TIME_OFFSET;
+       u64 abs_t;
 
        /*
         * Unfortunately can not use normal 64 bit division on 32 bit arch, but
@@ -933,13 +934,14 @@ cifs_NTtimeToUnix(__le64 ntutc)
         * to special case them
         */
        if (t < 0) {
-               t = -t;
-               ts.tv_nsec = (long)(do_div(t, 10000000) * 100);
+               abs_t = -t;
+               ts.tv_nsec = (long)(do_div(abs_t, 10000000) * 100);
                ts.tv_nsec = -ts.tv_nsec;
-               ts.tv_sec = -t;
+               ts.tv_sec = -abs_t;
        } else {
-               ts.tv_nsec = (long)do_div(t, 10000000) * 100;
-               ts.tv_sec = t;
+               abs_t = t;
+               ts.tv_nsec = (long)do_div(abs_t, 10000000) * 100;
+               ts.tv_sec = abs_t;
        }
 
        return ts;
index 8eaf20a806494c71002a668a3e49b159b1b66d71..c295338e0a98ce95a71c60afedc87ad9bd5267b5 100644 (file)
@@ -69,7 +69,8 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
  * Attempt to preload the dcache with the results from the FIND_FIRST/NEXT
  *
  * Find the dentry that matches "name". If there isn't one, create one. If it's
- * a negative dentry or the uniqueid changed, then drop it and recreate it.
+ * a negative dentry or the uniqueid or filetype(mode) changed,
+ * then drop it and recreate it.
  */
 static void
 cifs_prime_dcache(struct dentry *parent, struct qstr *name,
@@ -97,8 +98,11 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
                        if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
                                fattr->cf_uniqueid = CIFS_I(inode)->uniqueid;
 
-                       /* update inode in place if i_ino didn't change */
-                       if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid) {
+                       /* update inode in place
+                        * if both i_ino and i_mode didn't change */
+                       if (CIFS_I(inode)->uniqueid == fattr->cf_uniqueid &&
+                           (inode->i_mode & S_IFMT) ==
+                           (fattr->cf_mode & S_IFMT)) {
                                cifs_fattr_to_inode(inode, fattr);
                                goto out;
                        }
index f1cefc9763edaeb3115ee1868d9bc4f033b7e0f5..689f035915cf70f075d71fca5e281ec009c5420a 100644 (file)
 static int
 check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
 {
+       __u64 wire_mid = le64_to_cpu(hdr->MessageId);
+
        /*
         * Make sure that this really is an SMB, that it is a response,
         * and that the message ids match.
         */
        if ((*(__le32 *)hdr->ProtocolId == SMB2_PROTO_NUMBER) &&
-           (mid == hdr->MessageId)) {
+           (mid == wire_mid)) {
                if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
                        return 0;
                else {
@@ -51,11 +53,11 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
                if (*(__le32 *)hdr->ProtocolId != SMB2_PROTO_NUMBER)
                        cifs_dbg(VFS, "Bad protocol string signature header %x\n",
                                 *(unsigned int *) hdr->ProtocolId);
-               if (mid != hdr->MessageId)
+               if (mid != wire_mid)
                        cifs_dbg(VFS, "Mids do not match: %llu and %llu\n",
-                                mid, hdr->MessageId);
+                                mid, wire_mid);
        }
-       cifs_dbg(VFS, "Bad SMB detected. The Mid=%llu\n", hdr->MessageId);
+       cifs_dbg(VFS, "Bad SMB detected. The Mid=%llu\n", wire_mid);
        return 1;
 }
 
@@ -95,7 +97,7 @@ smb2_check_message(char *buf, unsigned int length)
 {
        struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
        struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
-       __u64 mid = hdr->MessageId;
+       __u64 mid = le64_to_cpu(hdr->MessageId);
        __u32 len = get_rfc1002_length(buf);
        __u32 clc_len;  /* calculated length */
        int command;
index 93fd0586f9ec6e661c17de59cb66535d80e7ff51..96b5d40a2ece611b27ed19668cc4b7b665605113 100644 (file)
@@ -176,10 +176,11 @@ smb2_find_mid(struct TCP_Server_Info *server, char *buf)
 {
        struct mid_q_entry *mid;
        struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+       __u64 wire_mid = le64_to_cpu(hdr->MessageId);
 
        spin_lock(&GlobalMid_Lock);
        list_for_each_entry(mid, &server->pending_mid_q, qhead) {
-               if ((mid->mid == hdr->MessageId) &&
+               if ((mid->mid == wire_mid) &&
                    (mid->mid_state == MID_REQUEST_SUBMITTED) &&
                    (mid->command == hdr->Command)) {
                        spin_unlock(&GlobalMid_Lock);
index ce858477002a6148e31a85e9f28fc012968f52c9..70867d54fb8bf485cb5ff4dcb3049f67ca86cb45 100644 (file)
@@ -110,7 +110,7 @@ struct smb2_hdr {
        __le16 CreditRequest;  /* CreditResponse */
        __le32 Flags;
        __le32 NextCommand;
-       __u64  MessageId;       /* opaque - so can stay little endian */
+       __le64 MessageId;
        __le32 ProcessId;
        __u32  TreeId;          /* opaque - so do not make little endian */
        __u64  SessionId;       /* opaque - so do not make little endian */
index 5111e7272db62e718fcb3d968af48083d598bccf..d4c5b6f109a7feaa6f2c99f21ca332ff41a2673f 100644 (file)
@@ -490,7 +490,7 @@ smb2_mid_entry_alloc(const struct smb2_hdr *smb_buffer,
                return temp;
        else {
                memset(temp, 0, sizeof(struct mid_q_entry));
-               temp->mid = smb_buffer->MessageId;      /* always LE */
+               temp->mid = le64_to_cpu(smb_buffer->MessageId);
                temp->pid = current->pid;
                temp->command = smb_buffer->Command;    /* Always LE */
                temp->when_alloc = jiffies;
index e5d3eadf47b1e7fb6251c590016044cf8b5c4c98..bed43081720f718fc30dca204be8509ddcf5eac5 100644 (file)
@@ -5166,8 +5166,8 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 
        /* fallback to generic here if not in extents fmt */
        if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
-               return __generic_block_fiemap(inode, fieinfo, start, len,
-                                             ext4_get_block);
+               return generic_block_fiemap(inode, fieinfo, start, len,
+                       ext4_get_block);
 
        if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS))
                return -EBADR;
index 513c12cf444c239f5c34bd4d73c653029bdaca96..8131be8c0af3166aac865557baa9f0371564a397 100644 (file)
@@ -273,19 +273,24 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
  * we determine this extent as a data or a hole according to whether the
  * page cache has data or not.
  */
-static int ext4_find_unwritten_pgoff(struct inode *inode, int whence,
-                                    loff_t endoff, loff_t *offset)
+static int ext4_find_unwritten_pgoff(struct inode *inode,
+                                    int whence,
+                                    struct ext4_map_blocks *map,
+                                    loff_t *offset)
 {
        struct pagevec pvec;
+       unsigned int blkbits;
        pgoff_t index;
        pgoff_t end;
+       loff_t endoff;
        loff_t startoff;
        loff_t lastoff;
        int found = 0;
 
+       blkbits = inode->i_sb->s_blocksize_bits;
        startoff = *offset;
        lastoff = startoff;
-
+       endoff = (loff_t)(map->m_lblk + map->m_len) << blkbits;
 
        index = startoff >> PAGE_CACHE_SHIFT;
        end = endoff >> PAGE_CACHE_SHIFT;
@@ -403,144 +408,147 @@ out:
 static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
 {
        struct inode *inode = file->f_mapping->host;
-       struct fiemap_extent_info fie;
-       struct fiemap_extent ext[2];
-       loff_t next;
-       int i, ret = 0;
+       struct ext4_map_blocks map;
+       struct extent_status es;
+       ext4_lblk_t start, last, end;
+       loff_t dataoff, isize;
+       int blkbits;
+       int ret = 0;
 
        mutex_lock(&inode->i_mutex);
-       if (offset >= inode->i_size) {
+
+       isize = i_size_read(inode);
+       if (offset >= isize) {
                mutex_unlock(&inode->i_mutex);
                return -ENXIO;
        }
-       fie.fi_flags = 0;
-       fie.fi_extents_max = 2;
-       fie.fi_extents_start = (struct fiemap_extent __user *) &ext;
-       while (1) {
-               mm_segment_t old_fs = get_fs();
-
-               fie.fi_extents_mapped = 0;
-               memset(ext, 0, sizeof(*ext) * fie.fi_extents_max);
-
-               set_fs(get_ds());
-               ret = ext4_fiemap(inode, &fie, offset, maxsize - offset);
-               set_fs(old_fs);
-               if (ret)
+
+       blkbits = inode->i_sb->s_blocksize_bits;
+       start = offset >> blkbits;
+       last = start;
+       end = isize >> blkbits;
+       dataoff = offset;
+
+       do {
+               map.m_lblk = last;
+               map.m_len = end - last + 1;
+               ret = ext4_map_blocks(NULL, inode, &map, 0);
+               if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) {
+                       if (last != start)
+                               dataoff = (loff_t)last << blkbits;
                        break;
+               }
 
-               /* No extents found, EOF */
-               if (!fie.fi_extents_mapped) {
-                       ret = -ENXIO;
+               /*
+                * If there is a delay extent at this offset,
+                * it will be as a data.
+                */
+               ext4_es_find_delayed_extent_range(inode, last, last, &es);
+               if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
+                       if (last != start)
+                               dataoff = (loff_t)last << blkbits;
                        break;
                }
-               for (i = 0; i < fie.fi_extents_mapped; i++) {
-                       next = (loff_t)(ext[i].fe_length + ext[i].fe_logical);
 
-                       if (offset < (loff_t)ext[i].fe_logical)
-                               offset = (loff_t)ext[i].fe_logical;
-                       /*
-                        * If extent is not unwritten, then it contains valid
-                        * data, mapped or delayed.
-                        */
-                       if (!(ext[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN))
-                               goto out;
+               /*
+                * If there is a unwritten extent at this offset,
+                * it will be as a data or a hole according to page
+                * cache that has data or not.
+                */
+               if (map.m_flags & EXT4_MAP_UNWRITTEN) {
+                       int unwritten;
+                       unwritten = ext4_find_unwritten_pgoff(inode, SEEK_DATA,
+                                                             &map, &dataoff);
+                       if (unwritten)
+                               break;
+               }
 
-                       /*
-                        * If there is a unwritten extent at this offset,
-                        * it will be as a data or a hole according to page
-                        * cache that has data or not.
-                        */
-                       if (ext4_find_unwritten_pgoff(inode, SEEK_DATA,
-                                                     next, &offset))
-                               goto out;
+               last++;
+               dataoff = (loff_t)last << blkbits;
+       } while (last <= end);
 
-                       if (ext[i].fe_flags & FIEMAP_EXTENT_LAST) {
-                               ret = -ENXIO;
-                               goto out;
-                       }
-                       offset = next;
-               }
-       }
-       if (offset > inode->i_size)
-               offset = inode->i_size;
-out:
        mutex_unlock(&inode->i_mutex);
-       if (ret)
-               return ret;
 
-       return vfs_setpos(file, offset, maxsize);
+       if (dataoff > isize)
+               return -ENXIO;
+
+       return vfs_setpos(file, dataoff, maxsize);
 }
 
 /*
- * ext4_seek_hole() retrieves the offset for SEEK_HOLE
+ * ext4_seek_hole() retrieves the offset for SEEK_HOLE.
  */
 static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
 {
        struct inode *inode = file->f_mapping->host;
-       struct fiemap_extent_info fie;
-       struct fiemap_extent ext[2];
-       loff_t next;
-       int i, ret = 0;
+       struct ext4_map_blocks map;
+       struct extent_status es;
+       ext4_lblk_t start, last, end;
+       loff_t holeoff, isize;
+       int blkbits;
+       int ret = 0;
 
        mutex_lock(&inode->i_mutex);
-       if (offset >= inode->i_size) {
+
+       isize = i_size_read(inode);
+       if (offset >= isize) {
                mutex_unlock(&inode->i_mutex);
                return -ENXIO;
        }
 
-       fie.fi_flags = 0;
-       fie.fi_extents_max = 2;
-       fie.fi_extents_start = (struct fiemap_extent __user *)&ext;
-       while (1) {
-               mm_segment_t old_fs = get_fs();
-
-               fie.fi_extents_mapped = 0;
-               memset(ext, 0, sizeof(*ext));
+       blkbits = inode->i_sb->s_blocksize_bits;
+       start = offset >> blkbits;
+       last = start;
+       end = isize >> blkbits;
+       holeoff = offset;
 
-               set_fs(get_ds());
-               ret = ext4_fiemap(inode, &fie, offset, maxsize - offset);
-               set_fs(old_fs);
-               if (ret)
-                       break;
+       do {
+               map.m_lblk = last;
+               map.m_len = end - last + 1;
+               ret = ext4_map_blocks(NULL, inode, &map, 0);
+               if (ret > 0 && !(map.m_flags & EXT4_MAP_UNWRITTEN)) {
+                       last += ret;
+                       holeoff = (loff_t)last << blkbits;
+                       continue;
+               }
 
-               /* No extents found */
-               if (!fie.fi_extents_mapped)
-                       break;
+               /*
+                * If there is a delay extent at this offset,
+                * we will skip this extent.
+                */
+               ext4_es_find_delayed_extent_range(inode, last, last, &es);
+               if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
+                       last = es.es_lblk + es.es_len;
+                       holeoff = (loff_t)last << blkbits;
+                       continue;
+               }
 
-               for (i = 0; i < fie.fi_extents_mapped; i++) {
-                       next = (loff_t)(ext[i].fe_logical + ext[i].fe_length);
-                       /*
-                        * If extent is not unwritten, then it contains valid
-                        * data, mapped or delayed.
-                        */
-                       if (!(ext[i].fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
-                               if (offset < (loff_t)ext[i].fe_logical)
-                                       goto out;
-                               offset = next;
+               /*
+                * If there is a unwritten extent at this offset,
+                * it will be as a data or a hole according to page
+                * cache that has data or not.
+                */
+               if (map.m_flags & EXT4_MAP_UNWRITTEN) {
+                       int unwritten;
+                       unwritten = ext4_find_unwritten_pgoff(inode, SEEK_HOLE,
+                                                             &map, &holeoff);
+                       if (!unwritten) {
+                               last += ret;
+                               holeoff = (loff_t)last << blkbits;
                                continue;
                        }
-                       /*
-                        * If there is a unwritten extent at this offset,
-                        * it will be as a data or a hole according to page
-                        * cache that has data or not.
-                        */
-                       if (ext4_find_unwritten_pgoff(inode, SEEK_HOLE,
-                                                     next, &offset))
-                               goto out;
-
-                       offset = next;
-                       if (ext[i].fe_flags & FIEMAP_EXTENT_LAST)
-                               goto out;
                }
-       }
-       if (offset > inode->i_size)
-               offset = inode->i_size;
-out:
+
+               /* find a hole */
+               break;
+       } while (last <= end);
+
        mutex_unlock(&inode->i_mutex);
-       if (ret)
-               return ret;
 
-       return vfs_setpos(file, offset, maxsize);
+       if (holeoff > isize)
+               holeoff = isize;
+
+       return vfs_setpos(file, holeoff, maxsize);
 }
 
 /*
index bf76f405a5f91df5f276e2a2d1dcf2935178d4a7..8a8ec6293b195f16623e716342463979427b3156 100644 (file)
@@ -23,6 +23,18 @@ int ext4_resize_begin(struct super_block *sb)
        if (!capable(CAP_SYS_RESOURCE))
                return -EPERM;
 
+       /*
+        * If we are not using the primary superblock/GDT copy don't resize,
+         * because the user tools have no way of handling this.  Probably a
+         * bad time to do it anyways.
+         */
+       if (EXT4_SB(sb)->s_sbh->b_blocknr !=
+           le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
+               ext4_warning(sb, "won't resize using backup superblock at %llu",
+                       (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
+               return -EPERM;
+       }
+
        /*
         * We are not allowed to do online-resizing on a filesystem mounted
         * with error, because it can destroy the filesystem easily.
@@ -758,18 +770,6 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
                       "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n",
                       gdb_num);
 
-       /*
-        * If we are not using the primary superblock/GDT copy don't resize,
-         * because the user tools have no way of handling this.  Probably a
-         * bad time to do it anyways.
-         */
-       if (EXT4_SB(sb)->s_sbh->b_blocknr !=
-           le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
-               ext4_warning(sb, "won't resize using backup superblock at %llu",
-                       (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
-               return -EPERM;
-       }
-
        gdb_bh = sb_bread(sb, gdblock);
        if (!gdb_bh)
                return -EIO;
index 43c92b1685cbff914240436f4d0901861c9fd2c2..74c5f53595fbd1d236026f0d78b3071982f89075 100644 (file)
@@ -3482,7 +3482,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
            EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
-               ext4_warning(sb, KERN_INFO "metadata_csum and uninit_bg are "
+               ext4_warning(sb, "metadata_csum and uninit_bg are "
                             "redundant flags; please run fsck.");
 
        /* Check for a known checksum algorithm */
index 99d440a4a6ba259e5bd7ec6b167dbedb2637ac5d..ee85cd4e136abbff33409fb018343028d21578e2 100644 (file)
@@ -740,14 +740,15 @@ static int __init fcntl_init(void)
         * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
         * is defined as O_NONBLOCK on some platforms and not on others.
         */
-       BUILD_BUG_ON(20 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
+       BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
                O_RDONLY        | O_WRONLY      | O_RDWR        |
                O_CREAT         | O_EXCL        | O_NOCTTY      |
                O_TRUNC         | O_APPEND      | /* O_NONBLOCK | */
                __O_SYNC        | O_DSYNC       | FASYNC        |
                O_DIRECT        | O_LARGEFILE   | O_DIRECTORY   |
                O_NOFOLLOW      | O_NOATIME     | O_CLOEXEC     |
-               __FMODE_EXEC    | O_PATH        | __O_TMPFILE
+               __FMODE_EXEC    | O_PATH        | __O_TMPFILE   |
+               __FMODE_NONOTIFY
                ));
 
        fasync_cache = kmem_cache_create("fasync_cache",
index ba1107977f2ecafa96cafc04f6498b3fb79a3145..ed19a7d622fa35decaa08b10e83b8bdee8712419 100644 (file)
@@ -131,6 +131,13 @@ static void fuse_req_init_context(struct fuse_req *req)
        req->in.h.pid = current->pid;
 }
 
+void fuse_set_initialized(struct fuse_conn *fc)
+{
+       /* Make sure stores before this are seen on another CPU */
+       smp_wmb();
+       fc->initialized = 1;
+}
+
 static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
 {
        return !fc->initialized || (for_background && fc->blocked);
@@ -155,6 +162,8 @@ static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
                if (intr)
                        goto out;
        }
+       /* Matches smp_wmb() in fuse_set_initialized() */
+       smp_rmb();
 
        err = -ENOTCONN;
        if (!fc->connected)
@@ -253,6 +262,8 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
 
        atomic_inc(&fc->num_waiting);
        wait_event(fc->blocked_waitq, fc->initialized);
+       /* Matches smp_wmb() in fuse_set_initialized() */
+       smp_rmb();
        req = fuse_request_alloc(0);
        if (!req)
                req = get_reserved_req(fc, file);
@@ -511,6 +522,39 @@ void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
 }
 EXPORT_SYMBOL_GPL(fuse_request_send);
 
+static void fuse_adjust_compat(struct fuse_conn *fc, struct fuse_args *args)
+{
+       if (fc->minor < 4 && args->in.h.opcode == FUSE_STATFS)
+               args->out.args[0].size = FUSE_COMPAT_STATFS_SIZE;
+
+       if (fc->minor < 9) {
+               switch (args->in.h.opcode) {
+               case FUSE_LOOKUP:
+               case FUSE_CREATE:
+               case FUSE_MKNOD:
+               case FUSE_MKDIR:
+               case FUSE_SYMLINK:
+               case FUSE_LINK:
+                       args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
+                       break;
+               case FUSE_GETATTR:
+               case FUSE_SETATTR:
+                       args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
+                       break;
+               }
+       }
+       if (fc->minor < 12) {
+               switch (args->in.h.opcode) {
+               case FUSE_CREATE:
+                       args->in.args[0].size = sizeof(struct fuse_open_in);
+                       break;
+               case FUSE_MKNOD:
+                       args->in.args[0].size = FUSE_COMPAT_MKNOD_IN_SIZE;
+                       break;
+               }
+       }
+}
+
 ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
 {
        struct fuse_req *req;
@@ -520,6 +564,9 @@ ssize_t fuse_simple_request(struct fuse_conn *fc, struct fuse_args *args)
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       /* Needs to be done after fuse_get_req() so that fc->minor is valid */
+       fuse_adjust_compat(fc, args);
+
        req->in.h.opcode = args->in.h.opcode;
        req->in.h.nodeid = args->in.h.nodeid;
        req->in.numargs = args->in.numargs;
@@ -2127,7 +2174,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
        if (fc->connected) {
                fc->connected = 0;
                fc->blocked = 0;
-               fc->initialized = 1;
+               fuse_set_initialized(fc);
                end_io_requests(fc);
                end_queued_requests(fc);
                end_polls(fc);
@@ -2146,7 +2193,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
                spin_lock(&fc->lock);
                fc->connected = 0;
                fc->blocked = 0;
-               fc->initialized = 1;
+               fuse_set_initialized(fc);
                end_queued_requests(fc);
                end_polls(fc);
                wake_up_all(&fc->blocked_waitq);
index 252b8a5de8b57f71b841d1fc64c9f48e78b641c2..08e7b1a9d5d0edaca8b94ef386d9200078958df3 100644 (file)
@@ -156,10 +156,7 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
        args->in.args[0].size = name->len + 1;
        args->in.args[0].value = name->name;
        args->out.numargs = 1;
-       if (fc->minor < 9)
-               args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
-       else
-               args->out.args[0].size = sizeof(struct fuse_entry_out);
+       args->out.args[0].size = sizeof(struct fuse_entry_out);
        args->out.args[0].value = outarg;
 }
 
@@ -422,16 +419,12 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
        args.in.h.opcode = FUSE_CREATE;
        args.in.h.nodeid = get_node_id(dir);
        args.in.numargs = 2;
-       args.in.args[0].size = fc->minor < 12 ? sizeof(struct fuse_open_in) :
-                                               sizeof(inarg);
+       args.in.args[0].size = sizeof(inarg);
        args.in.args[0].value = &inarg;
        args.in.args[1].size = entry->d_name.len + 1;
        args.in.args[1].value = entry->d_name.name;
        args.out.numargs = 2;
-       if (fc->minor < 9)
-               args.out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
-       else
-               args.out.args[0].size = sizeof(outentry);
+       args.out.args[0].size = sizeof(outentry);
        args.out.args[0].value = &outentry;
        args.out.args[1].size = sizeof(outopen);
        args.out.args[1].value = &outopen;
@@ -539,10 +532,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_args *args,
        memset(&outarg, 0, sizeof(outarg));
        args->in.h.nodeid = get_node_id(dir);
        args->out.numargs = 1;
-       if (fc->minor < 9)
-               args->out.args[0].size = FUSE_COMPAT_ENTRY_OUT_SIZE;
-       else
-               args->out.args[0].size = sizeof(outarg);
+       args->out.args[0].size = sizeof(outarg);
        args->out.args[0].value = &outarg;
        err = fuse_simple_request(fc, args);
        if (err)
@@ -592,8 +582,7 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
        inarg.umask = current_umask();
        args.in.h.opcode = FUSE_MKNOD;
        args.in.numargs = 2;
-       args.in.args[0].size = fc->minor < 12 ? FUSE_COMPAT_MKNOD_IN_SIZE :
-                                               sizeof(inarg);
+       args.in.args[0].size = sizeof(inarg);
        args.in.args[0].value = &inarg;
        args.in.args[1].size = entry->d_name.len + 1;
        args.in.args[1].value = entry->d_name.name;
@@ -899,10 +888,7 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
        args.in.args[0].size = sizeof(inarg);
        args.in.args[0].value = &inarg;
        args.out.numargs = 1;
-       if (fc->minor < 9)
-               args.out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
-       else
-               args.out.args[0].size = sizeof(outarg);
+       args.out.args[0].size = sizeof(outarg);
        args.out.args[0].value = &outarg;
        err = fuse_simple_request(fc, &args);
        if (!err) {
@@ -1574,10 +1560,7 @@ static void fuse_setattr_fill(struct fuse_conn *fc, struct fuse_args *args,
        args->in.args[0].size = sizeof(*inarg_p);
        args->in.args[0].value = inarg_p;
        args->out.numargs = 1;
-       if (fc->minor < 9)
-               args->out.args[0].size = FUSE_COMPAT_ATTR_OUT_SIZE;
-       else
-               args->out.args[0].size = sizeof(*outarg_p);
+       args->out.args[0].size = sizeof(*outarg_p);
        args->out.args[0].value = outarg_p;
 }
 
index e0fc6725d1d0d66a4c3c7dce595239631ba353b1..1cdfb07c1376b4f4b5633e86fdbdfc4320953de2 100644 (file)
@@ -906,4 +906,6 @@ int fuse_write_inode(struct inode *inode, struct writeback_control *wbc);
 int fuse_do_setattr(struct inode *inode, struct iattr *attr,
                    struct file *file);
 
+void fuse_set_initialized(struct fuse_conn *fc);
+
 #endif /* _FS_FUSE_I_H */
index 6749109f255da69a5c24825aab1f2a25140fbb47..f38256e4476ed2a9101480342bcd0fd90a99fd38 100644 (file)
@@ -424,8 +424,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
        args.in.h.opcode = FUSE_STATFS;
        args.in.h.nodeid = get_node_id(dentry->d_inode);
        args.out.numargs = 1;
-       args.out.args[0].size =
-               fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
+       args.out.args[0].size = sizeof(outarg);
        args.out.args[0].value = &outarg;
        err = fuse_simple_request(fc, &args);
        if (!err)
@@ -898,7 +897,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                fc->max_write = max_t(unsigned, 4096, fc->max_write);
                fc->conn_init = 1;
        }
-       fc->initialized = 1;
+       fuse_set_initialized(fc);
        wake_up_all(&fc->blocked_waitq);
 }
 
index c8b148bbdc8b574f77660eb35c8feba4baec2e5e..3e193cb36996d06520e2ed98e49a838fdfbab90d 100644 (file)
@@ -667,7 +667,7 @@ static void do_qc(struct gfs2_quota_data *qd, s64 change)
 
 static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
                             s64 change, struct gfs2_quota_data *qd,
-                            struct fs_disk_quota *fdq)
+                            struct qc_dqblk *fdq)
 {
        struct inode *inode = &ip->i_inode;
        struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -697,16 +697,16 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
        be64_add_cpu(&q.qu_value, change);
        qd->qd_qb.qb_value = q.qu_value;
        if (fdq) {
-               if (fdq->d_fieldmask & FS_DQ_BSOFT) {
-                       q.qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift);
+               if (fdq->d_fieldmask & QC_SPC_SOFT) {
+                       q.qu_warn = cpu_to_be64(fdq->d_spc_softlimit >> sdp->sd_sb.sb_bsize_shift);
                        qd->qd_qb.qb_warn = q.qu_warn;
                }
-               if (fdq->d_fieldmask & FS_DQ_BHARD) {
-                       q.qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift);
+               if (fdq->d_fieldmask & QC_SPC_HARD) {
+                       q.qu_limit = cpu_to_be64(fdq->d_spc_hardlimit >> sdp->sd_sb.sb_bsize_shift);
                        qd->qd_qb.qb_limit = q.qu_limit;
                }
-               if (fdq->d_fieldmask & FS_DQ_BCOUNT) {
-                       q.qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift);
+               if (fdq->d_fieldmask & QC_SPACE) {
+                       q.qu_value = cpu_to_be64(fdq->d_space >> sdp->sd_sb.sb_bsize_shift);
                        qd->qd_qb.qb_value = q.qu_value;
                }
        }
@@ -1497,7 +1497,7 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
 }
 
 static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
-                         struct fs_disk_quota *fdq)
+                         struct qc_dqblk *fdq)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_quota_lvb *qlvb;
@@ -1505,7 +1505,7 @@ static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
        struct gfs2_holder q_gh;
        int error;
 
-       memset(fdq, 0, sizeof(struct fs_disk_quota));
+       memset(fdq, 0, sizeof(*fdq));
 
        if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
                return -ESRCH; /* Crazy XFS error code */
@@ -1522,12 +1522,9 @@ static int gfs2_get_dqblk(struct super_block *sb, struct kqid qid,
                goto out;
 
        qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lksb.sb_lvbptr;
-       fdq->d_version = FS_DQUOT_VERSION;
-       fdq->d_flags = (qid.type == USRQUOTA) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
-       fdq->d_id = from_kqid_munged(current_user_ns(), qid);
-       fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift;
-       fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift;
-       fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift;
+       fdq->d_spc_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_sb.sb_bsize_shift;
+       fdq->d_spc_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_sb.sb_bsize_shift;
+       fdq->d_space = be64_to_cpu(qlvb->qb_value) << sdp->sd_sb.sb_bsize_shift;
 
        gfs2_glock_dq_uninit(&q_gh);
 out:
@@ -1536,10 +1533,10 @@ out:
 }
 
 /* GFS2 only supports a subset of the XFS fields */
-#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT)
+#define GFS2_FIELDMASK (QC_SPC_SOFT|QC_SPC_HARD|QC_SPACE)
 
 static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
-                         struct fs_disk_quota *fdq)
+                         struct qc_dqblk *fdq)
 {
        struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
@@ -1583,17 +1580,17 @@ static int gfs2_set_dqblk(struct super_block *sb, struct kqid qid,
                goto out_i;
 
        /* If nothing has changed, this is a no-op */
-       if ((fdq->d_fieldmask & FS_DQ_BSOFT) &&
-           ((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
-               fdq->d_fieldmask ^= FS_DQ_BSOFT;
+       if ((fdq->d_fieldmask & QC_SPC_SOFT) &&
+           ((fdq->d_spc_softlimit >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_warn)))
+               fdq->d_fieldmask ^= QC_SPC_SOFT;
 
-       if ((fdq->d_fieldmask & FS_DQ_BHARD) &&
-           ((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
-               fdq->d_fieldmask ^= FS_DQ_BHARD;
+       if ((fdq->d_fieldmask & QC_SPC_HARD) &&
+           ((fdq->d_spc_hardlimit >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_limit)))
+               fdq->d_fieldmask ^= QC_SPC_HARD;
 
-       if ((fdq->d_fieldmask & FS_DQ_BCOUNT) &&
-           ((fdq->d_bcount >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_value)))
-               fdq->d_fieldmask ^= FS_DQ_BCOUNT;
+       if ((fdq->d_fieldmask & QC_SPACE) &&
+           ((fdq->d_space >> sdp->sd_sb.sb_bsize_shift) == be64_to_cpu(qd->qd_qb.qb_value)))
+               fdq->d_fieldmask ^= QC_SPACE;
 
        if (fdq->d_fieldmask == 0)
                goto out_i;
index bb63254ed8486f42200230b4bbaa80257f92700d..735d7522a3a911f19af593d6b5f7d366d6cf448d 100644 (file)
@@ -362,6 +362,9 @@ repeat:
                        rs.cont_size = isonum_733(rr->u.CE.size);
                        break;
                case SIG('E', 'R'):
+                       /* Invalid length of ER tag id? */
+                       if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len)
+                               goto out;
                        ISOFS_SB(inode->i_sb)->s_rock = 1;
                        printk(KERN_DEBUG "ISO 9660 Extensions: ");
                        {
index 37989f02a226ac40e104ee02efdad39d805686c5..2d881b381d2b787bbb2ff40b151e7496c0abafae 100644 (file)
@@ -201,10 +201,14 @@ static unsigned int kernfs_name_hash(const char *name, const void *ns)
 static int kernfs_name_compare(unsigned int hash, const char *name,
                               const void *ns, const struct kernfs_node *kn)
 {
-       if (hash != kn->hash)
-               return hash - kn->hash;
-       if (ns != kn->ns)
-               return ns - kn->ns;
+       if (hash < kn->hash)
+               return -1;
+       if (hash > kn->hash)
+               return 1;
+       if (ns < kn->ns)
+               return -1;
+       if (ns > kn->ns)
+               return 1;
        return strcmp(name, kn->name);
 }
 
index e94c887da2d72f7043ed010bfa8675b4ad825bb6..55505cbe11afa165ec90ec934301c15a1b9a4314 100644 (file)
@@ -138,10 +138,6 @@ lockd(void *vrqstp)
 
        dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
 
-       if (!nlm_timeout)
-               nlm_timeout = LOCKD_DFLT_TIMEO;
-       nlmsvc_timeout = nlm_timeout * HZ;
-
        /*
         * The main request loop. We don't terminate until the last
         * NFS mount or NFS daemon has gone away.
@@ -350,6 +346,10 @@ static struct svc_serv *lockd_create_svc(void)
                printk(KERN_WARNING
                        "lockd_up: no pid, %d users??\n", nlmsvc_users);
 
+       if (!nlm_timeout)
+               nlm_timeout = LOCKD_DFLT_TIMEO;
+       nlmsvc_timeout = nlm_timeout * HZ;
+
        serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, svc_rpcb_cleanup);
        if (!serv) {
                printk(KERN_WARNING "lockd_up: create service failed\n");
index 735b8d3fa78c92bf746aff05475be1fa2a82abd6..59e2f905e4ffea324dbf44faf1b666974adc6c23 100644 (file)
@@ -1702,7 +1702,7 @@ static int generic_delete_lease(struct file *filp)
                        break;
        }
        trace_generic_delete_lease(inode, fl);
-       if (fl)
+       if (fl && IS_LEASE(fl))
                error = fl->fl_lmops->lm_change(before, F_UNLCK, &dispose);
        spin_unlock(&inode->i_lock);
        locks_dispose_list(&dispose);
index 10bf07280f4ab2715845003334b73d80bde15f44..294692ff83b1a4e024ff217727fe958edabb0e3d 100644 (file)
@@ -212,6 +212,12 @@ static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq,
  */
 ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, loff_t pos)
 {
+       struct inode *inode = iocb->ki_filp->f_mapping->host;
+
+       /* we only support swap file calling nfs_direct_IO */
+       if (!IS_SWAPFILE(inode))
+               return 0;
+
 #ifndef CONFIG_NFS_SWAP
        dprintk("NFS: nfs_direct_IO (%pD) off/no(%Ld/%lu) EINVAL\n",
                        iocb->ki_filp, (long long) pos, iter->nr_segs);
index 4bffe637ea3255fd2e1e6812556e3907791f4152..2211f6ba873628485fcabf874adf0c3c985a6d84 100644 (file)
@@ -352,8 +352,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
 
        nfs_attr_check_mountpoint(sb, fattr);
 
-       if (((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0) &&
-           !nfs_attr_use_mounted_on_fileid(fattr))
+       if (nfs_attr_use_mounted_on_fileid(fattr))
+               fattr->fileid = fattr->mounted_on_fileid;
+       else if ((fattr->valid & NFS_ATTR_FATTR_FILEID) == 0)
                goto out_no_inode;
        if ((fattr->valid & NFS_ATTR_FATTR_TYPE) == 0)
                goto out_no_inode;
index efaa31c70fbe1c43d265c51bc542a8270348c339..b6f34bfa6fe83b271a3b1f6c66e63f9e21587f6d 100644 (file)
@@ -31,8 +31,6 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
            (((fattr->valid & NFS_ATTR_FATTR_MOUNTPOINT) == 0) &&
             ((fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) == 0)))
                return 0;
-
-       fattr->fileid = fattr->mounted_on_fileid;
        return 1;
 }
 
index 03311259b0c45c88de37122cffc0f28c8f6c7e63..706ad10b8186d4401eb4da48ebf0e7fba7686481 100644 (file)
@@ -228,6 +228,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
        kfree(clp->cl_serverowner);
        kfree(clp->cl_serverscope);
        kfree(clp->cl_implid);
+       kfree(clp->cl_owner_id);
 }
 
 void nfs4_free_client(struct nfs_client *clp)
@@ -452,6 +453,14 @@ static void nfs4_swap_callback_idents(struct nfs_client *keep,
        spin_unlock(&nn->nfs_client_lock);
 }
 
+static bool nfs4_match_client_owner_id(const struct nfs_client *clp1,
+               const struct nfs_client *clp2)
+{
+       if (clp1->cl_owner_id == NULL || clp2->cl_owner_id == NULL)
+               return true;
+       return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0;
+}
+
 /**
  * nfs40_walk_client_list - Find server that recognizes a client ID
  *
@@ -483,9 +492,6 @@ int nfs40_walk_client_list(struct nfs_client *new,
                if (pos->rpc_ops != new->rpc_ops)
                        continue;
 
-               if (pos->cl_proto != new->cl_proto)
-                       continue;
-
                if (pos->cl_minorversion != new->cl_minorversion)
                        continue;
 
@@ -510,6 +516,9 @@ int nfs40_walk_client_list(struct nfs_client *new,
                if (pos->cl_clientid != new->cl_clientid)
                        continue;
 
+               if (!nfs4_match_client_owner_id(pos, new))
+                       continue;
+
                atomic_inc(&pos->cl_count);
                spin_unlock(&nn->nfs_client_lock);
 
@@ -566,20 +575,14 @@ static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b)
 }
 
 /*
- * Returns true if the server owners match
+ * Returns true if the server major ids match
  */
 static bool
-nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b)
+nfs4_check_clientid_trunking(struct nfs_client *a, struct nfs_client *b)
 {
        struct nfs41_server_owner *o1 = a->cl_serverowner;
        struct nfs41_server_owner *o2 = b->cl_serverowner;
 
-       if (o1->minor_id != o2->minor_id) {
-               dprintk("NFS: --> %s server owner minor IDs do not match\n",
-                       __func__);
-               return false;
-       }
-
        if (o1->major_id_sz != o2->major_id_sz)
                goto out_major_mismatch;
        if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0)
@@ -621,9 +624,6 @@ int nfs41_walk_client_list(struct nfs_client *new,
                if (pos->rpc_ops != new->rpc_ops)
                        continue;
 
-               if (pos->cl_proto != new->cl_proto)
-                       continue;
-
                if (pos->cl_minorversion != new->cl_minorversion)
                        continue;
 
@@ -639,7 +639,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
                        prev = pos;
 
                        status = nfs_wait_client_init_complete(pos);
-                       if (status == 0) {
+                       if (pos->cl_cons_state == NFS_CS_SESSION_INITING) {
                                nfs4_schedule_lease_recovery(pos);
                                status = nfs4_wait_clnt_recover(pos);
                        }
@@ -654,7 +654,19 @@ int nfs41_walk_client_list(struct nfs_client *new,
                if (!nfs4_match_clientids(pos, new))
                        continue;
 
-               if (!nfs4_match_serverowners(pos, new))
+               /*
+                * Note that session trunking is just a special subcase of
+                * client id trunking. In either case, we want to fall back
+                * to using the existing nfs_client.
+                */
+               if (!nfs4_check_clientid_trunking(pos, new))
+                       continue;
+
+               /* Unlike NFSv4.0, we know that NFSv4.1 always uses the
+                * uniform string, however someone might switch the
+                * uniquifier string on us.
+                */
+               if (!nfs4_match_client_owner_id(pos, new))
                        continue;
 
                atomic_inc(&pos->cl_count);
index e7f8d5ff2581a98269a262998beb43ccaca23e3c..c347705b016104de8b0360f163e87c19d9b4d78c 100644 (file)
@@ -1117,8 +1117,6 @@ static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
                return 0;
        if ((delegation->type & fmode) != fmode)
                return 0;
-       if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
-               return 0;
        if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
                return 0;
        nfs_mark_delegation_referenced(delegation);
@@ -4917,11 +4915,14 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
 }
 
 static unsigned int
-nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
+nfs4_init_nonuniform_client_string(struct nfs_client *clp,
                                   char *buf, size_t len)
 {
        unsigned int result;
 
+       if (clp->cl_owner_id != NULL)
+               return strlcpy(buf, clp->cl_owner_id, len);
+
        rcu_read_lock();
        result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
                                clp->cl_ipaddr,
@@ -4930,24 +4931,32 @@ nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
                                rpc_peeraddr2str(clp->cl_rpcclient,
                                                        RPC_DISPLAY_PROTO));
        rcu_read_unlock();
+       clp->cl_owner_id = kstrdup(buf, GFP_KERNEL);
        return result;
 }
 
 static unsigned int
-nfs4_init_uniform_client_string(const struct nfs_client *clp,
+nfs4_init_uniform_client_string(struct nfs_client *clp,
                                char *buf, size_t len)
 {
        const char *nodename = clp->cl_rpcclient->cl_nodename;
+       unsigned int result;
+
+       if (clp->cl_owner_id != NULL)
+               return strlcpy(buf, clp->cl_owner_id, len);
 
        if (nfs4_client_id_uniquifier[0] != '\0')
-               return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s",
+               result = scnprintf(buf, len, "Linux NFSv%u.%u %s/%s",
                                clp->rpc_ops->version,
                                clp->cl_minorversion,
                                nfs4_client_id_uniquifier,
                                nodename);
-       return scnprintf(buf, len, "Linux NFSv%u.%u %s",
+       else
+               result = scnprintf(buf, len, "Linux NFSv%u.%u %s",
                                clp->rpc_ops->version, clp->cl_minorversion,
                                nodename);
+       clp->cl_owner_id = kstrdup(buf, GFP_KERNEL);
+       return result;
 }
 
 /*
index 3550a9c876161afe908274c937591c5f40d9f78a..c06a1ba80d73e5fd2cd6c68f61210e8be9518993 100644 (file)
@@ -3897,11 +3897,11 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
                status = nfs4_setlease(dp);
                goto out;
        }
-       atomic_inc(&fp->fi_delegees);
        if (fp->fi_had_conflict) {
                status = -EAGAIN;
                goto out_unlock;
        }
+       atomic_inc(&fp->fi_delegees);
        hash_delegation_locked(dp, fp);
        status = 0;
 out_unlock:
index c991616acca9ef86e99d1e33dfd9d427adfb8b5f..bff8567aa42d1b04cd85e6f2863de3b1f4d9a2db 100644 (file)
@@ -259,16 +259,15 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
        struct fsnotify_event *kevent;
        char __user *start;
        int ret;
-       DEFINE_WAIT(wait);
+       DEFINE_WAIT_FUNC(wait, woken_wake_function);
 
        start = buf;
        group = file->private_data;
 
        pr_debug("%s: group=%p\n", __func__, group);
 
+       add_wait_queue(&group->notification_waitq, &wait);
        while (1) {
-               prepare_to_wait(&group->notification_waitq, &wait, TASK_INTERRUPTIBLE);
-
                mutex_lock(&group->notification_mutex);
                kevent = get_one_event(group, count);
                mutex_unlock(&group->notification_mutex);
@@ -289,7 +288,8 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
 
                        if (start != buf)
                                break;
-                       schedule();
+
+                       wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
                        continue;
                }
 
@@ -318,8 +318,8 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
                buf += ret;
                count -= ret;
        }
+       remove_wait_queue(&group->notification_waitq, &wait);
 
-       finish_wait(&group->notification_waitq, &wait);
        if (start != buf && ret != -EFAULT)
                ret = buf - start;
        return ret;
index 79b5af5e6a7b5d8a593a251cfa8c27aa11769447..cecd875653e4cc12d4326e7bf3e192106c0a94c0 100644 (file)
@@ -2023,11 +2023,8 @@ leave:
        dlm_lockres_drop_inflight_ref(dlm, res);
        spin_unlock(&res->spinlock);
 
-       if (ret < 0) {
+       if (ret < 0)
                mlog_errno(ret);
-               if (newlock)
-                       dlm_lock_put(newlock);
-       }
 
        return ret;
 }
index b931e04e33889742a6192255b3bd95d8779203ea..914c121ec8900380482f83728b90f7b0bd14e418 100644 (file)
@@ -94,6 +94,14 @@ static int ocfs2_create_symlink_data(struct ocfs2_super *osb,
                                     struct inode *inode,
                                     const char *symname);
 
+static int ocfs2_double_lock(struct ocfs2_super *osb,
+                            struct buffer_head **bh1,
+                            struct inode *inode1,
+                            struct buffer_head **bh2,
+                            struct inode *inode2,
+                            int rename);
+
+static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2);
 /* An orphan dir name is an 8 byte value, printed as a hex string */
 #define OCFS2_ORPHAN_NAMELEN ((int)(2 * sizeof(u64)))
 
@@ -678,8 +686,10 @@ static int ocfs2_link(struct dentry *old_dentry,
 {
        handle_t *handle;
        struct inode *inode = old_dentry->d_inode;
+       struct inode *old_dir = old_dentry->d_parent->d_inode;
        int err;
        struct buffer_head *fe_bh = NULL;
+       struct buffer_head *old_dir_bh = NULL;
        struct buffer_head *parent_fe_bh = NULL;
        struct ocfs2_dinode *fe = NULL;
        struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
@@ -696,19 +706,33 @@ static int ocfs2_link(struct dentry *old_dentry,
 
        dquot_initialize(dir);
 
-       err = ocfs2_inode_lock_nested(dir, &parent_fe_bh, 1, OI_LS_PARENT);
+       err = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
+                       &parent_fe_bh, dir, 0);
        if (err < 0) {
                if (err != -ENOENT)
                        mlog_errno(err);
                return err;
        }
 
+       /* make sure both dirs have bhs
+        * get an extra ref on old_dir_bh if old==new */
+       if (!parent_fe_bh) {
+               if (old_dir_bh) {
+                       parent_fe_bh = old_dir_bh;
+                       get_bh(parent_fe_bh);
+               } else {
+                       mlog(ML_ERROR, "%s: no old_dir_bh!\n", osb->uuid_str);
+                       err = -EIO;
+                       goto out;
+               }
+       }
+
        if (!dir->i_nlink) {
                err = -ENOENT;
                goto out;
        }
 
-       err = ocfs2_lookup_ino_from_name(dir, old_dentry->d_name.name,
+       err = ocfs2_lookup_ino_from_name(old_dir, old_dentry->d_name.name,
                        old_dentry->d_name.len, &old_de_ino);
        if (err) {
                err = -ENOENT;
@@ -801,10 +825,11 @@ out_unlock_inode:
        ocfs2_inode_unlock(inode, 1);
 
 out:
-       ocfs2_inode_unlock(dir, 1);
+       ocfs2_double_unlock(old_dir, dir);
 
        brelse(fe_bh);
        brelse(parent_fe_bh);
+       brelse(old_dir_bh);
 
        ocfs2_free_dir_lookup_result(&lookup);
 
@@ -1072,14 +1097,15 @@ static int ocfs2_check_if_ancestor(struct ocfs2_super *osb,
 }
 
 /*
- * The only place this should be used is rename!
+ * The only place this should be used is rename and link!
  * if they have the same id, then the 1st one is the only one locked.
  */
 static int ocfs2_double_lock(struct ocfs2_super *osb,
                             struct buffer_head **bh1,
                             struct inode *inode1,
                             struct buffer_head **bh2,
-                            struct inode *inode2)
+                            struct inode *inode2,
+                            int rename)
 {
        int status;
        int inode1_is_ancestor, inode2_is_ancestor;
@@ -1127,7 +1153,7 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
                }
                /* lock id2 */
                status = ocfs2_inode_lock_nested(inode2, bh2, 1,
-                                                OI_LS_RENAME1);
+                               rename == 1 ? OI_LS_RENAME1 : OI_LS_PARENT);
                if (status < 0) {
                        if (status != -ENOENT)
                                mlog_errno(status);
@@ -1136,7 +1162,8 @@ static int ocfs2_double_lock(struct ocfs2_super *osb,
        }
 
        /* lock id1 */
-       status = ocfs2_inode_lock_nested(inode1, bh1, 1, OI_LS_RENAME2);
+       status = ocfs2_inode_lock_nested(inode1, bh1, 1,
+                       rename == 1 ?  OI_LS_RENAME2 : OI_LS_PARENT);
        if (status < 0) {
                /*
                 * An error return must mean that no cluster locks
@@ -1252,7 +1279,7 @@ static int ocfs2_rename(struct inode *old_dir,
 
        /* if old and new are the same, this'll just do one lock. */
        status = ocfs2_double_lock(osb, &old_dir_bh, old_dir,
-                                  &new_dir_bh, new_dir);
+                                  &new_dir_bh, new_dir, 1);
        if (status < 0) {
                mlog_errno(status);
                goto bail;
index 8f0acef3d18481647507d32e1861420007f38e3d..69df5b239844f9395f38d2e3acb8f93f34142c0a 100644 (file)
@@ -2396,30 +2396,25 @@ static inline qsize_t stoqb(qsize_t space)
 }
 
 /* Generic routine for getting common part of quota structure */
-static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
+static void do_get_dqblk(struct dquot *dquot, struct qc_dqblk *di)
 {
        struct mem_dqblk *dm = &dquot->dq_dqb;
 
        memset(di, 0, sizeof(*di));
-       di->d_version = FS_DQUOT_VERSION;
-       di->d_flags = dquot->dq_id.type == USRQUOTA ?
-                       FS_USER_QUOTA : FS_GROUP_QUOTA;
-       di->d_id = from_kqid_munged(current_user_ns(), dquot->dq_id);
-
        spin_lock(&dq_data_lock);
-       di->d_blk_hardlimit = stoqb(dm->dqb_bhardlimit);
-       di->d_blk_softlimit = stoqb(dm->dqb_bsoftlimit);
+       di->d_spc_hardlimit = dm->dqb_bhardlimit;
+       di->d_spc_softlimit = dm->dqb_bsoftlimit;
        di->d_ino_hardlimit = dm->dqb_ihardlimit;
        di->d_ino_softlimit = dm->dqb_isoftlimit;
-       di->d_bcount = dm->dqb_curspace + dm->dqb_rsvspace;
-       di->d_icount = dm->dqb_curinodes;
-       di->d_btimer = dm->dqb_btime;
-       di->d_itimer = dm->dqb_itime;
+       di->d_space = dm->dqb_curspace + dm->dqb_rsvspace;
+       di->d_ino_count = dm->dqb_curinodes;
+       di->d_spc_timer = dm->dqb_btime;
+       di->d_ino_timer = dm->dqb_itime;
        spin_unlock(&dq_data_lock);
 }
 
 int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
-                   struct fs_disk_quota *di)
+                   struct qc_dqblk *di)
 {
        struct dquot *dquot;
 
@@ -2433,70 +2428,70 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid,
 }
 EXPORT_SYMBOL(dquot_get_dqblk);
 
-#define VFS_FS_DQ_MASK \
-       (FS_DQ_BCOUNT | FS_DQ_BSOFT | FS_DQ_BHARD | \
-        FS_DQ_ICOUNT | FS_DQ_ISOFT | FS_DQ_IHARD | \
-        FS_DQ_BTIMER | FS_DQ_ITIMER)
+#define VFS_QC_MASK \
+       (QC_SPACE | QC_SPC_SOFT | QC_SPC_HARD | \
+        QC_INO_COUNT | QC_INO_SOFT | QC_INO_HARD | \
+        QC_SPC_TIMER | QC_INO_TIMER)
 
 /* Generic routine for setting common part of quota structure */
-static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
+static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di)
 {
        struct mem_dqblk *dm = &dquot->dq_dqb;
        int check_blim = 0, check_ilim = 0;
        struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_id.type];
 
-       if (di->d_fieldmask & ~VFS_FS_DQ_MASK)
+       if (di->d_fieldmask & ~VFS_QC_MASK)
                return -EINVAL;
 
-       if (((di->d_fieldmask & FS_DQ_BSOFT) &&
-            (di->d_blk_softlimit > dqi->dqi_maxblimit)) ||
-           ((di->d_fieldmask & FS_DQ_BHARD) &&
-            (di->d_blk_hardlimit > dqi->dqi_maxblimit)) ||
-           ((di->d_fieldmask & FS_DQ_ISOFT) &&
+       if (((di->d_fieldmask & QC_SPC_SOFT) &&
+            stoqb(di->d_spc_softlimit) > dqi->dqi_maxblimit) ||
+           ((di->d_fieldmask & QC_SPC_HARD) &&
+            stoqb(di->d_spc_hardlimit) > dqi->dqi_maxblimit) ||
+           ((di->d_fieldmask & QC_INO_SOFT) &&
             (di->d_ino_softlimit > dqi->dqi_maxilimit)) ||
-           ((di->d_fieldmask & FS_DQ_IHARD) &&
+           ((di->d_fieldmask & QC_INO_HARD) &&
             (di->d_ino_hardlimit > dqi->dqi_maxilimit)))
                return -ERANGE;
 
        spin_lock(&dq_data_lock);
-       if (di->d_fieldmask & FS_DQ_BCOUNT) {
-               dm->dqb_curspace = di->d_bcount - dm->dqb_rsvspace;
+       if (di->d_fieldmask & QC_SPACE) {
+               dm->dqb_curspace = di->d_space - dm->dqb_rsvspace;
                check_blim = 1;
                set_bit(DQ_LASTSET_B + QIF_SPACE_B, &dquot->dq_flags);
        }
 
-       if (di->d_fieldmask & FS_DQ_BSOFT)
-               dm->dqb_bsoftlimit = qbtos(di->d_blk_softlimit);
-       if (di->d_fieldmask & FS_DQ_BHARD)
-               dm->dqb_bhardlimit = qbtos(di->d_blk_hardlimit);
-       if (di->d_fieldmask & (FS_DQ_BSOFT | FS_DQ_BHARD)) {
+       if (di->d_fieldmask & QC_SPC_SOFT)
+               dm->dqb_bsoftlimit = di->d_spc_softlimit;
+       if (di->d_fieldmask & QC_SPC_HARD)
+               dm->dqb_bhardlimit = di->d_spc_hardlimit;
+       if (di->d_fieldmask & (QC_SPC_SOFT | QC_SPC_HARD)) {
                check_blim = 1;
                set_bit(DQ_LASTSET_B + QIF_BLIMITS_B, &dquot->dq_flags);
        }
 
-       if (di->d_fieldmask & FS_DQ_ICOUNT) {
-               dm->dqb_curinodes = di->d_icount;
+       if (di->d_fieldmask & QC_INO_COUNT) {
+               dm->dqb_curinodes = di->d_ino_count;
                check_ilim = 1;
                set_bit(DQ_LASTSET_B + QIF_INODES_B, &dquot->dq_flags);
        }
 
-       if (di->d_fieldmask & FS_DQ_ISOFT)
+       if (di->d_fieldmask & QC_INO_SOFT)
                dm->dqb_isoftlimit = di->d_ino_softlimit;
-       if (di->d_fieldmask & FS_DQ_IHARD)
+       if (di->d_fieldmask & QC_INO_HARD)
                dm->dqb_ihardlimit = di->d_ino_hardlimit;
-       if (di->d_fieldmask & (FS_DQ_ISOFT | FS_DQ_IHARD)) {
+       if (di->d_fieldmask & (QC_INO_SOFT | QC_INO_HARD)) {
                check_ilim = 1;
                set_bit(DQ_LASTSET_B + QIF_ILIMITS_B, &dquot->dq_flags);
        }
 
-       if (di->d_fieldmask & FS_DQ_BTIMER) {
-               dm->dqb_btime = di->d_btimer;
+       if (di->d_fieldmask & QC_SPC_TIMER) {
+               dm->dqb_btime = di->d_spc_timer;
                check_blim = 1;
                set_bit(DQ_LASTSET_B + QIF_BTIME_B, &dquot->dq_flags);
        }
 
-       if (di->d_fieldmask & FS_DQ_ITIMER) {
-               dm->dqb_itime = di->d_itimer;
+       if (di->d_fieldmask & QC_INO_TIMER) {
+               dm->dqb_itime = di->d_ino_timer;
                check_ilim = 1;
                set_bit(DQ_LASTSET_B + QIF_ITIME_B, &dquot->dq_flags);
        }
@@ -2506,7 +2501,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
                    dm->dqb_curspace < dm->dqb_bsoftlimit) {
                        dm->dqb_btime = 0;
                        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
-               } else if (!(di->d_fieldmask & FS_DQ_BTIMER))
+               } else if (!(di->d_fieldmask & QC_SPC_TIMER))
                        /* Set grace only if user hasn't provided his own... */
                        dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
        }
@@ -2515,7 +2510,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
                    dm->dqb_curinodes < dm->dqb_isoftlimit) {
                        dm->dqb_itime = 0;
                        clear_bit(DQ_INODES_B, &dquot->dq_flags);
-               } else if (!(di->d_fieldmask & FS_DQ_ITIMER))
+               } else if (!(di->d_fieldmask & QC_INO_TIMER))
                        /* Set grace only if user hasn't provided his own... */
                        dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
        }
@@ -2531,7 +2526,7 @@ static int do_set_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
 }
 
 int dquot_set_dqblk(struct super_block *sb, struct kqid qid,
-                 struct fs_disk_quota *di)
+                 struct qc_dqblk *di)
 {
        struct dquot *dquot;
        int rc;
index 2aa4151f99d2e5e9183adfb34e2c31da24e2faa2..6f3856328eeabd4bbc57b09ca9c8fe01a9827c9c 100644 (file)
@@ -118,17 +118,27 @@ static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
        return sb->s_qcop->set_info(sb, type, &info);
 }
 
-static void copy_to_if_dqblk(struct if_dqblk *dst, struct fs_disk_quota *src)
+static inline qsize_t qbtos(qsize_t blocks)
+{
+       return blocks << QIF_DQBLKSIZE_BITS;
+}
+
+static inline qsize_t stoqb(qsize_t space)
+{
+       return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
+}
+
+static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src)
 {
        memset(dst, 0, sizeof(*dst));
-       dst->dqb_bhardlimit = src->d_blk_hardlimit;
-       dst->dqb_bsoftlimit = src->d_blk_softlimit;
-       dst->dqb_curspace = src->d_bcount;
+       dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
+       dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
+       dst->dqb_curspace = src->d_space;
        dst->dqb_ihardlimit = src->d_ino_hardlimit;
        dst->dqb_isoftlimit = src->d_ino_softlimit;
-       dst->dqb_curinodes = src->d_icount;
-       dst->dqb_btime = src->d_btimer;
-       dst->dqb_itime = src->d_itimer;
+       dst->dqb_curinodes = src->d_ino_count;
+       dst->dqb_btime = src->d_spc_timer;
+       dst->dqb_itime = src->d_ino_timer;
        dst->dqb_valid = QIF_ALL;
 }
 
@@ -136,7 +146,7 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
                          void __user *addr)
 {
        struct kqid qid;
-       struct fs_disk_quota fdq;
+       struct qc_dqblk fdq;
        struct if_dqblk idq;
        int ret;
 
@@ -154,36 +164,36 @@ static int quota_getquota(struct super_block *sb, int type, qid_t id,
        return 0;
 }
 
-static void copy_from_if_dqblk(struct fs_disk_quota *dst, struct if_dqblk *src)
+static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
 {
-       dst->d_blk_hardlimit = src->dqb_bhardlimit;
-       dst->d_blk_softlimit  = src->dqb_bsoftlimit;
-       dst->d_bcount = src->dqb_curspace;
+       dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
+       dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
+       dst->d_space = src->dqb_curspace;
        dst->d_ino_hardlimit = src->dqb_ihardlimit;
        dst->d_ino_softlimit = src->dqb_isoftlimit;
-       dst->d_icount = src->dqb_curinodes;
-       dst->d_btimer = src->dqb_btime;
-       dst->d_itimer = src->dqb_itime;
+       dst->d_ino_count = src->dqb_curinodes;
+       dst->d_spc_timer = src->dqb_btime;
+       dst->d_ino_timer = src->dqb_itime;
 
        dst->d_fieldmask = 0;
        if (src->dqb_valid & QIF_BLIMITS)
-               dst->d_fieldmask |= FS_DQ_BSOFT | FS_DQ_BHARD;
+               dst->d_fieldmask |= QC_SPC_SOFT | QC_SPC_HARD;
        if (src->dqb_valid & QIF_SPACE)
-               dst->d_fieldmask |= FS_DQ_BCOUNT;
+               dst->d_fieldmask |= QC_SPACE;
        if (src->dqb_valid & QIF_ILIMITS)
-               dst->d_fieldmask |= FS_DQ_ISOFT | FS_DQ_IHARD;
+               dst->d_fieldmask |= QC_INO_SOFT | QC_INO_HARD;
        if (src->dqb_valid & QIF_INODES)
-               dst->d_fieldmask |= FS_DQ_ICOUNT;
+               dst->d_fieldmask |= QC_INO_COUNT;
        if (src->dqb_valid & QIF_BTIME)
-               dst->d_fieldmask |= FS_DQ_BTIMER;
+               dst->d_fieldmask |= QC_SPC_TIMER;
        if (src->dqb_valid & QIF_ITIME)
-               dst->d_fieldmask |= FS_DQ_ITIMER;
+               dst->d_fieldmask |= QC_INO_TIMER;
 }
 
 static int quota_setquota(struct super_block *sb, int type, qid_t id,
                          void __user *addr)
 {
-       struct fs_disk_quota fdq;
+       struct qc_dqblk fdq;
        struct if_dqblk idq;
        struct kqid qid;
 
@@ -247,10 +257,78 @@ static int quota_getxstatev(struct super_block *sb, void __user *addr)
        return ret;
 }
 
+/*
+ * XFS defines BBTOB and BTOBB macros inside fs/xfs/ and we cannot move them
+ * out of there as xfsprogs rely on definitions being in that header file. So
+ * just define same functions here for quota purposes.
+ */
+#define XFS_BB_SHIFT 9
+
+static inline u64 quota_bbtob(u64 blocks)
+{
+       return blocks << XFS_BB_SHIFT;
+}
+
+static inline u64 quota_btobb(u64 bytes)
+{
+       return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
+}
+
+static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
+{
+       dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
+       dst->d_spc_softlimit = quota_bbtob(src->d_blk_softlimit);
+       dst->d_ino_hardlimit = src->d_ino_hardlimit;
+       dst->d_ino_softlimit = src->d_ino_softlimit;
+       dst->d_space = quota_bbtob(src->d_bcount);
+       dst->d_ino_count = src->d_icount;
+       dst->d_ino_timer = src->d_itimer;
+       dst->d_spc_timer = src->d_btimer;
+       dst->d_ino_warns = src->d_iwarns;
+       dst->d_spc_warns = src->d_bwarns;
+       dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
+       dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
+       dst->d_rt_space = quota_bbtob(src->d_rtbcount);
+       dst->d_rt_spc_timer = src->d_rtbtimer;
+       dst->d_rt_spc_warns = src->d_rtbwarns;
+       dst->d_fieldmask = 0;
+       if (src->d_fieldmask & FS_DQ_ISOFT)
+               dst->d_fieldmask |= QC_INO_SOFT;
+       if (src->d_fieldmask & FS_DQ_IHARD)
+               dst->d_fieldmask |= QC_INO_HARD;
+       if (src->d_fieldmask & FS_DQ_BSOFT)
+               dst->d_fieldmask |= QC_SPC_SOFT;
+       if (src->d_fieldmask & FS_DQ_BHARD)
+               dst->d_fieldmask |= QC_SPC_HARD;
+       if (src->d_fieldmask & FS_DQ_RTBSOFT)
+               dst->d_fieldmask |= QC_RT_SPC_SOFT;
+       if (src->d_fieldmask & FS_DQ_RTBHARD)
+               dst->d_fieldmask |= QC_RT_SPC_HARD;
+       if (src->d_fieldmask & FS_DQ_BTIMER)
+               dst->d_fieldmask |= QC_SPC_TIMER;
+       if (src->d_fieldmask & FS_DQ_ITIMER)
+               dst->d_fieldmask |= QC_INO_TIMER;
+       if (src->d_fieldmask & FS_DQ_RTBTIMER)
+               dst->d_fieldmask |= QC_RT_SPC_TIMER;
+       if (src->d_fieldmask & FS_DQ_BWARNS)
+               dst->d_fieldmask |= QC_SPC_WARNS;
+       if (src->d_fieldmask & FS_DQ_IWARNS)
+               dst->d_fieldmask |= QC_INO_WARNS;
+       if (src->d_fieldmask & FS_DQ_RTBWARNS)
+               dst->d_fieldmask |= QC_RT_SPC_WARNS;
+       if (src->d_fieldmask & FS_DQ_BCOUNT)
+               dst->d_fieldmask |= QC_SPACE;
+       if (src->d_fieldmask & FS_DQ_ICOUNT)
+               dst->d_fieldmask |= QC_INO_COUNT;
+       if (src->d_fieldmask & FS_DQ_RTBCOUNT)
+               dst->d_fieldmask |= QC_RT_SPACE;
+}
+
 static int quota_setxquota(struct super_block *sb, int type, qid_t id,
                           void __user *addr)
 {
        struct fs_disk_quota fdq;
+       struct qc_dqblk qdq;
        struct kqid qid;
 
        if (copy_from_user(&fdq, addr, sizeof(fdq)))
@@ -260,13 +338,44 @@ static int quota_setxquota(struct super_block *sb, int type, qid_t id,
        qid = make_kqid(current_user_ns(), type, id);
        if (!qid_valid(qid))
                return -EINVAL;
-       return sb->s_qcop->set_dqblk(sb, qid, &fdq);
+       copy_from_xfs_dqblk(&qdq, &fdq);
+       return sb->s_qcop->set_dqblk(sb, qid, &qdq);
+}
+
+static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
+                             int type, qid_t id)
+{
+       memset(dst, 0, sizeof(*dst));
+       dst->d_version = FS_DQUOT_VERSION;
+       dst->d_id = id;
+       if (type == USRQUOTA)
+               dst->d_flags = FS_USER_QUOTA;
+       else if (type == PRJQUOTA)
+               dst->d_flags = FS_PROJ_QUOTA;
+       else
+               dst->d_flags = FS_GROUP_QUOTA;
+       dst->d_blk_hardlimit = quota_btobb(src->d_spc_hardlimit);
+       dst->d_blk_softlimit = quota_btobb(src->d_spc_softlimit);
+       dst->d_ino_hardlimit = src->d_ino_hardlimit;
+       dst->d_ino_softlimit = src->d_ino_softlimit;
+       dst->d_bcount = quota_btobb(src->d_space);
+       dst->d_icount = src->d_ino_count;
+       dst->d_itimer = src->d_ino_timer;
+       dst->d_btimer = src->d_spc_timer;
+       dst->d_iwarns = src->d_ino_warns;
+       dst->d_bwarns = src->d_spc_warns;
+       dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
+       dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
+       dst->d_rtbcount = quota_btobb(src->d_rt_space);
+       dst->d_rtbtimer = src->d_rt_spc_timer;
+       dst->d_rtbwarns = src->d_rt_spc_warns;
 }
 
 static int quota_getxquota(struct super_block *sb, int type, qid_t id,
                           void __user *addr)
 {
        struct fs_disk_quota fdq;
+       struct qc_dqblk qdq;
        struct kqid qid;
        int ret;
 
@@ -275,8 +384,11 @@ static int quota_getxquota(struct super_block *sb, int type, qid_t id,
        qid = make_kqid(current_user_ns(), type, id);
        if (!qid_valid(qid))
                return -EINVAL;
-       ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
-       if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
+       ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
+       if (ret)
+               return ret;
+       copy_to_xfs_dqblk(&fdq, &qdq, type, id);
+       if (copy_to_user(addr, &fdq, sizeof(fdq)))
                return -EFAULT;
        return ret;
 }
index a012c51caffd2a195b6015b9594d0f1862dba324..05e90edd199214fd0507b5e5b79a3b60ea8a49d3 100644 (file)
@@ -57,6 +57,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
        sector_t offset;
        int i, num, ret = 0;
        struct extent_position epos = { NULL, 0, {0, 0} };
+       struct super_block *sb = dir->i_sb;
 
        if (ctx->pos == 0) {
                if (!dir_emit_dot(file, ctx))
@@ -76,16 +77,16 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
        if (nf_pos == 0)
                nf_pos = udf_ext0_offset(dir);
 
-       fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1);
+       fibh.soffset = fibh.eoffset = nf_pos & (sb->s_blocksize - 1);
        if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
-               if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
+               if (inode_bmap(dir, nf_pos >> sb->s_blocksize_bits,
                    &epos, &eloc, &elen, &offset)
                    != (EXT_RECORDED_ALLOCATED >> 30)) {
                        ret = -ENOENT;
                        goto out;
                }
-               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
-               if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+               block = udf_get_lb_pblock(sb, &eloc, offset);
+               if ((++offset << sb->s_blocksize_bits) < elen) {
                        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(struct short_ad);
                        else if (iinfo->i_alloc_type ==
@@ -95,18 +96,18 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
                        offset = 0;
                }
 
-               if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
+               if (!(fibh.sbh = fibh.ebh = udf_tread(sb, block))) {
                        ret = -EIO;
                        goto out;
                }
 
-               if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
-                       i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
-                       if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
-                               i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
+               if (!(offset & ((16 >> (sb->s_blocksize_bits - 9)) - 1))) {
+                       i = 16 >> (sb->s_blocksize_bits - 9);
+                       if (i + offset > (elen >> sb->s_blocksize_bits))
+                               i = (elen >> sb->s_blocksize_bits) - offset;
                        for (num = 0; i > 0; i--) {
-                               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset + i);
-                               tmp = udf_tgetblk(dir->i_sb, block);
+                               block = udf_get_lb_pblock(sb, &eloc, offset + i);
+                               tmp = udf_tgetblk(sb, block);
                                if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
                                        bha[num++] = tmp;
                                else
@@ -152,12 +153,12 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
                }
 
                if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
-                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
+                       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
                                continue;
                }
 
                if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
-                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
+                       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
                                continue;
                }
 
@@ -167,12 +168,12 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
                        continue;
                }
 
-               flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
+               flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
                if (!flen)
                        continue;
 
                tloc = lelb_to_cpu(cfi.icb.extLocation);
-               iblock = udf_get_lb_pblock(dir->i_sb, &tloc, 0);
+               iblock = udf_get_lb_pblock(sb, &tloc, 0);
                if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
                        goto out;
        } /* end while */
index bb15771b92ae32ae02390179492647a1d87c9dc2..08f3555fbeac3f6ceeda033cb8f6ec82557623d0 100644 (file)
@@ -224,7 +224,7 @@ out:
 static int udf_release_file(struct inode *inode, struct file *filp)
 {
        if (filp->f_mode & FMODE_WRITE &&
-           atomic_read(&inode->i_writecount) > 1) {
+           atomic_read(&inode->i_writecount) == 1) {
                /*
                 * Grab i_mutex to avoid races with writes changing i_size
                 * while we are running.
index c9b4df5810d52560b084b9557150faf8cfbe6e29..5bc71d9a674a7e5dfc3ff882ee61a2591a328c7b 100644 (file)
@@ -1489,6 +1489,20 @@ reread:
        }
        inode->i_generation = iinfo->i_unique;
 
+       /* Sanity checks for files in ICB so that we don't get confused later */
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               /*
+                * For file in ICB data is stored in allocation descriptor
+                * so sizes should match
+                */
+               if (iinfo->i_lenAlloc != inode->i_size)
+                       goto out;
+               /* File in ICB has to fit in there... */
+               if (inode->i_size > inode->i_sb->s_blocksize -
+                                       udf_file_entry_alloc_offset(inode))
+                       goto out;
+       }
+
        switch (fe->icbTag.fileType) {
        case ICBTAG_FILE_TYPE_DIRECTORY:
                inode->i_op = &udf_dir_inode_operations;
index c12e260fd6c417eb9c690782b8860f0e5eeff8d9..33b246b82c98510289d533fcdcbc59154d38589f 100644 (file)
@@ -159,18 +159,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
        struct udf_inode_info *dinfo = UDF_I(dir);
        int isdotdot = child->len == 2 &&
                child->name[0] == '.' && child->name[1] == '.';
+       struct super_block *sb = dir->i_sb;
 
        size = udf_ext0_offset(dir) + dir->i_size;
        f_pos = udf_ext0_offset(dir);
 
        fibh->sbh = fibh->ebh = NULL;
-       fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
+       fibh->soffset = fibh->eoffset = f_pos & (sb->s_blocksize - 1);
        if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
-               if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
+               if (inode_bmap(dir, f_pos >> sb->s_blocksize_bits, &epos,
                    &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
                        goto out_err;
-               block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
-               if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
+               block = udf_get_lb_pblock(sb, &eloc, offset);
+               if ((++offset << sb->s_blocksize_bits) < elen) {
                        if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
                                epos.offset -= sizeof(struct short_ad);
                        else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
@@ -178,7 +179,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
                } else
                        offset = 0;
 
-               fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
+               fibh->sbh = fibh->ebh = udf_tread(sb, block);
                if (!fibh->sbh)
                        goto out_err;
        }
@@ -217,12 +218,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
                }
 
                if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
-                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
+                       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
                                continue;
                }
 
                if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
-                       if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
+                       if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
                                continue;
                }
 
@@ -233,7 +234,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
                if (!lfi)
                        continue;
 
-               flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
+               flen = udf_get_filename(sb, nameptr, lfi, fname, UDF_NAME_LEN);
                if (flen && udf_match(flen, fname, child->len, child->name))
                        goto out_ok;
        }
index 6fb7945c1e6e8813afce2ad81aa41ea28a6f4565..ac10ca939f267283ba0f64da9d4ec82de0eeeb61 100644 (file)
 #include <linux/buffer_head.h>
 #include "udf_i.h"
 
-static void udf_pc_to_char(struct super_block *sb, unsigned char *from,
-                          int fromlen, unsigned char *to)
+static int udf_pc_to_char(struct super_block *sb, unsigned char *from,
+                         int fromlen, unsigned char *to, int tolen)
 {
        struct pathComponent *pc;
        int elen = 0;
+       int comp_len;
        unsigned char *p = to;
 
+       /* Reserve one byte for terminating \0 */
+       tolen--;
        while (elen < fromlen) {
                pc = (struct pathComponent *)(from + elen);
+               elen += sizeof(struct pathComponent);
                switch (pc->componentType) {
                case 1:
                        /*
                         * Symlink points to some place which should be agreed
                         * upon between originator and receiver of the media. Ignore.
                         */
-                       if (pc->lengthComponentIdent > 0)
+                       if (pc->lengthComponentIdent > 0) {
+                               elen += pc->lengthComponentIdent;
                                break;
+                       }
                        /* Fall through */
                case 2:
+                       if (tolen == 0)
+                               return -ENAMETOOLONG;
                        p = to;
                        *p++ = '/';
+                       tolen--;
                        break;
                case 3:
+                       if (tolen < 3)
+                               return -ENAMETOOLONG;
                        memcpy(p, "../", 3);
                        p += 3;
+                       tolen -= 3;
                        break;
                case 4:
+                       if (tolen < 2)
+                               return -ENAMETOOLONG;
                        memcpy(p, "./", 2);
                        p += 2;
+                       tolen -= 2;
                        /* that would be . - just ignore */
                        break;
                case 5:
-                       p += udf_get_filename(sb, pc->componentIdent, p,
-                                             pc->lengthComponentIdent);
+                       elen += pc->lengthComponentIdent;
+                       if (elen > fromlen)
+                               return -EIO;
+                       comp_len = udf_get_filename(sb, pc->componentIdent,
+                                                   pc->lengthComponentIdent,
+                                                   p, tolen);
+                       p += comp_len;
+                       tolen -= comp_len;
+                       if (tolen == 0)
+                               return -ENAMETOOLONG;
                        *p++ = '/';
+                       tolen--;
                        break;
                }
-               elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;
        }
        if (p > to + 1)
                p[-1] = '\0';
        else
                p[0] = '\0';
+       return 0;
 }
 
 static int udf_symlink_filler(struct file *file, struct page *page)
@@ -80,11 +104,17 @@ static int udf_symlink_filler(struct file *file, struct page *page)
        struct inode *inode = page->mapping->host;
        struct buffer_head *bh = NULL;
        unsigned char *symlink;
-       int err = -EIO;
+       int err;
        unsigned char *p = kmap(page);
        struct udf_inode_info *iinfo;
        uint32_t pos;
 
+       /* We don't support symlinks longer than one block */
+       if (inode->i_size > inode->i_sb->s_blocksize) {
+               err = -ENAMETOOLONG;
+               goto out_unmap;
+       }
+
        iinfo = UDF_I(inode);
        pos = udf_block_map(inode, 0);
 
@@ -94,14 +124,18 @@ static int udf_symlink_filler(struct file *file, struct page *page)
        } else {
                bh = sb_bread(inode->i_sb, pos);
 
-               if (!bh)
-                       goto out;
+               if (!bh) {
+                       err = -EIO;
+                       goto out_unlock_inode;
+               }
 
                symlink = bh->b_data;
        }
 
-       udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p);
+       err = udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p, PAGE_SIZE);
        brelse(bh);
+       if (err)
+               goto out_unlock_inode;
 
        up_read(&iinfo->i_data_sem);
        SetPageUptodate(page);
@@ -109,9 +143,10 @@ static int udf_symlink_filler(struct file *file, struct page *page)
        unlock_page(page);
        return 0;
 
-out:
+out_unlock_inode:
        up_read(&iinfo->i_data_sem);
        SetPageError(page);
+out_unmap:
        kunmap(page);
        unlock_page(page);
        return err;
index 1cc3c993ebd04f4adb7b425f500e40d1185aae9f..47bb3f5ca360d4f1be8f92036685278868ab99e3 100644 (file)
@@ -211,7 +211,8 @@ udf_get_lb_pblock(struct super_block *sb, struct kernel_lb_addr *loc,
 }
 
 /* unicode.c */
-extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int);
+extern int udf_get_filename(struct super_block *, uint8_t *, int, uint8_t *,
+                           int);
 extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *,
                            int);
 extern int udf_build_ustr(struct ustr *, dstring *, int);
index afd470e588ffbbd24ec886b3e8a619833a5e3e9a..b84fee372734bd494ba5eb86f5ce5c8c28b99b5a 100644 (file)
@@ -28,7 +28,8 @@
 
 #include "udf_sb.h"
 
-static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int);
+static int udf_translate_to_linux(uint8_t *, int, uint8_t *, int, uint8_t *,
+                                 int);
 
 static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen)
 {
@@ -333,8 +334,8 @@ try_again:
        return u_len + 1;
 }
 
-int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
-                    int flen)
+int udf_get_filename(struct super_block *sb, uint8_t *sname, int slen,
+                    uint8_t *dname, int dlen)
 {
        struct ustr *filename, *unifilename;
        int len = 0;
@@ -347,7 +348,7 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
        if (!unifilename)
                goto out1;
 
-       if (udf_build_ustr_exact(unifilename, sname, flen))
+       if (udf_build_ustr_exact(unifilename, sname, slen))
                goto out2;
 
        if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) {
@@ -366,7 +367,8 @@ int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname,
        } else
                goto out2;
 
-       len = udf_translate_to_linux(dname, filename->u_name, filename->u_len,
+       len = udf_translate_to_linux(dname, dlen,
+                                    filename->u_name, filename->u_len,
                                     unifilename->u_name, unifilename->u_len);
 out2:
        kfree(unifilename);
@@ -403,10 +405,12 @@ int udf_put_filename(struct super_block *sb, const uint8_t *sname,
 #define EXT_MARK               '.'
 #define CRC_MARK               '#'
 #define EXT_SIZE               5
+/* Number of chars we need to store generated CRC to make filename unique */
+#define CRC_LEN                        5
 
-static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
-                                 int udfLen, uint8_t *fidName,
-                                 int fidNameLen)
+static int udf_translate_to_linux(uint8_t *newName, int newLen,
+                                 uint8_t *udfName, int udfLen,
+                                 uint8_t *fidName, int fidNameLen)
 {
        int index, newIndex = 0, needsCRC = 0;
        int extIndex = 0, newExtIndex = 0, hasExt = 0;
@@ -439,7 +443,7 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
                                        newExtIndex = newIndex;
                                }
                        }
-                       if (newIndex < 256)
+                       if (newIndex < newLen)
                                newName[newIndex++] = curr;
                        else
                                needsCRC = 1;
@@ -467,13 +471,13 @@ static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName,
                                }
                                ext[localExtIndex++] = curr;
                        }
-                       maxFilenameLen = 250 - localExtIndex;
+                       maxFilenameLen = newLen - CRC_LEN - localExtIndex;
                        if (newIndex > maxFilenameLen)
                                newIndex = maxFilenameLen;
                        else
                                newIndex = newExtIndex;
-               } else if (newIndex > 250)
-                       newIndex = 250;
+               } else if (newIndex > newLen - CRC_LEN)
+                       newIndex = newLen - CRC_LEN;
                newName[newIndex++] = CRC_MARK;
                valueCRC = crc_itu_t(0, fidName, fidNameLen);
                newName[newIndex++] = hex_asc_upper_hi(valueCRC >> 8);
index 3a07a937e232a7e51bf089f981a664f782f5a75f..41f6c0b9d51cd3dc3d8b22b2fe37fcf78cd064bf 100644 (file)
@@ -166,9 +166,9 @@ extern void         xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint);
 /* quota ops */
 extern int             xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint);
 extern int             xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t,
-                                       uint, struct fs_disk_quota *);
+                                       uint, struct qc_dqblk *);
 extern int             xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
-                                       struct fs_disk_quota *);
+                                       struct qc_dqblk *);
 extern int             xfs_qm_scall_getqstat(struct xfs_mount *,
                                        struct fs_quota_stat *);
 extern int             xfs_qm_scall_getqstatv(struct xfs_mount *,
index 74fca68e43b6b4e98a0d203204d4ce2f646ff8fa..cb6168ec92c9e0763640d5cc4eeff12fc89f6ef0 100644 (file)
@@ -39,7 +39,6 @@ STATIC int    xfs_qm_log_quotaoff(xfs_mount_t *, xfs_qoff_logitem_t **, uint);
 STATIC int     xfs_qm_log_quotaoff_end(xfs_mount_t *, xfs_qoff_logitem_t *,
                                        uint);
 STATIC uint    xfs_qm_export_flags(uint);
-STATIC uint    xfs_qm_export_qtype_flags(uint);
 
 /*
  * Turn off quota accounting and/or enforcement for all udquots and/or
@@ -573,8 +572,8 @@ xfs_qm_scall_getqstatv(
        return 0;
 }
 
-#define XFS_DQ_MASK \
-       (FS_DQ_LIMIT_MASK | FS_DQ_TIMER_MASK | FS_DQ_WARNS_MASK)
+#define XFS_QC_MASK \
+       (QC_LIMIT_MASK | QC_TIMER_MASK | QC_WARNS_MASK)
 
 /*
  * Adjust quota limits, and start/stop timers accordingly.
@@ -584,7 +583,7 @@ xfs_qm_scall_setqlim(
        struct xfs_mount        *mp,
        xfs_dqid_t              id,
        uint                    type,
-       fs_disk_quota_t         *newlim)
+       struct qc_dqblk         *newlim)
 {
        struct xfs_quotainfo    *q = mp->m_quotainfo;
        struct xfs_disk_dquot   *ddq;
@@ -593,9 +592,9 @@ xfs_qm_scall_setqlim(
        int                     error;
        xfs_qcnt_t              hard, soft;
 
-       if (newlim->d_fieldmask & ~XFS_DQ_MASK)
+       if (newlim->d_fieldmask & ~XFS_QC_MASK)
                return -EINVAL;
-       if ((newlim->d_fieldmask & XFS_DQ_MASK) == 0)
+       if ((newlim->d_fieldmask & XFS_QC_MASK) == 0)
                return 0;
 
        /*
@@ -633,11 +632,11 @@ xfs_qm_scall_setqlim(
        /*
         * Make sure that hardlimits are >= soft limits before changing.
         */
-       hard = (newlim->d_fieldmask & FS_DQ_BHARD) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) :
+       hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
+               (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
                        be64_to_cpu(ddq->d_blk_hardlimit);
-       soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) :
+       soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
+               (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
                        be64_to_cpu(ddq->d_blk_softlimit);
        if (hard == 0 || hard >= soft) {
                ddq->d_blk_hardlimit = cpu_to_be64(hard);
@@ -650,11 +649,11 @@ xfs_qm_scall_setqlim(
        } else {
                xfs_debug(mp, "blkhard %Ld < blksoft %Ld", hard, soft);
        }
-       hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) :
+       hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
+               (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
                        be64_to_cpu(ddq->d_rtb_hardlimit);
-       soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ?
-               (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) :
+       soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
+               (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
                        be64_to_cpu(ddq->d_rtb_softlimit);
        if (hard == 0 || hard >= soft) {
                ddq->d_rtb_hardlimit = cpu_to_be64(hard);
@@ -667,10 +666,10 @@ xfs_qm_scall_setqlim(
                xfs_debug(mp, "rtbhard %Ld < rtbsoft %Ld", hard, soft);
        }
 
-       hard = (newlim->d_fieldmask & FS_DQ_IHARD) ?
+       hard = (newlim->d_fieldmask & QC_INO_HARD) ?
                (xfs_qcnt_t) newlim->d_ino_hardlimit :
                        be64_to_cpu(ddq->d_ino_hardlimit);
-       soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ?
+       soft = (newlim->d_fieldmask & QC_INO_SOFT) ?
                (xfs_qcnt_t) newlim->d_ino_softlimit :
                        be64_to_cpu(ddq->d_ino_softlimit);
        if (hard == 0 || hard >= soft) {
@@ -687,12 +686,12 @@ xfs_qm_scall_setqlim(
        /*
         * Update warnings counter(s) if requested
         */
-       if (newlim->d_fieldmask & FS_DQ_BWARNS)
-               ddq->d_bwarns = cpu_to_be16(newlim->d_bwarns);
-       if (newlim->d_fieldmask & FS_DQ_IWARNS)
-               ddq->d_iwarns = cpu_to_be16(newlim->d_iwarns);
-       if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
-               ddq->d_rtbwarns = cpu_to_be16(newlim->d_rtbwarns);
+       if (newlim->d_fieldmask & QC_SPC_WARNS)
+               ddq->d_bwarns = cpu_to_be16(newlim->d_spc_warns);
+       if (newlim->d_fieldmask & QC_INO_WARNS)
+               ddq->d_iwarns = cpu_to_be16(newlim->d_ino_warns);
+       if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
+               ddq->d_rtbwarns = cpu_to_be16(newlim->d_rt_spc_warns);
 
        if (id == 0) {
                /*
@@ -702,24 +701,24 @@ xfs_qm_scall_setqlim(
                 * soft and hard limit values (already done, above), and
                 * for warnings.
                 */
-               if (newlim->d_fieldmask & FS_DQ_BTIMER) {
-                       q->qi_btimelimit = newlim->d_btimer;
-                       ddq->d_btimer = cpu_to_be32(newlim->d_btimer);
+               if (newlim->d_fieldmask & QC_SPC_TIMER) {
+                       q->qi_btimelimit = newlim->d_spc_timer;
+                       ddq->d_btimer = cpu_to_be32(newlim->d_spc_timer);
                }
-               if (newlim->d_fieldmask & FS_DQ_ITIMER) {
-                       q->qi_itimelimit = newlim->d_itimer;
-                       ddq->d_itimer = cpu_to_be32(newlim->d_itimer);
+               if (newlim->d_fieldmask & QC_INO_TIMER) {
+                       q->qi_itimelimit = newlim->d_ino_timer;
+                       ddq->d_itimer = cpu_to_be32(newlim->d_ino_timer);
                }
-               if (newlim->d_fieldmask & FS_DQ_RTBTIMER) {
-                       q->qi_rtbtimelimit = newlim->d_rtbtimer;
-                       ddq->d_rtbtimer = cpu_to_be32(newlim->d_rtbtimer);
+               if (newlim->d_fieldmask & QC_RT_SPC_TIMER) {
+                       q->qi_rtbtimelimit = newlim->d_rt_spc_timer;
+                       ddq->d_rtbtimer = cpu_to_be32(newlim->d_rt_spc_timer);
                }
-               if (newlim->d_fieldmask & FS_DQ_BWARNS)
-                       q->qi_bwarnlimit = newlim->d_bwarns;
-               if (newlim->d_fieldmask & FS_DQ_IWARNS)
-                       q->qi_iwarnlimit = newlim->d_iwarns;
-               if (newlim->d_fieldmask & FS_DQ_RTBWARNS)
-                       q->qi_rtbwarnlimit = newlim->d_rtbwarns;
+               if (newlim->d_fieldmask & QC_SPC_WARNS)
+                       q->qi_bwarnlimit = newlim->d_spc_warns;
+               if (newlim->d_fieldmask & QC_INO_WARNS)
+                       q->qi_iwarnlimit = newlim->d_ino_warns;
+               if (newlim->d_fieldmask & QC_RT_SPC_WARNS)
+                       q->qi_rtbwarnlimit = newlim->d_rt_spc_warns;
        } else {
                /*
                 * If the user is now over quota, start the timelimit.
@@ -824,7 +823,7 @@ xfs_qm_scall_getquota(
        struct xfs_mount        *mp,
        xfs_dqid_t              id,
        uint                    type,
-       struct fs_disk_quota    *dst)
+       struct qc_dqblk         *dst)
 {
        struct xfs_dquot        *dqp;
        int                     error;
@@ -848,28 +847,25 @@ xfs_qm_scall_getquota(
        }
 
        memset(dst, 0, sizeof(*dst));
-       dst->d_version = FS_DQUOT_VERSION;
-       dst->d_flags = xfs_qm_export_qtype_flags(dqp->q_core.d_flags);
-       dst->d_id = be32_to_cpu(dqp->q_core.d_id);
-       dst->d_blk_hardlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
-       dst->d_blk_softlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_blk_softlimit));
+       dst->d_spc_hardlimit =
+               XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_hardlimit));
+       dst->d_spc_softlimit =
+               XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_blk_softlimit));
        dst->d_ino_hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit);
        dst->d_ino_softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit);
-       dst->d_bcount = XFS_FSB_TO_BB(mp, dqp->q_res_bcount);
-       dst->d_icount = dqp->q_res_icount;
-       dst->d_btimer = be32_to_cpu(dqp->q_core.d_btimer);
-       dst->d_itimer = be32_to_cpu(dqp->q_core.d_itimer);
-       dst->d_iwarns = be16_to_cpu(dqp->q_core.d_iwarns);
-       dst->d_bwarns = be16_to_cpu(dqp->q_core.d_bwarns);
-       dst->d_rtb_hardlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
-       dst->d_rtb_softlimit =
-               XFS_FSB_TO_BB(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
-       dst->d_rtbcount = XFS_FSB_TO_BB(mp, dqp->q_res_rtbcount);
-       dst->d_rtbtimer = be32_to_cpu(dqp->q_core.d_rtbtimer);
-       dst->d_rtbwarns = be16_to_cpu(dqp->q_core.d_rtbwarns);
+       dst->d_space = XFS_FSB_TO_B(mp, dqp->q_res_bcount);
+       dst->d_ino_count = dqp->q_res_icount;
+       dst->d_spc_timer = be32_to_cpu(dqp->q_core.d_btimer);
+       dst->d_ino_timer = be32_to_cpu(dqp->q_core.d_itimer);
+       dst->d_ino_warns = be16_to_cpu(dqp->q_core.d_iwarns);
+       dst->d_spc_warns = be16_to_cpu(dqp->q_core.d_bwarns);
+       dst->d_rt_spc_hardlimit =
+               XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_hardlimit));
+       dst->d_rt_spc_softlimit =
+               XFS_FSB_TO_B(mp, be64_to_cpu(dqp->q_core.d_rtb_softlimit));
+       dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_res_rtbcount);
+       dst->d_rt_spc_timer = be32_to_cpu(dqp->q_core.d_rtbtimer);
+       dst->d_rt_spc_warns = be16_to_cpu(dqp->q_core.d_rtbwarns);
 
        /*
         * Internally, we don't reset all the timers when quota enforcement
@@ -882,23 +878,23 @@ xfs_qm_scall_getquota(
             dqp->q_core.d_flags == XFS_DQ_GROUP) ||
            (!XFS_IS_PQUOTA_ENFORCED(mp) &&
             dqp->q_core.d_flags == XFS_DQ_PROJ)) {
-               dst->d_btimer = 0;
-               dst->d_itimer = 0;
-               dst->d_rtbtimer = 0;
+               dst->d_spc_timer = 0;
+               dst->d_ino_timer = 0;
+               dst->d_rt_spc_timer = 0;
        }
 
 #ifdef DEBUG
-       if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
-            (XFS_IS_GQUOTA_ENFORCED(mp) && dst->d_flags == FS_GROUP_QUOTA) ||
-            (XFS_IS_PQUOTA_ENFORCED(mp) && dst->d_flags == FS_PROJ_QUOTA)) &&
-           dst->d_id != 0) {
-               if ((dst->d_bcount > dst->d_blk_softlimit) &&
-                   (dst->d_blk_softlimit > 0)) {
-                       ASSERT(dst->d_btimer != 0);
+       if (((XFS_IS_UQUOTA_ENFORCED(mp) && type == XFS_DQ_USER) ||
+            (XFS_IS_GQUOTA_ENFORCED(mp) && type == XFS_DQ_GROUP) ||
+            (XFS_IS_PQUOTA_ENFORCED(mp) && type == XFS_DQ_PROJ)) &&
+           id != 0) {
+               if ((dst->d_space > dst->d_spc_softlimit) &&
+                   (dst->d_spc_softlimit > 0)) {
+                       ASSERT(dst->d_spc_timer != 0);
                }
-               if ((dst->d_icount > dst->d_ino_softlimit) &&
+               if ((dst->d_ino_count > dst->d_ino_softlimit) &&
                    (dst->d_ino_softlimit > 0)) {
-                       ASSERT(dst->d_itimer != 0);
+                       ASSERT(dst->d_ino_timer != 0);
                }
        }
 #endif
@@ -907,26 +903,6 @@ out_put:
        return error;
 }
 
-STATIC uint
-xfs_qm_export_qtype_flags(
-       uint flags)
-{
-       /*
-        * Can't be more than one, or none.
-        */
-       ASSERT((flags & (FS_PROJ_QUOTA | FS_USER_QUOTA)) !=
-               (FS_PROJ_QUOTA | FS_USER_QUOTA));
-       ASSERT((flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)) !=
-               (FS_PROJ_QUOTA | FS_GROUP_QUOTA));
-       ASSERT((flags & (FS_USER_QUOTA | FS_GROUP_QUOTA)) !=
-               (FS_USER_QUOTA | FS_GROUP_QUOTA));
-       ASSERT((flags & (FS_PROJ_QUOTA|FS_USER_QUOTA|FS_GROUP_QUOTA)) != 0);
-
-       return (flags & XFS_DQ_USER) ?
-               FS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
-                       FS_PROJ_QUOTA : FS_GROUP_QUOTA;
-}
-
 STATIC uint
 xfs_qm_export_flags(
        uint flags)
index 7542bbeca6a12b18ae1162a51a8dd97f6c35790e..801a84c1cdc3c76d86ae413cf4a1dfddd89cdc92 100644 (file)
@@ -131,7 +131,7 @@ STATIC int
 xfs_fs_get_dqblk(
        struct super_block      *sb,
        struct kqid             qid,
-       struct fs_disk_quota    *fdq)
+       struct qc_dqblk         *qdq)
 {
        struct xfs_mount        *mp = XFS_M(sb);
 
@@ -141,14 +141,14 @@ xfs_fs_get_dqblk(
                return -ESRCH;
 
        return xfs_qm_scall_getquota(mp, from_kqid(&init_user_ns, qid),
-                                     xfs_quota_type(qid.type), fdq);
+                                     xfs_quota_type(qid.type), qdq);
 }
 
 STATIC int
 xfs_fs_set_dqblk(
        struct super_block      *sb,
        struct kqid             qid,
-       struct fs_disk_quota    *fdq)
+       struct qc_dqblk         *qdq)
 {
        struct xfs_mount        *mp = XFS_M(sb);
 
@@ -160,7 +160,7 @@ xfs_fs_set_dqblk(
                return -ESRCH;
 
        return xfs_qm_scall_setqlim(mp, from_kqid(&init_user_ns, qid),
-                                    xfs_quota_type(qid.type), fdq);
+                                    xfs_quota_type(qid.type), qdq);
 }
 
 const struct quotactl_ops xfs_quotactl_operations = {
index 3ca9b751f1224cfd9a6816ebebe38d7559c7bcd0..b95dc32a6e6b61aefac9fefce83c6a3da20fa111 100644 (file)
@@ -196,8 +196,8 @@ struct acpi_processor_flags {
 struct acpi_processor {
        acpi_handle handle;
        u32 acpi_id;
-       u32 apic_id;
-       u32 id;
+       u32 phys_id;    /* CPU hardware ID such as APIC ID for x86 */
+       u32 id;         /* CPU logical ID allocated by OS */
        u32 pblk;
        int performance_platform_limit;
        int throttling_platform_limit;
@@ -310,8 +310,8 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
 #endif                         /* CONFIG_CPU_FREQ */
 
 /* in processor_core.c */
-int acpi_get_apicid(acpi_handle, int type, u32 acpi_id);
-int acpi_map_cpuid(int apic_id, u32 acpi_id);
+int acpi_get_phys_id(acpi_handle, int type, u32 acpi_id);
+int acpi_map_cpuid(int phys_id, u32 acpi_id);
 int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
 
 /* in processor_pdc.c */
index 08848050922e613f28a1d8f7e4b3ad4c34b463be..db284bff29dcceb39360d458cec3a194745955f8 100644 (file)
@@ -136,8 +136,12 @@ static inline void __tlb_adjust_range(struct mmu_gather *tlb,
 
 static inline void __tlb_reset_range(struct mmu_gather *tlb)
 {
-       tlb->start = TASK_SIZE;
-       tlb->end = 0;
+       if (tlb->fullmm) {
+               tlb->start = tlb->end = ~0;
+       } else {
+               tlb->start = TASK_SIZE;
+               tlb->end = 0;
+       }
 }
 
 /*
index 8ba35c622e2202a889a3a06706bdc93e035fb841..e1b2e8b98af7cde2c7276e915cd90ea4794b317e 100644 (file)
@@ -901,11 +901,15 @@ extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
 extern int drm_wait_vblank(struct drm_device *dev, void *data,
                           struct drm_file *filp);
 extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
+extern u32 drm_crtc_vblank_count(struct drm_crtc *crtc);
 extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
                                     struct timeval *vblanktime);
 extern void drm_send_vblank_event(struct drm_device *dev, int crtc,
                                     struct drm_pending_vblank_event *e);
+extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
+                                      struct drm_pending_vblank_event *e);
 extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
+extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
 extern int drm_vblank_get(struct drm_device *dev, int crtc);
 extern void drm_vblank_put(struct drm_device *dev, int crtc);
 extern int drm_crtc_vblank_get(struct drm_crtc *crtc);
index 780511a459c01e3012efbfe2912ee27dc5996971..1e6ae1458f7ab98ef42cd66ef9834cef8f276718 100644 (file)
@@ -119,13 +119,6 @@ struct drm_gem_object {
         * simply leave it as NULL.
         */
        struct dma_buf_attachment *import_attach;
-
-       /**
-        * dumb - created as dumb buffer
-        * Whether the gem object was created using the dumb buffer interface
-        * as such it may not be used for GPU rendering.
-        */
-       bool dumb;
 };
 
 void drm_gem_object_release(struct drm_gem_object *obj);
index 1ea1b702fec2c49f5ca8d7443df6933ec88da175..d4110d5caa3efde4e0b44402ed8d4d8a00aed6cc 100644 (file)
@@ -7,14 +7,14 @@
 
 #include <dt-bindings/interrupt-controller/irq.h>
 
-/* interrupt specific cell 0 */
+/* interrupt specifier cell 0 */
 
 #define GIC_SPI 0
 #define GIC_PPI 1
 
 /*
  * Interrupt specifier cell 2.
- * The flaggs in irq.h are valid, plus those below.
+ * The flags in irq.h are valid, plus those below.
  */
 #define GIC_CPU_MASK_RAW(x) ((x) << 8)
 #define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1)
diff --git a/include/dt-bindings/sound/samsung-i2s.h b/include/dt-bindings/sound/samsung-i2s.h
new file mode 100644 (file)
index 0000000..0c69818
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _DT_BINDINGS_SAMSUNG_I2S_H
+#define _DT_BINDINGS_SAMSUNG_I2S_H
+
+#define CLK_I2S_CDCLK          0
+#define CLK_I2S_RCLK_SRC       1
+#define CLK_I2S_RCLK_PSR       2
+
+#endif /* _DT_BINDINGS_SAMSUNG_I2S_H */
index 59822a9958581dc5a1871ec3bc02c756656a836e..b5e6b0069ac7703b927a0c040ffcbd764c1afd89 100644 (file)
@@ -11,7 +11,7 @@
 #define _DT_BINDINGS_THERMAL_THERMAL_H
 
 /* On cooling devices upper and lower limits */
-#define THERMAL_NO_LIMIT               (-1UL)
+#define THERMAL_NO_LIMIT               (~0)
 
 #endif
 
index 856d381b1d5b83ce923be0f5d7da80ba420c1d14..d459cd17b477600cadf54ad2a227b66c5638112f 100644 (file)
@@ -147,8 +147,8 @@ void acpi_numa_arch_fixup(void);
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 /* Arch dependent functions for cpu hotplug support */
-int acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu);
-int acpi_unmap_lsapic(int cpu);
+int acpi_map_cpu(acpi_handle handle, int physid, int *pcpu);
+int acpi_unmap_cpu(int cpu);
 #endif /* CONFIG_ACPI_HOTPLUG_CPU */
 
 int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
index 0c04917c2f1297f0a013e32fe6e3cf380b967d3a..af84234e1f6e2f3741ccb42f1a89e325f17749e8 100644 (file)
@@ -47,6 +47,7 @@ struct sk_buff;
 
 struct audit_krule {
        int                     vers_ops;
+       u32                     pflags;
        u32                     flags;
        u32                     listnr;
        u32                     action;
@@ -64,6 +65,9 @@ struct audit_krule {
        u64                     prio;
 };
 
+/* Flag to indicate legacy AUDIT_LOGINUID unset usage */
+#define AUDIT_LOGINUID_LEGACY          0x1
+
 struct audit_field {
        u32                             type;
        union {
index 8aded9ab2e4e89ddb66e5920c0819bade6fb0760..5735e7130d630f94fe62d3e0a7a7078434c8ee12 100644 (file)
@@ -34,7 +34,6 @@ struct blk_mq_hw_ctx {
        unsigned long           flags;          /* BLK_MQ_F_* flags */
 
        struct request_queue    *queue;
-       unsigned int            queue_num;
        struct blk_flush_queue  *fq;
 
        void                    *driver_data;
@@ -54,7 +53,7 @@ struct blk_mq_hw_ctx {
        unsigned long           dispatched[BLK_MQ_MAX_DISPATCH_ORDER];
 
        unsigned int            numa_node;
-       unsigned int            cmd_size;       /* per-request extra data */
+       unsigned int            queue_num;
 
        atomic_t                nr_active;
 
@@ -195,13 +194,16 @@ static inline u16 blk_mq_unique_tag_to_tag(u32 unique_tag)
 struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_index);
 struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *, unsigned int, int);
 
+int blk_mq_request_started(struct request *rq);
 void blk_mq_start_request(struct request *rq);
 void blk_mq_end_request(struct request *rq, int error);
 void __blk_mq_end_request(struct request *rq, int error);
 
 void blk_mq_requeue_request(struct request *rq);
 void blk_mq_add_to_requeue_list(struct request *rq, bool at_head);
+void blk_mq_cancel_requeue_work(struct request_queue *q);
 void blk_mq_kick_requeue_list(struct request_queue *q);
+void blk_mq_abort_requeue_list(struct request_queue *q);
 void blk_mq_complete_request(struct request *rq);
 
 void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx);
@@ -212,6 +214,8 @@ void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async);
 void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs);
 void blk_mq_tag_busy_iter(struct blk_mq_hw_ctx *hctx, busy_iter_fn *fn,
                void *priv);
+void blk_mq_unfreeze_queue(struct request_queue *q);
+void blk_mq_freeze_queue_start(struct request_queue *q);
 
 /*
  * Driver command data is immediately after the request. So subtract request
index 445d59231bc4cc242e2aa0e1ca073e3c320af56c..c294e3e25e37a50a953a4a0bb3cb1aa66ba904d9 100644 (file)
@@ -190,6 +190,7 @@ enum rq_flag_bits {
        __REQ_PM,               /* runtime pm request */
        __REQ_HASHED,           /* on IO scheduler merge hash */
        __REQ_MQ_INFLIGHT,      /* track inflight for MQ */
+       __REQ_NO_TIMEOUT,       /* requests may never expire */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -243,5 +244,6 @@ enum rq_flag_bits {
 #define REQ_PM                 (1ULL << __REQ_PM)
 #define REQ_HASHED             (1ULL << __REQ_HASHED)
 #define REQ_MQ_INFLIGHT                (1ULL << __REQ_MQ_INFLIGHT)
+#define REQ_NO_TIMEOUT         (1ULL << __REQ_NO_TIMEOUT)
 
 #endif /* __LINUX_BLK_TYPES_H */
index 5d86416d35f2223da40fae9e9fd8e312d365026b..61b19c46bdb33d5fc2f4752df0c345350fa739e8 100644 (file)
@@ -87,8 +87,8 @@ struct ceph_osd_req_op {
                        struct ceph_osd_data osd_data;
                } extent;
                struct {
-                       __le32 name_len;
-                       __le32 value_len;
+                       u32 name_len;
+                       u32 value_len;
                        __u8 cmp_op;       /* CEPH_OSD_CMPXATTR_OP_* */
                        __u8 cmp_mode;     /* CEPH_OSD_CMPXATTR_MODE_* */
                        struct ceph_osd_data osd_data;
index a1c81f80978ee4b38bbbb1cdd781c7afa0362c5e..33063f872ee3cd698a233a0f0defa67aa1b6bd01 100644 (file)
@@ -215,7 +215,7 @@ static __always_inline void __read_once_size(volatile void *p, void *res, int si
        }
 }
 
-static __always_inline void __assign_once_size(volatile void *p, void *res, int size)
+static __always_inline void __write_once_size(volatile void *p, void *res, int size)
 {
        switch (size) {
        case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
@@ -235,15 +235,15 @@ static __always_inline void __assign_once_size(volatile void *p, void *res, int
 /*
  * Prevent the compiler from merging or refetching reads or writes. The
  * compiler is also forbidden from reordering successive instances of
- * READ_ONCE, ASSIGN_ONCE and ACCESS_ONCE (see below), but only when the
+ * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the
  * compiler is aware of some particular ordering.  One way to make the
  * compiler aware of ordering is to put the two invocations of READ_ONCE,
- * ASSIGN_ONCE or ACCESS_ONCE() in different C statements.
+ * WRITE_ONCE or ACCESS_ONCE() in different C statements.
  *
  * In contrast to ACCESS_ONCE these two macros will also work on aggregate
  * data types like structs or unions. If the size of the accessed data
  * type exceeds the word size of the machine (e.g., 32 bits or 64 bits)
- * READ_ONCE() and ASSIGN_ONCE()  will fall back to memcpy and print a
+ * READ_ONCE() and WRITE_ONCE()  will fall back to memcpy and print a
  * compile-time warning.
  *
  * Their two major use cases are: (1) Mediating communication between
@@ -257,8 +257,8 @@ static __always_inline void __assign_once_size(volatile void *p, void *res, int
 #define READ_ONCE(x) \
        ({ typeof(x) __val; __read_once_size(&x, &__val, sizeof(__val)); __val; })
 
-#define ASSIGN_ONCE(val, x) \
-       ({ typeof(x) __val; __val = val; __assign_once_size(&x, &__val, sizeof(__val)); __val; })
+#define WRITE_ONCE(x, val) \
+       ({ typeof(x) __val; __val = val; __write_once_size(&x, &__val, sizeof(__val)); __val; })
 
 #endif /* __KERNEL__ */
 
index c303d383def1146589a30c980d2c8dadd1bd89cc..bd955270d5aae60f77cc8f936a5820d9690ac6ac 100644 (file)
@@ -50,7 +50,7 @@ static inline struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct device_node *np,
                            const struct cpumask *clip_cpus)
 {
-       return NULL;
+       return ERR_PTR(-ENOSYS);
 }
 #endif
 
@@ -65,13 +65,13 @@ unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq);
 static inline struct thermal_cooling_device *
 cpufreq_cooling_register(const struct cpumask *clip_cpus)
 {
-       return NULL;
+       return ERR_PTR(-ENOSYS);
 }
 static inline struct thermal_cooling_device *
 of_cpufreq_cooling_register(struct device_node *np,
                            const struct cpumask *clip_cpus)
 {
-       return NULL;
+       return ERR_PTR(-ENOSYS);
 }
 static inline
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
index a07e087f54b205741da6c126d0ca2144257140af..ab70f3bc44ad7a2c1ddf2454dac51f7a80e95f41 100644 (file)
@@ -53,7 +53,6 @@ struct cpuidle_state {
 };
 
 /* Idle State Flags */
-#define CPUIDLE_FLAG_TIME_INVALID      (0x01) /* is residency time measurable? */
 #define CPUIDLE_FLAG_COUPLED   (0x02) /* state applies to multiple cpus */
 #define CPUIDLE_FLAG_TIMER_STOP (0x04)  /* timer is stopped on this state */
 
@@ -89,8 +88,6 @@ DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev);
 /**
  * cpuidle_get_last_residency - retrieves the last state's residency time
  * @dev: the target CPU
- *
- * NOTE: this value is invalid if CPUIDLE_FLAG_TIME_INVALID is set
  */
 static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
 {
index f90c0282c11493f94a84095f61db94ac90974cc4..42efe13077b6c1b8dd139c6cea7a241e5d6b320d 100644 (file)
@@ -135,7 +135,7 @@ typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 #define FMODE_CAN_WRITE         ((__force fmode_t)0x40000)
 
 /* File was opened by fanotify and shouldn't generate fanotify events */
-#define FMODE_NONOTIFY         ((__force fmode_t)0x1000000)
+#define FMODE_NONOTIFY         ((__force fmode_t)0x4000000)
 
 /*
  * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
index 55b685719d522da32a37ba59013d1f029ff6a37e..09460d6d668208e3e4997b42f6dca05d0ef917a8 100644 (file)
@@ -11,6 +11,10 @@ extern void genl_unlock(void);
 extern int lockdep_genl_is_held(void);
 #endif
 
+/* for synchronisation between af_netlink and genetlink */
+extern atomic_t genl_sk_destructing_cnt;
+extern wait_queue_head_t genl_sk_destructing_waitq;
+
 /**
  * rcu_dereference_genl - rcu_dereference with debug checking
  * @p: The pointer to read, prior to dereferencing
index e3a1721c8354b98d6c613d536e4704ff52fa18d4..7c7695940dddeae9d3d22129ce4a14eaf70e1a5e 100644 (file)
@@ -228,7 +228,9 @@ struct i2c_client {
        struct device dev;              /* the device structure         */
        int irq;                        /* irq issued by device         */
        struct list_head detected;
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
        i2c_slave_cb_t slave_cb;        /* callback for slave mode      */
+#endif
 };
 #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
 
@@ -253,6 +255,7 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
 
 /* I2C slave support */
 
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
 enum i2c_slave_event {
        I2C_SLAVE_REQ_READ_START,
        I2C_SLAVE_REQ_READ_END,
@@ -269,6 +272,7 @@ static inline int i2c_slave_event(struct i2c_client *client,
 {
        return client->slave_cb(client, event, val);
 }
+#endif
 
 /**
  * struct i2c_board_info - template for device creation
@@ -404,8 +408,10 @@ struct i2c_algorithm {
        /* To determine what the adapter supports */
        u32 (*functionality) (struct i2c_adapter *);
 
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
        int (*reg_slave)(struct i2c_client *client);
        int (*unreg_slave)(struct i2c_client *client);
+#endif
 };
 
 /**
index 290db1269c4c7970ab016165c62d93eec53059b4..75ae2e2631fceaa27915f3d100b1f03244b17500 100644 (file)
  * Copyright (C) 2009 Jason Wessel <jason.wessel@windriver.com>
  */
 
+/* Shifted versions of the command enable bits are be used if the command
+ * has no arguments (see kdb_check_flags). This allows commands, such as
+ * go, to have different permissions depending upon whether it is called
+ * with an argument.
+ */
+#define KDB_ENABLE_NO_ARGS_SHIFT 10
+
 typedef enum {
-       KDB_REPEAT_NONE = 0,    /* Do not repeat this command */
-       KDB_REPEAT_NO_ARGS,     /* Repeat the command without arguments */
-       KDB_REPEAT_WITH_ARGS,   /* Repeat the command including its arguments */
-} kdb_repeat_t;
+       KDB_ENABLE_ALL = (1 << 0), /* Enable everything */
+       KDB_ENABLE_MEM_READ = (1 << 1),
+       KDB_ENABLE_MEM_WRITE = (1 << 2),
+       KDB_ENABLE_REG_READ = (1 << 3),
+       KDB_ENABLE_REG_WRITE = (1 << 4),
+       KDB_ENABLE_INSPECT = (1 << 5),
+       KDB_ENABLE_FLOW_CTRL = (1 << 6),
+       KDB_ENABLE_SIGNAL = (1 << 7),
+       KDB_ENABLE_REBOOT = (1 << 8),
+       /* User exposed values stop here, all remaining flags are
+        * exclusively used to describe a commands behaviour.
+        */
+
+       KDB_ENABLE_ALWAYS_SAFE = (1 << 9),
+       KDB_ENABLE_MASK = (1 << KDB_ENABLE_NO_ARGS_SHIFT) - 1,
+
+       KDB_ENABLE_ALL_NO_ARGS = KDB_ENABLE_ALL << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_MEM_READ_NO_ARGS = KDB_ENABLE_MEM_READ
+                                     << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_MEM_WRITE_NO_ARGS = KDB_ENABLE_MEM_WRITE
+                                      << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_REG_READ_NO_ARGS = KDB_ENABLE_REG_READ
+                                     << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_REG_WRITE_NO_ARGS = KDB_ENABLE_REG_WRITE
+                                      << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_INSPECT_NO_ARGS = KDB_ENABLE_INSPECT
+                                    << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_FLOW_CTRL_NO_ARGS = KDB_ENABLE_FLOW_CTRL
+                                      << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_SIGNAL_NO_ARGS = KDB_ENABLE_SIGNAL
+                                   << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_REBOOT_NO_ARGS = KDB_ENABLE_REBOOT
+                                   << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_ALWAYS_SAFE_NO_ARGS = KDB_ENABLE_ALWAYS_SAFE
+                                        << KDB_ENABLE_NO_ARGS_SHIFT,
+       KDB_ENABLE_MASK_NO_ARGS = KDB_ENABLE_MASK << KDB_ENABLE_NO_ARGS_SHIFT,
+
+       KDB_REPEAT_NO_ARGS = 0x40000000, /* Repeat the command w/o arguments */
+       KDB_REPEAT_WITH_ARGS = 0x80000000, /* Repeat the command with args */
+} kdb_cmdflags_t;
 
 typedef int (*kdb_func_t)(int, const char **);
 
@@ -62,6 +105,7 @@ extern atomic_t kdb_event;
 #define KDB_BADLENGTH  (-19)
 #define KDB_NOBP       (-20)
 #define KDB_BADADDR    (-21)
+#define KDB_NOPERM     (-22)
 
 /*
  * kdb_diemsg
@@ -146,17 +190,17 @@ static inline const char *kdb_walk_kallsyms(loff_t *pos)
 
 /* Dynamic kdb shell command registration */
 extern int kdb_register(char *, kdb_func_t, char *, char *, short);
-extern int kdb_register_repeat(char *, kdb_func_t, char *, char *,
-                              short, kdb_repeat_t);
+extern int kdb_register_flags(char *, kdb_func_t, char *, char *,
+                             short, kdb_cmdflags_t);
 extern int kdb_unregister(char *);
 #else /* ! CONFIG_KGDB_KDB */
 static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; }
 static inline void kdb_init(int level) {}
 static inline int kdb_register(char *cmd, kdb_func_t func, char *usage,
                               char *help, short minlen) { return 0; }
-static inline int kdb_register_repeat(char *cmd, kdb_func_t func, char *usage,
-                                     char *help, short minlen,
-                                     kdb_repeat_t repeat) { return 0; }
+static inline int kdb_register_flags(char *cmd, kdb_func_t func, char *usage,
+                                    char *help, short minlen,
+                                    kdb_cmdflags_t flags) { return 0; }
 static inline int kdb_unregister(char *cmd) { return 0; }
 #endif /* CONFIG_KGDB_KDB */
 enum {
index 5449d2f4a1efa51203ecd27237ddf9899af2d59a..64ce58bee6f5a74356f612a48730c35455ae6662 100644 (file)
@@ -176,7 +176,7 @@ extern int _cond_resched(void);
  */
 # define might_sleep() \
        do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)
-# define sched_annotate_sleep()        __set_current_state(TASK_RUNNING)
+# define sched_annotate_sleep()        (current->task_state_change = 0)
 #else
   static inline void ___might_sleep(const char *file, int line,
                                   int preempt_offset) { }
index 2d182413b1db5bbf3b9afa2c15dd674d2b817b4e..91f705de2c0be743dac06dac565817516058fc56 100644 (file)
@@ -231,6 +231,7 @@ enum {
        ATA_FLAG_SW_ACTIVITY    = (1 << 22), /* driver supports sw activity
                                              * led */
        ATA_FLAG_NO_DIPM        = (1 << 23), /* host not happy with DIPM */
+       ATA_FLAG_LOWTAG         = (1 << 24), /* host wants lowest available tag */
 
        /* bits 24:31 of ap->flags are reserved for LLD specific flags */
 
@@ -422,6 +423,7 @@ enum {
        ATA_HORKAGE_NO_NCQ_TRIM = (1 << 19),    /* don't use queued TRIM */
        ATA_HORKAGE_NOLPM       = (1 << 20),    /* don't use LPM */
        ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21),  /* some WDs have broken LPM */
+       ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */
 
         /* DMA mask for user DMA control: User visible values; DO NOT
            renumber */
index ce5dda8958fe83af981a19669662fe808581c261..b1fd675fa36f36a7ec5b68d2ba9d76684ad3bcfd 100644 (file)
@@ -59,6 +59,7 @@ enum s2mps13_reg {
        S2MPS13_REG_B6CTRL,
        S2MPS13_REG_B6OUT,
        S2MPS13_REG_B7CTRL,
+       S2MPS13_REG_B7SW,
        S2MPS13_REG_B7OUT,
        S2MPS13_REG_B8CTRL,
        S2MPS13_REG_B8OUT,
@@ -102,6 +103,7 @@ enum s2mps13_reg {
        S2MPS13_REG_L26CTRL,
        S2MPS13_REG_L27CTRL,
        S2MPS13_REG_L28CTRL,
+       S2MPS13_REG_L29CTRL,
        S2MPS13_REG_L30CTRL,
        S2MPS13_REG_L31CTRL,
        S2MPS13_REG_L32CTRL,
index 575a86c7fcbd2d2b4168d25c3ee20c275e84fc0e..f742b6717d52af2d83aaebaa6d5ff22a72cf786b 100644 (file)
@@ -50,6 +50,8 @@ enum {
        STMPE_IDX_GPEDR_MSB,
        STMPE_IDX_GPRER_LSB,
        STMPE_IDX_GPFER_LSB,
+       STMPE_IDX_GPPUR_LSB,
+       STMPE_IDX_GPPDR_LSB,
        STMPE_IDX_GPAFR_U_MSB,
        STMPE_IDX_IEGPIOR_LSB,
        STMPE_IDX_ISGPIOR_LSB,
@@ -113,24 +115,6 @@ extern int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins,
 extern int stmpe_enable(struct stmpe *stmpe, unsigned int blocks);
 extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
 
-struct matrix_keymap_data;
-
-/**
- * struct stmpe_keypad_platform_data - STMPE keypad platform data
- * @keymap_data: key map table and size
- * @debounce_ms: debounce interval, in ms.  Maximum is
- *              %STMPE_KEYPAD_MAX_DEBOUNCE.
- * @scan_count: number of key scanning cycles to confirm key data.
- *             Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT.
- * @no_autorepeat: disable key autorepeat
- */
-struct stmpe_keypad_platform_data {
-       const struct matrix_keymap_data *keymap_data;
-       unsigned int debounce_ms;
-       unsigned int scan_count;
-       bool no_autorepeat;
-};
-
 #define STMPE_GPIO_NOREQ_811_TOUCH     (0xf0)
 
 /**
@@ -199,7 +183,6 @@ struct stmpe_ts_platform_data {
  * @irq_gpio: gpio number over which irq will be requested (significant only if
  *           irq_over_gpio is true)
  * @gpio: GPIO-specific platform data
- * @keypad: keypad-specific platform data
  * @ts: touchscreen-specific platform data
  */
 struct stmpe_platform_data {
@@ -212,7 +195,6 @@ struct stmpe_platform_data {
        int autosleep_timeout;
 
        struct stmpe_gpio_platform_data *gpio;
-       struct stmpe_keypad_platform_data *keypad;
        struct stmpe_ts_platform_data *ts;
 };
 
index f80d0194c9bc2fa67b73eadbf93ac65e62434000..dd5ea3016fc4e854ded6b1e7c2e096224d83317f 100644 (file)
@@ -1070,6 +1070,7 @@ static inline int page_mapped(struct page *page)
 #define VM_FAULT_WRITE 0x0008  /* Special case for get_user_pages */
 #define VM_FAULT_HWPOISON 0x0010       /* Hit poisoned small page */
 #define VM_FAULT_HWPOISON_LARGE 0x0020  /* Hit poisoned large page. Index encoded in upper bits */
+#define VM_FAULT_SIGSEGV 0x0040
 
 #define VM_FAULT_NOPAGE        0x0100  /* ->fault installed the pte, not return page */
 #define VM_FAULT_LOCKED        0x0200  /* ->fault locked the returned page */
@@ -1078,8 +1079,9 @@ static inline int page_mapped(struct page *page)
 
 #define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
 
-#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
-                        VM_FAULT_FALLBACK | VM_FAULT_HWPOISON_LARGE)
+#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \
+                        VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE | \
+                        VM_FAULT_FALLBACK)
 
 /* Encode hstate index for a hwpoisoned large page */
 #define VM_FAULT_SET_HINDEX(x) ((x) << 12)
@@ -1952,7 +1954,7 @@ extern int expand_downwards(struct vm_area_struct *vma,
 #if VM_GROWSUP
 extern int expand_upwards(struct vm_area_struct *vma, unsigned long address);
 #else
-  #define expand_upwards(vma, address) do { } while (0)
+  #define expand_upwards(vma, address) (0)
 #endif
 
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
index 375af80bde7d7c90bb1c09efb3edc297dbe4d864..f767a0de611f8a726df957c6595d84df92d8efb3 100644 (file)
@@ -137,6 +137,7 @@ struct sdhci_host {
 #define SDHCI_SDR104_NEEDS_TUNING (1<<10)      /* SDR104/HS200 needs tuning */
 #define SDHCI_USING_RETUNING_TIMER (1<<11)     /* Host is using a retuning timer for the card */
 #define SDHCI_USE_64_BIT_DMA   (1<<12) /* Use 64-bit DMA */
+#define SDHCI_HS400_TUNING     (1<<13) /* Tuning for HS400 */
 
        unsigned int version;   /* SDHCI spec. version */
 
index ebfb0e153c6a78de5cc26162b2f7e904a9890fe1..b653d7c0a05a0abbaf5e1b4759a3f79b398c8b25 100644 (file)
@@ -444,7 +444,7 @@ extern void __module_put_and_exit(struct module *mod, long code)
 #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code)
 
 #ifdef CONFIG_MODULE_UNLOAD
-unsigned long module_refcount(struct module *mod);
+int module_refcount(struct module *mod);
 void __symbol_put(const char *symbol);
 #define symbol_put(x) __symbol_put(VMLINUX_SYMBOL_STR(x))
 void symbol_put_addr(void *addr);
index 7eeb9bbfb816f3afc11662f05e5dde3d297db489..f7556261fe3c54adb52b28789b7cb7b19b280b13 100644 (file)
@@ -26,7 +26,7 @@ unsigned int arch_mod_section_prepend(struct module *mod, unsigned int section);
 void *module_alloc(unsigned long size);
 
 /* Free memory returned from module_alloc. */
-void module_free(struct module *mod, void *module_region);
+void module_memfree(void *module_region);
 
 /*
  * Apply the given relocation to the (simplified) ELF.  Return -error
@@ -82,4 +82,6 @@ int module_finalize(const Elf_Ehdr *hdr,
 /* Any cleanup needed when module leaves. */
 void module_arch_cleanup(struct module *mod);
 
+/* Any cleanup before freeing mod->module_init */
+void module_arch_freeing_init(struct module *mod);
 #endif
index c31f74d76ebd3c595160a4b3b513594423f43240..52fd8e8694cfade5e844d52a70b191c3183f60a2 100644 (file)
@@ -852,11 +852,11 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *     3. Update dev->stats asynchronously and atomically, and define
  *        neither operation.
  *
- * int (*ndo_vlan_rx_add_vid)(struct net_device *dev, __be16 proto, u16t vid);
+ * int (*ndo_vlan_rx_add_vid)(struct net_device *dev, __be16 proto, u16 vid);
  *     If device support VLAN filtering this function is called when a
  *     VLAN id is registered.
  *
- * int (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid);
+ * int (*ndo_vlan_rx_kill_vid)(struct net_device *dev, __be16 proto, u16 vid);
  *     If device support VLAN filtering this function is called when a
  *     VLAN id is unregistered.
  *
@@ -1012,12 +1012,15 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev,
  *     Callback to use for xmit over the accelerated station. This
  *     is used in place of ndo_start_xmit on accelerated net
  *     devices.
- * bool        (*ndo_gso_check) (struct sk_buff *skb,
- *                       struct net_device *dev);
+ * 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 GSO on a packet. The device returns true if it is
- *     able to GSO the packet, false otherwise. If the return value is
- *     false the stack will do software GSO.
+ *     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_switch_parent_id_get)(struct net_device *dev,
  *                                struct netdev_phys_item_id *psid);
@@ -1178,8 +1181,9 @@ struct net_device_ops {
                                                        struct net_device *dev,
                                                        void *priv);
        int                     (*ndo_get_lock_subclass)(struct net_device *dev);
-       bool                    (*ndo_gso_check) (struct sk_buff *skb,
-                                                 struct net_device *dev);
+       netdev_features_t       (*ndo_features_check) (struct sk_buff *skb,
+                                                      struct net_device *dev,
+                                                      netdev_features_t features);
 #ifdef CONFIG_NET_SWITCHDEV
        int                     (*ndo_switch_parent_id_get)(struct net_device *dev,
                                                            struct netdev_phys_item_id *psid);
@@ -2081,7 +2085,7 @@ extern rwlock_t                           dev_base_lock;          /* Device list lock */
        list_for_each_entry_continue_rcu(d, &(net)->dev_base_head, dev_list)
 #define for_each_netdev_in_bond_rcu(bond, slave)       \
                for_each_netdev_rcu(&init_net, slave)   \
-                       if (netdev_master_upper_dev_get_rcu(slave) == bond)
+                       if (netdev_master_upper_dev_get_rcu(slave) == (bond))
 #define net_device_entry(lh)   list_entry(lh, struct net_device, dev_list)
 
 static inline struct net_device *next_net_device(struct net_device *dev)
@@ -3611,8 +3615,6 @@ static inline bool netif_needs_gso(struct net_device *dev, struct sk_buff *skb,
                                   netdev_features_t features)
 {
        return skb_is_gso(skb) && (!skb_gso_ok(skb, features) ||
-               (dev->netdev_ops->ndo_gso_check &&
-                !dev->netdev_ops->ndo_gso_check(skb, dev)) ||
                unlikely((skb->ip_summed != CHECKSUM_PARTIAL) &&
                         (skb->ip_summed != CHECKSUM_UNNECESSARY)));
 }
index 9e572daa15d568cc0d7c82342a0d7fb3ad37c327..02fc86d2348e2157d19cd4c16c4574ef86ac4d07 100644 (file)
@@ -46,8 +46,8 @@ struct netlink_kernel_cfg {
        unsigned int    flags;
        void            (*input)(struct sk_buff *skb);
        struct mutex    *cb_mutex;
-       int             (*bind)(int group);
-       void            (*unbind)(int group);
+       int             (*bind)(struct net *net, int group);
+       void            (*unbind)(struct net *net, int group);
        bool            (*compare)(struct net *net, struct sock *sk);
 };
 
index 1e37fbb78f7afbc57b8ab3c076d66ce7555f3cb0..ddea982355f3be93947dae0b2e30f9e00209920e 100644 (file)
@@ -74,6 +74,9 @@ struct nfs_client {
        /* idmapper */
        struct idmap *          cl_idmap;
 
+       /* Client owner identifier */
+       const char *            cl_owner_id;
+
        /* Our own IP address, as a null-terminated string.
         * This is used to generate the mv0 callback address.
         */
index 853698c721f7d1547df181a4fbfc904a67758f72..76200984d1e22081954234d49f32653e18478717 100644 (file)
@@ -85,11 +85,6 @@ static inline void oom_killer_enable(void)
        oom_killer_disabled = false;
 }
 
-static inline bool oom_gfp_allowed(gfp_t gfp_mask)
-{
-       return (gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY);
-}
-
 extern struct task_struct *find_lock_task_mm(struct task_struct *p);
 
 static inline bool task_will_free_mem(struct task_struct *task)
index 7ea069cd32579caacc5953802356a62237ac0413..4b3736f7065c496601011b9474368238f9af923a 100644 (file)
@@ -251,7 +251,7 @@ pgoff_t page_cache_prev_hole(struct address_space *mapping,
 #define FGP_NOWAIT             0x00000020
 
 struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset,
-               int fgp_flags, gfp_t cache_gfp_mask, gfp_t radix_gfp_mask);
+               int fgp_flags, gfp_t cache_gfp_mask);
 
 /**
  * find_get_page - find and get a page reference
@@ -266,13 +266,13 @@ struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset,
 static inline struct page *find_get_page(struct address_space *mapping,
                                        pgoff_t offset)
 {
-       return pagecache_get_page(mapping, offset, 0, 0, 0);
+       return pagecache_get_page(mapping, offset, 0, 0);
 }
 
 static inline struct page *find_get_page_flags(struct address_space *mapping,
                                        pgoff_t offset, int fgp_flags)
 {
-       return pagecache_get_page(mapping, offset, fgp_flags, 0, 0);
+       return pagecache_get_page(mapping, offset, fgp_flags, 0);
 }
 
 /**
@@ -292,7 +292,7 @@ static inline struct page *find_get_page_flags(struct address_space *mapping,
 static inline struct page *find_lock_page(struct address_space *mapping,
                                        pgoff_t offset)
 {
-       return pagecache_get_page(mapping, offset, FGP_LOCK, 0, 0);
+       return pagecache_get_page(mapping, offset, FGP_LOCK, 0);
 }
 
 /**
@@ -319,7 +319,7 @@ static inline struct page *find_or_create_page(struct address_space *mapping,
 {
        return pagecache_get_page(mapping, offset,
                                        FGP_LOCK|FGP_ACCESSED|FGP_CREAT,
-                                       gfp_mask, gfp_mask & GFP_RECLAIM_MASK);
+                                       gfp_mask);
 }
 
 /**
@@ -340,8 +340,7 @@ static inline struct page *grab_cache_page_nowait(struct address_space *mapping,
 {
        return pagecache_get_page(mapping, index,
                        FGP_LOCK|FGP_CREAT|FGP_NOFS|FGP_NOWAIT,
-                       mapping_gfp_mask(mapping),
-                       GFP_NOFS);
+                       mapping_gfp_mask(mapping));
 }
 
 struct page *find_get_entry(struct address_space *mapping, pgoff_t offset);
index 360a966a97a5807f7ff13441748c0c93850ff7e1..9603094ed59b2adb5defa9eb93a955c5ce93e543 100644 (file)
@@ -175,6 +175,8 @@ enum pci_dev_flags {
        PCI_DEV_FLAGS_DMA_ALIAS_DEVFN = (__force pci_dev_flags_t) (1 << 4),
        /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */
        PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5),
+       /* Do not use bus resets for device */
+       PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6),
 };
 
 enum pci_irq_reroute_variant {
@@ -1065,6 +1067,7 @@ resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
+int pci_claim_bridge_resource(struct pci_dev *bridge, int i);
 void pci_assign_unassigned_resources(void);
 void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge);
 void pci_assign_unassigned_bus_resources(struct pci_bus *bus);
index 486e84ccb1f92545ec0d4f74aaa153abf0ff8049..664de5a4ec4672d9bbd9d1059a2c7005591329b3 100644 (file)
@@ -79,11 +79,6 @@ struct perf_branch_stack {
        struct perf_branch_entry        entries[0];
 };
 
-struct perf_regs {
-       __u64           abi;
-       struct pt_regs  *regs;
-};
-
 struct task_struct;
 
 /*
@@ -455,11 +450,6 @@ struct perf_event {
 #endif /* CONFIG_PERF_EVENTS */
 };
 
-enum perf_event_context_type {
-       task_context,
-       cpu_context,
-};
-
 /**
  * struct perf_event_context - event context structure
  *
@@ -467,7 +457,6 @@ enum perf_event_context_type {
  */
 struct perf_event_context {
        struct pmu                      *pmu;
-       enum perf_event_context_type    type;
        /*
         * Protect the states of the events in the list,
         * nr_active, and the list:
@@ -610,7 +599,14 @@ struct perf_sample_data {
                u32     reserved;
        }                               cpu_entry;
        struct perf_callchain_entry     *callchain;
+
+       /*
+        * regs_user may point to task_pt_regs or to regs_user_copy, depending
+        * on arch details.
+        */
        struct perf_regs                regs_user;
+       struct pt_regs                  regs_user_copy;
+
        struct perf_regs                regs_intr;
        u64                             stack_user_size;
 } ____cacheline_aligned;
index 3c73d5fe18be4b950628f82234b7ba58855b2c29..a5f98d53d7325b0358bd45b7b7406b4f02fef6d5 100644 (file)
@@ -1,11 +1,19 @@
 #ifndef _LINUX_PERF_REGS_H
 #define _LINUX_PERF_REGS_H
 
+struct perf_regs {
+       __u64           abi;
+       struct pt_regs  *regs;
+};
+
 #ifdef CONFIG_HAVE_PERF_REGS
 #include <asm/perf_regs.h>
 u64 perf_reg_value(struct pt_regs *regs, int idx);
 int perf_reg_validate(u64 mask);
 u64 perf_reg_abi(struct task_struct *task);
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs,
+                       struct pt_regs *regs_user_copy);
 #else
 static inline u64 perf_reg_value(struct pt_regs *regs, int idx)
 {
@@ -21,5 +29,13 @@ static inline u64 perf_reg_abi(struct task_struct *task)
 {
        return PERF_SAMPLE_REGS_ABI_NONE;
 }
+
+static inline void perf_get_regs_user(struct perf_regs *regs_user,
+                                     struct pt_regs *regs,
+                                     struct pt_regs *regs_user_copy)
+{
+       regs_user->regs = task_pt_regs(current);
+       regs_user->abi = perf_reg_abi(current);
+}
 #endif /* CONFIG_HAVE_PERF_REGS */
 #endif /* _LINUX_PERF_REGS_H */
index e9e6cfbfbb589d0393060e2fed0422ec402dd612..eb7d4a135a9ea71364105c0bade762b5f06b67da 100644 (file)
@@ -66,7 +66,7 @@ enum omap_control_usb_mode {
 #define        OMAP_CTRL_PIPE3_PHY_TX_RX_POWEROFF      0x0
 
 #define        OMAP_CTRL_PCIE_PCS_MASK                 0xff
-#define        OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT    0x8
+#define        OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT    16
 
 #define OMAP_CTRL_USB2_PHY_PD          BIT(28)
 
@@ -79,7 +79,7 @@ enum omap_control_usb_mode {
 void omap_control_phy_power(struct device *dev, int on);
 void omap_control_usb_set_mode(struct device *dev,
                               enum omap_control_usb_mode mode);
-void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay);
+void omap_control_pcie_pcs(struct device *dev, u8 delay);
 #else
 
 static inline void omap_control_phy_power(struct device *dev, int on)
@@ -91,7 +91,7 @@ static inline void omap_control_usb_set_mode(struct device *dev,
 {
 }
 
-static inline void omap_control_pcie_pcs(struct device *dev, u8 id, u8 delay)
+static inline void omap_control_pcie_pcs(struct device *dev, u8 delay)
 {
 }
 #endif
index 6cd20d5e651b9d751b9555000a6417d10368dee2..a9edab2c787a53e809150034128bc46448a010ad 100644 (file)
@@ -271,6 +271,8 @@ typedef struct generic_pm_domain *(*genpd_xlate_t)(struct of_phandle_args *args,
 int __of_genpd_add_provider(struct device_node *np, genpd_xlate_t xlate,
                        void *data);
 void of_genpd_del_provider(struct device_node *np);
+struct generic_pm_domain *of_genpd_get_from_provider(
+                       struct of_phandle_args *genpdspec);
 
 struct generic_pm_domain *__of_genpd_xlate_simple(
                                        struct of_phandle_args *genpdspec,
@@ -288,6 +290,12 @@ static inline int __of_genpd_add_provider(struct device_node *np,
 }
 static inline void of_genpd_del_provider(struct device_node *np) {}
 
+static inline struct generic_pm_domain *of_genpd_get_from_provider(
+                       struct of_phandle_args *genpdspec)
+{
+       return NULL;
+}
+
 #define __of_genpd_xlate_simple                NULL
 #define __of_genpd_xlate_onecell       NULL
 
index c8f170324e643ccb895dacfd9b06a66a8afa7193..4d5bf5726578c58b739a79a5f093e5f7c4a009a3 100644 (file)
@@ -10,9 +10,6 @@
 extern const char linux_banner[];
 extern const char linux_proc_banner[];
 
-extern char *log_buf_addr_get(void);
-extern u32 log_buf_len_get(void);
-
 static inline int printk_get_level(const char *buffer)
 {
        if (buffer[0] == KERN_SOH_ASCII && buffer[1]) {
@@ -163,6 +160,8 @@ extern int kptr_restrict;
 
 extern void wake_up_klogd(void);
 
+char *log_buf_addr_get(void);
+u32 log_buf_len_get(void);
 void log_buf_kexec_setup(void);
 void __init setup_log_buf(int early);
 void dump_stack_set_arch_desc(const char *fmt, ...);
@@ -198,6 +197,16 @@ static inline void wake_up_klogd(void)
 {
 }
 
+static inline char *log_buf_addr_get(void)
+{
+       return NULL;
+}
+
+static inline u32 log_buf_len_get(void)
+{
+       return 0;
+}
+
 static inline void log_buf_kexec_setup(void)
 {
 }
index 50978b781a19c4d82c60c44918f5049c4cd25272..097d7eb2441e529f139822b6bf4fe5031dc5e710 100644 (file)
@@ -321,6 +321,49 @@ struct dquot_operations {
 
 struct path;
 
+/* Structure for communicating via ->get_dqblk() & ->set_dqblk() */
+struct qc_dqblk {
+       int d_fieldmask;        /* mask of fields to change in ->set_dqblk() */
+       u64 d_spc_hardlimit;    /* absolute limit on used space */
+       u64 d_spc_softlimit;    /* preferred limit on used space */
+       u64 d_ino_hardlimit;    /* maximum # allocated inodes */
+       u64 d_ino_softlimit;    /* preferred inode limit */
+       u64 d_space;            /* Space owned by the user */
+       u64 d_ino_count;        /* # inodes owned by the user */
+       s64 d_ino_timer;        /* zero if within inode limits */
+                               /* if not, we refuse service */
+       s64 d_spc_timer;        /* similar to above; for space */
+       int d_ino_warns;        /* # warnings issued wrt num inodes */
+       int d_spc_warns;        /* # warnings issued wrt used space */
+       u64 d_rt_spc_hardlimit; /* absolute limit on realtime space */
+       u64 d_rt_spc_softlimit; /* preferred limit on RT space */
+       u64 d_rt_space;         /* realtime space owned */
+       s64 d_rt_spc_timer;     /* similar to above; for RT space */
+       int d_rt_spc_warns;     /* # warnings issued wrt RT space */
+};
+
+/* Field specifiers for ->set_dqblk() in struct qc_dqblk */
+#define        QC_INO_SOFT     (1<<0)
+#define        QC_INO_HARD     (1<<1)
+#define        QC_SPC_SOFT     (1<<2)
+#define        QC_SPC_HARD     (1<<3)
+#define        QC_RT_SPC_SOFT  (1<<4)
+#define        QC_RT_SPC_HARD  (1<<5)
+#define QC_LIMIT_MASK (QC_INO_SOFT | QC_INO_HARD | QC_SPC_SOFT | QC_SPC_HARD | \
+                      QC_RT_SPC_SOFT | QC_RT_SPC_HARD)
+#define        QC_SPC_TIMER    (1<<6)
+#define        QC_INO_TIMER    (1<<7)
+#define        QC_RT_SPC_TIMER (1<<8)
+#define QC_TIMER_MASK (QC_SPC_TIMER | QC_INO_TIMER | QC_RT_SPC_TIMER)
+#define        QC_SPC_WARNS    (1<<9)
+#define        QC_INO_WARNS    (1<<10)
+#define        QC_RT_SPC_WARNS (1<<11)
+#define QC_WARNS_MASK (QC_SPC_WARNS | QC_INO_WARNS | QC_RT_SPC_WARNS)
+#define        QC_SPACE        (1<<12)
+#define        QC_INO_COUNT    (1<<13)
+#define        QC_RT_SPACE     (1<<14)
+#define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE)
+
 /* Operations handling requests from userspace */
 struct quotactl_ops {
        int (*quota_on)(struct super_block *, int, int, struct path *);
@@ -329,8 +372,8 @@ struct quotactl_ops {
        int (*quota_sync)(struct super_block *, int);
        int (*get_info)(struct super_block *, int, struct if_dqinfo *);
        int (*set_info)(struct super_block *, int, struct if_dqinfo *);
-       int (*get_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
-       int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
+       int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);
+       int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *);
        int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
        int (*set_xstate)(struct super_block *, unsigned int, int);
        int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
index f23538a6e411f4e1d5700ebbed96480f1425a9e3..29e3455f7d41f7f951e95d544acefd970388e767 100644 (file)
@@ -98,9 +98,9 @@ int dquot_quota_sync(struct super_block *sb, int type);
 int dquot_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii);
 int dquot_get_dqblk(struct super_block *sb, struct kqid id,
-               struct fs_disk_quota *di);
+               struct qc_dqblk *di);
 int dquot_set_dqblk(struct super_block *sb, struct kqid id,
-               struct fs_disk_quota *di);
+               struct qc_dqblk *di);
 
 int __dquot_transfer(struct inode *inode, struct dquot **transfer_to);
 int dquot_transfer(struct inode *inode, struct iattr *iattr);
index c0c2bce6b0b7bab50f5c7bb5a1353d8991f8e08b..d9d7e7e56352a8855def8f86af24fdb569ee480c 100644 (file)
@@ -36,6 +36,16 @@ struct anon_vma {
         */
        atomic_t refcount;
 
+       /*
+        * Count of child anon_vmas and VMAs which points to this anon_vma.
+        *
+        * This counter is used for making decision about reusing anon_vma
+        * instead of forking new one. See comments in function anon_vma_clone.
+        */
+       unsigned degree;
+
+       struct anon_vma *parent;        /* Parent of this anon_vma */
+
        /*
         * NOTE: the LSB of the rb_root.rb_node is set by
         * mm_take_all_locks() _after_ taking the above lock. So the
index c611a02fbc51246c9ea71e81eb9ccd6a4030d763..fc52e307efab8768effbb7880702986653e0a07c 100644 (file)
@@ -38,7 +38,7 @@
 #define THERMAL_CSTATE_INVALID -1UL
 
 /* No upper/lower limit requirement */
-#define THERMAL_NO_LIMIT       THERMAL_CSTATE_INVALID
+#define THERMAL_NO_LIMIT       ((u32)~0)
 
 /* Unit conversion macros */
 #define KELVIN_TO_CELSIUS(t)   (long)(((long)t-2732 >= 0) ?    \
index 203c2ad40d7184726b585b7c644b0a7f11ad6894..beebe3a02d43f5c527633cbd12af690c02e8288d 100644 (file)
@@ -110,6 +110,19 @@ static inline bool timespec_valid_strict(const struct timespec *ts)
        return true;
 }
 
+static inline bool timeval_valid(const struct timeval *tv)
+{
+       /* Dates before 1970 are bogus */
+       if (tv->tv_sec < 0)
+               return false;
+
+       /* Can't have more microseconds then a second */
+       if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+               return false;
+
+       return true;
+}
+
 extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
 
 #define CURRENT_TIME           (current_kernel_time())
index a219be961c0a2cb7ab21ce08353bdb1c968d2b92..00048339c23e4f252ee6a4b15cd38b49b8032de4 100644 (file)
@@ -177,7 +177,6 @@ int write_cache_pages(struct address_space *mapping,
                      struct writeback_control *wbc, writepage_t writepage,
                      void *data);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
-void set_page_dirty_balance(struct page *page);
 void writeback_set_ratelimit(void);
 void tag_pages_for_writeback(struct address_space *mapping,
                             pgoff_t start, pgoff_t end);
index af10c2cf8a1dce00d9cc5414f67d5917bf911570..6c92415311cacb3ee39ff768edc3d2a4461e922f 100644 (file)
@@ -27,10 +27,18 @@ struct genl_info;
  * @maxattr: maximum number of attributes supported
  * @netnsok: set to true if the family can handle network
  *     namespaces and should be presented in all of them
+ * @parallel_ops: operations can be called in parallel and aren't
+ *     synchronized by the core genetlink code
  * @pre_doit: called before an operation's doit callback, it may
  *     do additional, common, filtering and return an error
  * @post_doit: called after an operation's doit callback, it may
  *     undo operations done by pre_doit, for example release locks
+ * @mcast_bind: a socket bound to the given multicast group (which
+ *     is given as the offset into the groups array)
+ * @mcast_unbind: a socket was unbound from the given multicast group.
+ *     Note that unbind() will not be called symmetrically if the
+ *     generic netlink family is removed while there are still open
+ *     sockets.
  * @attrbuf: buffer to store parsed attributes
  * @family_list: family list
  * @mcgrps: multicast groups used by this family (private)
@@ -53,6 +61,8 @@ struct genl_family {
        void                    (*post_doit)(const struct genl_ops *ops,
                                             struct sk_buff *skb,
                                             struct genl_info *info);
+       int                     (*mcast_bind)(struct net *net, int group);
+       void                    (*mcast_unbind)(struct net *net, int group);
        struct nlattr **        attrbuf;        /* private */
        const struct genl_ops * ops;            /* private */
        const struct genl_multicast_group *mcgrps; /* private */
@@ -395,11 +405,11 @@ static inline int genl_set_err(struct genl_family *family, struct net *net,
 }
 
 static inline int genl_has_listeners(struct genl_family *family,
-                                    struct sock *sk, unsigned int group)
+                                    struct net *net, unsigned int group)
 {
        if (WARN_ON_ONCE(group >= family->n_mcgrps))
                return -EINVAL;
        group = family->mcgrp_offset + group;
-       return netlink_has_listeners(sk, group);
+       return netlink_has_listeners(net->genl_sock, group);
 }
 #endif /* __NET_GENERIC_NETLINK_H */
index 0bb620702929e7ad3b48f7aa40e5c73df3638141..f7cbd703d15d24edca61cf9e159cb1ce3857cb5b 100644 (file)
@@ -39,11 +39,12 @@ struct inet_skb_parm {
        struct ip_options       opt;            /* Compiled IP options          */
        unsigned char           flags;
 
-#define IPSKB_FORWARDED                1
-#define IPSKB_XFRM_TUNNEL_SIZE 2
-#define IPSKB_XFRM_TRANSFORMED 4
-#define IPSKB_FRAG_COMPLETE    8
-#define IPSKB_REROUTED         16
+#define IPSKB_FORWARDED                BIT(0)
+#define IPSKB_XFRM_TUNNEL_SIZE BIT(1)
+#define IPSKB_XFRM_TRANSFORMED BIT(2)
+#define IPSKB_FRAG_COMPLETE    BIT(3)
+#define IPSKB_REROUTED         BIT(4)
+#define IPSKB_DOREDIRECT       BIT(5)
 
        u16                     frag_max_size;
 };
index 58d719ddaa60c93d2c6424765e96abf254cb4dc6..29c7be8808d52b21e0c41949ce62d816d8b58372 100644 (file)
@@ -1270,8 +1270,7 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  *
  * @IEEE80211_KEY_FLAG_GENERATE_IV: This flag should be set by the
  *     driver to indicate that it requires IV generation for this
- *     particular key. Setting this flag does not necessarily mean that SKBs
- *     will have sufficient tailroom for ICV or MIC.
+ *     particular key.
  * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
  *     the driver for a TKIP key if it requires Michael MIC
  *     generation in software.
@@ -1283,9 +1282,7 @@ struct ieee80211_vif *wdev_to_ieee80211_vif(struct wireless_dev *wdev);
  * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
  *     if space should be prepared for the IV, but the IV
  *     itself should not be generated. Do not set together with
- *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. Setting this flag does
- *     not necessarily mean that SKBs will have sufficient tailroom for ICV or
- *     MIC.
+ *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
  * @IEEE80211_KEY_FLAG_RX_MGMT: This key will be used to decrypt received
  *     management frames. The flag can help drivers that have a hardware
  *     crypto implementation that doesn't deal with management frames
index eb070b3674a1ba346c2c779889a90b636a8d3d7a..76f708486aaec76031a24ee5ff1d02f126185304 100644 (file)
@@ -190,7 +190,6 @@ struct neigh_hash_table {
 
 
 struct neigh_table {
-       struct neigh_table      *next;
        int                     family;
        int                     entry_size;
        int                     key_len;
index 57cccd0052e58dd124ec997174d8cd9ff885be99..903461aa5644ce9d1e366818fa6cbda1ba0cc1b1 100644 (file)
@@ -1,6 +1,9 @@
 #ifndef __NET_VXLAN_H
 #define __NET_VXLAN_H 1
 
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/if_vlan.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/udp.h>
@@ -51,16 +54,33 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
                   __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
                   __be16 src_port, __be16 dst_port, __be32 vni, bool xnet);
 
-static inline bool vxlan_gso_check(struct sk_buff *skb)
+static inline netdev_features_t vxlan_features_check(struct sk_buff *skb,
+                                                    netdev_features_t features)
 {
-       if ((skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL) &&
+       u8 l4_hdr = 0;
+
+       if (!skb->encapsulation)
+               return features;
+
+       switch (vlan_get_protocol(skb)) {
+       case htons(ETH_P_IP):
+               l4_hdr = ip_hdr(skb)->protocol;
+               break;
+       case htons(ETH_P_IPV6):
+               l4_hdr = ipv6_hdr(skb)->nexthdr;
+               break;
+       default:
+               return features;;
+       }
+
+       if ((l4_hdr == IPPROTO_UDP) &&
            (skb->inner_protocol_type != ENCAP_TYPE_ETHER ||
             skb->inner_protocol != htons(ETH_P_TEB) ||
             (skb_inner_mac_header(skb) - skb_transport_header(skb) !=
              sizeof(struct udphdr) + sizeof(struct vxlanhdr))))
-               return false;
+               return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK);
 
-       return true;
+       return features;
 }
 
 /* IP header + UDP + VXLAN + Ethernet header */
index 1e7f74acc2eccb75b735b82c66d1612ce762c248..95d1c20fa659662eca3b555e9f3fba3a56d09432 100644 (file)
@@ -275,6 +275,12 @@ struct snd_pcm_hw_constraint_list {
        unsigned int mask;
 };
 
+struct snd_pcm_hw_constraint_ranges {
+       unsigned int count;
+       const struct snd_interval *ranges;
+       unsigned int mask;
+};
+
 struct snd_pcm_hwptr_log;
 
 struct snd_pcm_runtime {
@@ -857,7 +863,7 @@ static inline unsigned int params_channels(const struct snd_pcm_hw_params *p)
 }
 
 /**
- * params_channels - Get the sample rate from the hw params
+ * params_rate - Get the sample rate from the hw params
  * @p: hw params
  */
 static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
@@ -866,7 +872,7 @@ static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
 }
 
 /**
- * params_channels - Get the period size (in frames) from the hw params
+ * params_period_size - Get the period size (in frames) from the hw params
  * @p: hw params
  */
 static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
@@ -875,7 +881,7 @@ static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
 }
 
 /**
- * params_channels - Get the number of periods from the hw params
+ * params_periods - Get the number of periods from the hw params
  * @p: hw params
  */
 static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
@@ -884,7 +890,7 @@ static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
 }
 
 /**
- * params_channels - Get the buffer size (in frames) from the hw params
+ * params_buffer_size - Get the buffer size (in frames) from the hw params
  * @p: hw params
  */
 static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
@@ -893,7 +899,7 @@ static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
 }
 
 /**
- * params_channels - Get the buffer size (in bytes) from the hw params
+ * params_buffer_bytes - Get the buffer size (in bytes) from the hw params
  * @p: hw params
  */
 static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p)
@@ -910,6 +916,8 @@ void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
                          const struct snd_interval *b, struct snd_interval *c);
 int snd_interval_list(struct snd_interval *i, unsigned int count,
                      const unsigned int *list, unsigned int mask);
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+                       const struct snd_interval *list, unsigned int mask);
 int snd_interval_ratnum(struct snd_interval *i,
                        unsigned int rats_count, struct snd_ratnum *rats,
                        unsigned int *nump, unsigned int *denp);
@@ -934,6 +942,10 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
                               unsigned int cond,
                               snd_pcm_hw_param_t var,
                               const struct snd_pcm_hw_constraint_list *l);
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+                                unsigned int cond,
+                                snd_pcm_hw_param_t var,
+                                const struct snd_pcm_hw_constraint_ranges *r);
 int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime, 
                                  unsigned int cond,
                                  snd_pcm_hw_param_t var,
index 83284cae464c492bf77cf127958f46469ee4b9c0..4cecd0c175f607c7f3cae2a2fb03660f81131799 100644 (file)
@@ -55,6 +55,7 @@ struct rsnd_ssi_platform_info {
 struct rsnd_src_platform_info {
        u32 convert_rate; /* sampling rate convert */
        int dma_id; /* for Gen2 SCU */
+       int irq;
 };
 
 /*
index d9eb7d861cd0da77722e178b3c3f94ee88ba9b99..a6207043ac3c7f80f1def8b4fb2025f0dd1a05ca 100644 (file)
@@ -37,6 +37,9 @@ struct rt5677_platform_data {
                OFF, GPIO4, GPIO5 and GPIO6 respectively */
        unsigned int jd2_gpio;
        unsigned int jd3_gpio;
+
+       /* Set MICBIAS1 VDD 1v8 or 3v3 */
+       bool micbias1_vdd_3v3;
 };
 
 #endif
index 9b0ac77177b6e3aa13156822a2c23f61635e56bd..1255ddb1d3e2c22d05b188a82bc589f62c307b9b 100644 (file)
@@ -20,6 +20,7 @@ struct asoc_simple_dai {
        unsigned int sysclk;
        int slots;
        int slot_width;
+       struct clk *clk;
 };
 
 struct asoc_simple_card_info {
index 89823cfe6f043147b3798b78ac4034831d25c790..8d7416e46861744d990f4c0dbb2d1f72fdd9407b 100644 (file)
@@ -405,7 +405,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
                struct snd_soc_dapm_update *update);
 
 /* dapm sys fs - used by the core */
-int snd_soc_dapm_sys_add(struct device *dev);
+extern struct attribute *soc_dapm_dev_attrs[];
 void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm,
                                struct dentry *parent);
 
@@ -431,7 +431,6 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
                                           const char *pin);
 int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
                                const char *pin);
-void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
 unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
 
 /* Mostly internal - should not normally be used */
@@ -526,7 +525,6 @@ struct snd_soc_dapm_widget {
        enum snd_soc_dapm_type id;
        const char *name;               /* widget name */
        const char *sname;      /* stream name */
-       struct snd_soc_codec *codec;
        struct list_head list;
        struct snd_soc_dapm_context *dapm;
 
index b4fca9aed2a2b00296ce040428b830b93095d562..0d1ade19562857c7b65157636ac37b2f0222e202 100644 (file)
@@ -429,6 +429,9 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd);
 void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream);
 void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream);
 
+int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
+       unsigned int dai_fmt);
+
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -498,6 +501,7 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
                                unsigned int mask, unsigned int value);
 
 #ifdef CONFIG_SND_SOC_AC97_BUS
+struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
 struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
 void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
 
index 8d93b0357a14b39a23fa4292a85510b7dc21635a..a894f7d17b1a325e882723ce696c8a921f9508ec 100644 (file)
 #define STA32X_THERMAL_RECOVERY_ENABLE         2
 
 struct sta32x_platform_data {
-       int output_conf;
-       int ch1_output_mapping;
-       int ch2_output_mapping;
-       int ch3_output_mapping;
-       int thermal_conf;
+       u8 output_conf;
+       u8 ch1_output_mapping;
+       u8 ch2_output_mapping;
+       u8 ch3_output_mapping;
        int needs_esd_watchdog;
+       u8 drop_compensation_ns;
+       unsigned int thermal_warning_recovery:1;
+       unsigned int thermal_warning_adjustment:1;
+       unsigned int fault_detect_recovery:1;
+       unsigned int max_power_use_mpcc:1;
+       unsigned int max_power_correction:1;
+       unsigned int am_reduction_mode:1;
+       unsigned int odd_pwm_speed_mode:1;
+       unsigned int invalid_input_detect_mute:1;
 };
 
 #endif /* __LINUX_SND__STA32X_H */
index 430cfaf92285f177d977d11717599bf1ff85b70b..db81c65b8f4857c011a025e5b54026bf7d683f7c 100644 (file)
@@ -135,7 +135,6 @@ int se_dev_set_is_nonrot(struct se_device *, int);
 int    se_dev_set_emulate_rest_reord(struct se_device *dev, int);
 int    se_dev_set_queue_depth(struct se_device *, u32);
 int    se_dev_set_max_sectors(struct se_device *, u32);
-int    se_dev_set_fabric_max_sectors(struct se_device *, u32);
 int    se_dev_set_optimal_sectors(struct se_device *, u32);
 int    se_dev_set_block_size(struct se_device *, u32);
 
index 3247d7530107968aa7c1d1957f96790c226845dd..186f7a92357094fbb4735043b2a2b8c8cd884af8 100644 (file)
@@ -98,8 +98,6 @@ static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name
        TB_DEV_ATTR(_backend, block_size, S_IRUGO | S_IWUSR);           \
        DEF_TB_DEV_ATTRIB_RO(_backend, hw_max_sectors);                 \
        TB_DEV_ATTR_RO(_backend, hw_max_sectors);                       \
-       DEF_TB_DEV_ATTRIB(_backend, fabric_max_sectors);                \
-       TB_DEV_ATTR(_backend, fabric_max_sectors, S_IRUGO | S_IWUSR);   \
        DEF_TB_DEV_ATTRIB(_backend, optimal_sectors);                   \
        TB_DEV_ATTR(_backend, optimal_sectors, S_IRUGO | S_IWUSR);      \
        DEF_TB_DEV_ATTRIB_RO(_backend, hw_queue_depth);                 \
index 397fb635766a96faa94c5b91788ad24fca0d2a34..4a8795a87b9e99f30ee07f43fdce3984ddc658e0 100644 (file)
@@ -77,8 +77,6 @@
 #define DA_UNMAP_GRANULARITY_ALIGNMENT_DEFAULT 0
 /* Default max_write_same_len, disabled by default */
 #define DA_MAX_WRITE_SAME_LEN                  0
-/* Default max transfer length */
-#define DA_FABRIC_MAX_SECTORS                  8192
 /* Use a model alias based on the configfs backend device name */
 #define DA_EMULATE_MODEL_ALIAS                 0
 /* Emulation for Direct Page Out */
@@ -694,7 +692,6 @@ struct se_dev_attrib {
        u32             hw_block_size;
        u32             block_size;
        u32             hw_max_sectors;
-       u32             fabric_max_sectors;
        u32             optimal_sectors;
        u32             hw_queue_depth;
        u32             queue_depth;
index 6edf1f2028cdb0e0801af85183e02d0416fa73ed..86b399c66c3d6d3c5f12d1cd8749777b9d5c89f9 100644 (file)
@@ -146,6 +146,14 @@ TRACE_EVENT(kvm_msi_set_irq,
 
 #if defined(CONFIG_HAVE_KVM_IRQFD)
 
+#ifdef kvm_irqchips
+#define kvm_ack_irq_string "irqchip %s pin %u"
+#define kvm_ack_irq_parm  __print_symbolic(__entry->irqchip, kvm_irqchips), __entry->pin
+#else
+#define kvm_ack_irq_string "irqchip %d pin %u"
+#define kvm_ack_irq_parm  __entry->irqchip, __entry->pin
+#endif
+
 TRACE_EVENT(kvm_ack_irq,
        TP_PROTO(unsigned int irqchip, unsigned int pin),
        TP_ARGS(irqchip, pin),
@@ -160,13 +168,7 @@ TRACE_EVENT(kvm_ack_irq,
                __entry->pin            = pin;
        ),
 
-#ifdef kvm_irqchips
-       TP_printk("irqchip %s pin %u",
-                 __print_symbolic(__entry->irqchip, kvm_irqchips),
-                __entry->pin)
-#else
-       TP_printk("irqchip %d pin %u", __entry->irqchip, __entry->pin)
-#endif
+       TP_printk(kvm_ack_irq_string, kvm_ack_irq_parm)
 );
 
 #endif /* defined(CONFIG_HAVE_KVM_IRQFD) */
index 7543b3e51331fcb38574e3f309713b3a6a2d31c0..e063effe0cc18f0976f01b49cb56c3aeac47bf69 100644 (file)
@@ -5,7 +5,7 @@
 
 /*
  * FMODE_EXEC is 0x20
- * FMODE_NONOTIFY is 0x1000000
+ * FMODE_NONOTIFY is 0x4000000
  * These cannot be used by userspace O_* until internal and external open
  * flags are split.
  * -Eric Paris
index 3e4323a3918d7266efc46edb622636621f042afc..94ffe0c83ce72cf5e396a615fe039bec6fe468d4 100644 (file)
@@ -98,6 +98,7 @@ struct can_ctrlmode {
 #define CAN_CTRLMODE_BERR_REPORTING    0x10    /* Bus-error reporting */
 #define CAN_CTRLMODE_FD                        0x20    /* CAN FD mode */
 #define CAN_CTRLMODE_PRESUME_ACK       0x40    /* Ignore missing CAN ACKs */
+#define CAN_CTRLMODE_FD_NON_ISO                0x80    /* CAN FD in non-ISO mode */
 
 /*
  * CAN device statistics
index 74a2a1773494caba153cf20fc85e56693df15038..79b12b004ade03100930e9dc08f31b329e6398d3 100644 (file)
@@ -149,7 +149,7 @@ struct in6_flowlabel_req {
 /*
  *     IPV6 socket options
  */
-
+#if __UAPI_DEF_IPV6_OPTIONS
 #define IPV6_ADDRFORM          1
 #define IPV6_2292PKTINFO       2
 #define IPV6_2292HOPOPTS       3
@@ -196,6 +196,7 @@ struct in6_flowlabel_req {
 
 #define IPV6_IPSEC_POLICY      34
 #define IPV6_XFRM_POLICY       35
+#endif
 
 /*
  * Multicast:
index 7acef41fc2092abee6e977970ddb22df2952e8f9..af94f31e33ac9d8ccb5f68312feff34ea4eb6aa1 100644 (file)
@@ -128,27 +128,34 @@ struct kfd_ioctl_get_process_apertures_args {
        uint32_t pad;
 };
 
-#define KFD_IOC_MAGIC 'K'
+#define AMDKFD_IOCTL_BASE 'K'
+#define AMDKFD_IO(nr)                  _IO(AMDKFD_IOCTL_BASE, nr)
+#define AMDKFD_IOR(nr, type)           _IOR(AMDKFD_IOCTL_BASE, nr, type)
+#define AMDKFD_IOW(nr, type)           _IOW(AMDKFD_IOCTL_BASE, nr, type)
+#define AMDKFD_IOWR(nr, type)          _IOWR(AMDKFD_IOCTL_BASE, nr, type)
 
-#define KFD_IOC_GET_VERSION \
-               _IOR(KFD_IOC_MAGIC, 1, struct kfd_ioctl_get_version_args)
+#define AMDKFD_IOC_GET_VERSION                 \
+               AMDKFD_IOR(0x01, struct kfd_ioctl_get_version_args)
 
-#define KFD_IOC_CREATE_QUEUE \
-               _IOWR(KFD_IOC_MAGIC, 2, struct kfd_ioctl_create_queue_args)
+#define AMDKFD_IOC_CREATE_QUEUE                        \
+               AMDKFD_IOWR(0x02, struct kfd_ioctl_create_queue_args)
 
-#define KFD_IOC_DESTROY_QUEUE \
-       _IOWR(KFD_IOC_MAGIC, 3, struct kfd_ioctl_destroy_queue_args)
+#define AMDKFD_IOC_DESTROY_QUEUE               \
+               AMDKFD_IOWR(0x03, struct kfd_ioctl_destroy_queue_args)
 
-#define KFD_IOC_SET_MEMORY_POLICY \
-       _IOW(KFD_IOC_MAGIC, 4, struct kfd_ioctl_set_memory_policy_args)
+#define AMDKFD_IOC_SET_MEMORY_POLICY           \
+               AMDKFD_IOW(0x04, struct kfd_ioctl_set_memory_policy_args)
 
-#define KFD_IOC_GET_CLOCK_COUNTERS \
-       _IOWR(KFD_IOC_MAGIC, 5, struct kfd_ioctl_get_clock_counters_args)
+#define AMDKFD_IOC_GET_CLOCK_COUNTERS          \
+               AMDKFD_IOWR(0x05, struct kfd_ioctl_get_clock_counters_args)
 
-#define KFD_IOC_GET_PROCESS_APERTURES \
-       _IOR(KFD_IOC_MAGIC, 6, struct kfd_ioctl_get_process_apertures_args)
+#define AMDKFD_IOC_GET_PROCESS_APERTURES       \
+               AMDKFD_IOR(0x06, struct kfd_ioctl_get_process_apertures_args)
 
-#define KFD_IOC_UPDATE_QUEUE \
-       _IOW(KFD_IOC_MAGIC, 7, struct kfd_ioctl_update_queue_args)
+#define AMDKFD_IOC_UPDATE_QUEUE                        \
+               AMDKFD_IOW(0x07, struct kfd_ioctl_update_queue_args)
+
+#define AMDKFD_COMMAND_START           0x01
+#define AMDKFD_COMMAND_END             0x08
 
 #endif
index c140620dad921a12bc36ac477911e12665d9a736..e28807ad17fa8dffb69879e1c0eaf23bf8971f88 100644 (file)
@@ -69,6 +69,7 @@
 #define __UAPI_DEF_SOCKADDR_IN6                0
 #define __UAPI_DEF_IPV6_MREQ           0
 #define __UAPI_DEF_IPPROTO_V6          0
+#define __UAPI_DEF_IPV6_OPTIONS                0
 
 #else
 
@@ -82,6 +83,7 @@
 #define __UAPI_DEF_SOCKADDR_IN6                1
 #define __UAPI_DEF_IPV6_MREQ           1
 #define __UAPI_DEF_IPPROTO_V6          1
+#define __UAPI_DEF_IPV6_OPTIONS                1
 
 #endif /* _NETINET_IN_H */
 
 #define __UAPI_DEF_SOCKADDR_IN6                1
 #define __UAPI_DEF_IPV6_MREQ           1
 #define __UAPI_DEF_IPPROTO_V6          1
+#define __UAPI_DEF_IPV6_OPTIONS                1
 
 /* Definitions for xattr.h */
 #define __UAPI_DEF_XATTR               1
index 3a6dcaa359b768d09bfc58f71c0f9b23582d9f24..f714e863335204a4c3e29525e41605f3a9e0f0f4 100644 (file)
@@ -174,6 +174,10 @@ enum ovs_packet_attr {
        OVS_PACKET_ATTR_USERDATA,    /* OVS_ACTION_ATTR_USERSPACE arg. */
        OVS_PACKET_ATTR_EGRESS_TUN_KEY,  /* Nested OVS_TUNNEL_KEY_ATTR_*
                                            attributes. */
+       OVS_PACKET_ATTR_UNUSED1,
+       OVS_PACKET_ATTR_UNUSED2,
+       OVS_PACKET_ATTR_PROBE,      /* Packet operation is a feature probe,
+                                      error logging should be suppressed. */
        __OVS_PACKET_ATTR_MAX
 };
 
index baeab83deb6469c5abb22ac61ee07f73b0dfedfe..013c9d8db3720cc1c606323def3e47692702cfa2 100644 (file)
@@ -82,7 +82,7 @@ struct uinput_ff_erase {
  * The complete sysfs path is then /sys/devices/virtual/input/--NAME--
  * Usually, it is in the form "inputN"
  */
-#define UI_GET_SYSNAME(len)    _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 300, len)
+#define UI_GET_SYSNAME(len)    _IOC(_IOC_READ, UINPUT_IOCTL_BASE, 44, len)
 
 /**
  * UI_GET_VERSION - Return version of uinput protocol
@@ -91,7 +91,7 @@ struct uinput_ff_erase {
  * the integer pointed to by the ioctl argument. The protocol version
  * is hard-coded in the kernel and is independent of the uinput device.
  */
-#define UI_GET_VERSION         _IOR(UINPUT_IOCTL_BASE, 301, unsigned int)
+#define UI_GET_VERSION         _IOR(UINPUT_IOCTL_BASE, 45, unsigned int)
 
 /*
  * To write a force-feedback-capable driver, the upload_effect
index 61c818a7fe70dfca4d26b2ef7f4269e9da22233f..a3318f31e8e7fd05f317c595e8c4ce3bc3595fac 100644 (file)
@@ -101,6 +101,13 @@ struct vring {
        struct vring_used *used;
 };
 
+/* Alignment requirements for vring elements.
+ * When using pre-virtio 1.0 layout, these fall out naturally.
+ */
+#define VRING_AVAIL_ALIGN_SIZE 2
+#define VRING_USED_ALIGN_SIZE 4
+#define VRING_DESC_ALIGN_SIZE 16
+
 /* The standard layout for the ring is a continuous chunk of memory which looks
  * like this.  We assume num is a power of 2.
  *
diff --git a/include/xen/interface/nmi.h b/include/xen/interface/nmi.h
new file mode 100644 (file)
index 0000000..b47d9d0
--- /dev/null
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * nmi.h
+ *
+ * NMI callback registration and reason codes.
+ *
+ * Copyright (c) 2005, Keir Fraser <keir@xensource.com>
+ */
+
+#ifndef __XEN_PUBLIC_NMI_H__
+#define __XEN_PUBLIC_NMI_H__
+
+#include <xen/interface/xen.h>
+
+/*
+ * NMI reason codes:
+ * Currently these are x86-specific, stored in arch_shared_info.nmi_reason.
+ */
+ /* I/O-check error reported via ISA port 0x61, bit 6. */
+#define _XEN_NMIREASON_io_error     0
+#define XEN_NMIREASON_io_error      (1UL << _XEN_NMIREASON_io_error)
+ /* PCI SERR reported via ISA port 0x61, bit 7. */
+#define _XEN_NMIREASON_pci_serr     1
+#define XEN_NMIREASON_pci_serr      (1UL << _XEN_NMIREASON_pci_serr)
+ /* Unknown hardware-generated NMI. */
+#define _XEN_NMIREASON_unknown      2
+#define XEN_NMIREASON_unknown       (1UL << _XEN_NMIREASON_unknown)
+
+/*
+ * long nmi_op(unsigned int cmd, void *arg)
+ * NB. All ops return zero on success, else a negative error code.
+ */
+
+/*
+ * Register NMI callback for this (calling) VCPU. Currently this only makes
+ * sense for domain 0, vcpu 0. All other callers will be returned EINVAL.
+ * arg == pointer to xennmi_callback structure.
+ */
+#define XENNMI_register_callback   0
+struct xennmi_callback {
+    unsigned long handler_address;
+    unsigned long pad;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xennmi_callback);
+
+/*
+ * Deregister NMI callback for this (calling) VCPU.
+ * arg == NULL.
+ */
+#define XENNMI_unregister_callback 1
+
+#endif /* __XEN_PUBLIC_NMI_H__ */
index f8f203e8018c5995b546457342d18f262a2565dc..72ab759a0b43a6400750cefa71650ed64e7a8222 100644 (file)
@@ -429,7 +429,7 @@ static void kauditd_send_skb(struct sk_buff *skb)
  * This function doesn't consume an skb as might be expected since it has to
  * copy it anyways.
  */
-static void kauditd_send_multicast_skb(struct sk_buff *skb)
+static void kauditd_send_multicast_skb(struct sk_buff *skb, gfp_t gfp_mask)
 {
        struct sk_buff          *copy;
        struct audit_net        *aunet = net_generic(&init_net, audit_net_id);
@@ -448,11 +448,11 @@ static void kauditd_send_multicast_skb(struct sk_buff *skb)
         * no reason for new multicast clients to continue with this
         * non-compliance.
         */
-       copy = skb_copy(skb, GFP_KERNEL);
+       copy = skb_copy(skb, gfp_mask);
        if (!copy)
                return;
 
-       nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, GFP_KERNEL);
+       nlmsg_multicast(sock, copy, 0, AUDIT_NLGRP_READLOG, gfp_mask);
 }
 
 /*
@@ -1100,7 +1100,7 @@ static void audit_receive(struct sk_buff  *skb)
 }
 
 /* Run custom bind function on netlink socket group connect or bind requests. */
-static int audit_bind(int group)
+static int audit_bind(struct net *net, int group)
 {
        if (!capable(CAP_AUDIT_READ))
                return -EPERM;
@@ -1940,7 +1940,7 @@ void audit_log_end(struct audit_buffer *ab)
                struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
 
                nlh->nlmsg_len = ab->skb->len;
-               kauditd_send_multicast_skb(ab->skb);
+               kauditd_send_multicast_skb(ab->skb, ab->gfp_mask);
 
                /*
                 * The original kaudit unicast socket sends up messages with
index 3598e13f2a655dbbcfb0df6b6c1bd1afcebd2b8f..4f68a326d92e65883425c3f16f01e78ae55bc255 100644 (file)
@@ -442,19 +442,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
                if ((f->type == AUDIT_LOGINUID) && (f->val == AUDIT_UID_UNSET)) {
                        f->type = AUDIT_LOGINUID_SET;
                        f->val = 0;
-               }
-
-               if ((f->type == AUDIT_PID) || (f->type == AUDIT_PPID)) {
-                       struct pid *pid;
-                       rcu_read_lock();
-                       pid = find_vpid(f->val);
-                       if (!pid) {
-                               rcu_read_unlock();
-                               err = -ESRCH;
-                               goto exit_free;
-                       }
-                       f->val = pid_nr(pid);
-                       rcu_read_unlock();
+                       entry->rule.pflags |= AUDIT_LOGINUID_LEGACY;
                }
 
                err = audit_field_valid(entry, f);
@@ -630,6 +618,13 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
                        data->buflen += data->values[i] =
                                audit_pack_string(&bufp, krule->filterkey);
                        break;
+               case AUDIT_LOGINUID_SET:
+                       if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
+                               data->fields[i] = AUDIT_LOGINUID;
+                               data->values[i] = AUDIT_UID_UNSET;
+                               break;
+                       }
+                       /* fallthrough if set */
                default:
                        data->values[i] = f->val;
                }
@@ -646,6 +641,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
        int i;
 
        if (a->flags != b->flags ||
+           a->pflags != b->pflags ||
            a->listnr != b->listnr ||
            a->action != b->action ||
            a->field_count != b->field_count)
@@ -764,6 +760,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
        new = &entry->rule;
        new->vers_ops = old->vers_ops;
        new->flags = old->flags;
+       new->pflags = old->pflags;
        new->listnr = old->listnr;
        new->action = old->action;
        for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
index c75522a83678d14d542f0e1b25a13180762803ca..072566dd0caf7739fc42b7d59c6791c29dc89343 100644 (file)
@@ -72,6 +72,8 @@
 #include <linux/fs_struct.h>
 #include <linux/compat.h>
 #include <linux/ctype.h>
+#include <linux/string.h>
+#include <uapi/linux/limits.h>
 
 #include "audit.h"
 
@@ -1861,8 +1863,7 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
        }
 
        list_for_each_entry_reverse(n, &context->names_list, list) {
-               /* does the name pointer match? */
-               if (!n->name || n->name->name != name->name)
+               if (!n->name || strcmp(n->name->name, name->name))
                        continue;
 
                /* match the correct record type */
@@ -1877,12 +1878,48 @@ void __audit_inode(struct filename *name, const struct dentry *dentry,
        }
 
 out_alloc:
-       /* unable to find the name from a previous getname(). Allocate a new
-        * anonymous entry.
-        */
-       n = audit_alloc_name(context, AUDIT_TYPE_NORMAL);
+       /* unable to find an entry with both a matching name and type */
+       n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN);
        if (!n)
                return;
+       /* unfortunately, while we may have a path name to record with the
+        * inode, we can't always rely on the string lasting until the end of
+        * the syscall so we need to create our own copy, it may fail due to
+        * memory allocation issues, but we do our best */
+       if (name) {
+               /* we can't use getname_kernel() due to size limits */
+               size_t len = strlen(name->name) + 1;
+               struct filename *new = __getname();
+
+               if (unlikely(!new))
+                       goto out;
+
+               if (len <= (PATH_MAX - sizeof(*new))) {
+                       new->name = (char *)(new) + sizeof(*new);
+                       new->separate = false;
+               } else if (len <= PATH_MAX) {
+                       /* this looks odd, but is due to final_putname() */
+                       struct filename *new2;
+
+                       new2 = kmalloc(sizeof(*new2), GFP_KERNEL);
+                       if (unlikely(!new2)) {
+                               __putname(new);
+                               goto out;
+                       }
+                       new2->name = (char *)new;
+                       new2->separate = true;
+                       new = new2;
+               } else {
+                       /* we should never get here, but let's be safe */
+                       __putname(new);
+                       goto out;
+               }
+               strlcpy((char *)new->name, name->name, len);
+               new->uptr = NULL;
+               new->aname = n;
+               n->name = new;
+               n->name_put = true;
+       }
 out:
        if (parent) {
                n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL;
index d6594e457a25af32e41a4b46a00a43ddf0a2c46b..a64e7a207d2b5cd123b65f7143c6d659c0aed726 100644 (file)
@@ -163,7 +163,7 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
 
 void bpf_jit_binary_free(struct bpf_binary_header *hdr)
 {
-       module_free(NULL, hdr);
+       module_memfree(hdr);
 }
 #endif /* CONFIG_BPF_JIT */
 
index 088ac0b1b106ff772e9122529866eb5406effd14..536edc2be3072e91ab132555fc4f9bc3ce656604 100644 (file)
@@ -150,7 +150,7 @@ static int map_lookup_elem(union bpf_attr *attr)
        int ufd = attr->map_fd;
        struct fd f = fdget(ufd);
        struct bpf_map *map;
-       void *key, *value;
+       void *key, *value, *ptr;
        int err;
 
        if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
@@ -169,20 +169,29 @@ static int map_lookup_elem(union bpf_attr *attr)
        if (copy_from_user(key, ukey, map->key_size) != 0)
                goto free_key;
 
-       err = -ENOENT;
-       rcu_read_lock();
-       value = map->ops->map_lookup_elem(map, key);
+       err = -ENOMEM;
+       value = kmalloc(map->value_size, GFP_USER);
        if (!value)
-               goto err_unlock;
+               goto free_key;
+
+       rcu_read_lock();
+       ptr = map->ops->map_lookup_elem(map, key);
+       if (ptr)
+               memcpy(value, ptr, map->value_size);
+       rcu_read_unlock();
+
+       err = -ENOENT;
+       if (!ptr)
+               goto free_value;
 
        err = -EFAULT;
        if (copy_to_user(uvalue, value, map->value_size) != 0)
-               goto err_unlock;
+               goto free_value;
 
        err = 0;
 
-err_unlock:
-       rcu_read_unlock();
+free_value:
+       kfree(value);
 free_key:
        kfree(key);
 err_put:
index bb263d0caab323810f2c30fc3799be467859a7ac..04cfe8ace52088a4c5ed092c389d08fd99117b19 100644 (file)
@@ -1909,7 +1909,7 @@ static void cgroup_kill_sb(struct super_block *sb)
         *
         * And don't kill the default root.
         */
-       if (css_has_online_children(&root->cgrp.self) ||
+       if (!list_empty(&root->cgrp.self.children) ||
            root == &cgrp_dfl_root)
                cgroup_put(&root->cgrp);
        else
index 1adf62b39b96b496e56ca8484c6939429981277c..07ce18ca71e0cd46b70155269a77b04af23f6526 100644 (file)
@@ -27,6 +27,9 @@
  * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
+
+#define pr_fmt(fmt) "KGDB: " fmt
+
 #include <linux/pid_namespace.h>
 #include <linux/clocksource.h>
 #include <linux/serial_core.h>
@@ -196,8 +199,8 @@ int __weak kgdb_validate_break_address(unsigned long addr)
                return err;
        err = kgdb_arch_remove_breakpoint(&tmp);
        if (err)
-               printk(KERN_ERR "KGDB: Critical breakpoint error, kernel "
-                  "memory destroyed at: %lx", addr);
+               pr_err("Critical breakpoint error, kernel memory destroyed at: %lx\n",
+                      addr);
        return err;
 }
 
@@ -256,8 +259,8 @@ int dbg_activate_sw_breakpoints(void)
                error = kgdb_arch_set_breakpoint(&kgdb_break[i]);
                if (error) {
                        ret = error;
-                       printk(KERN_INFO "KGDB: BP install failed: %lx",
-                              kgdb_break[i].bpt_addr);
+                       pr_info("BP install failed: %lx\n",
+                               kgdb_break[i].bpt_addr);
                        continue;
                }
 
@@ -319,8 +322,8 @@ int dbg_deactivate_sw_breakpoints(void)
                        continue;
                error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
                if (error) {
-                       printk(KERN_INFO "KGDB: BP remove failed: %lx\n",
-                              kgdb_break[i].bpt_addr);
+                       pr_info("BP remove failed: %lx\n",
+                               kgdb_break[i].bpt_addr);
                        ret = error;
                }
 
@@ -367,7 +370,7 @@ int dbg_remove_all_break(void)
                        goto setundefined;
                error = kgdb_arch_remove_breakpoint(&kgdb_break[i]);
                if (error)
-                       printk(KERN_ERR "KGDB: breakpoint remove failed: %lx\n",
+                       pr_err("breakpoint remove failed: %lx\n",
                               kgdb_break[i].bpt_addr);
 setundefined:
                kgdb_break[i].state = BP_UNDEFINED;
@@ -400,9 +403,9 @@ static int kgdb_io_ready(int print_wait)
        if (print_wait) {
 #ifdef CONFIG_KGDB_KDB
                if (!dbg_kdb_mode)
-                       printk(KERN_CRIT "KGDB: waiting... or $3#33 for KDB\n");
+                       pr_crit("waiting... or $3#33 for KDB\n");
 #else
-               printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
+               pr_crit("Waiting for remote debugger\n");
 #endif
        }
        return 1;
@@ -430,8 +433,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
                exception_level = 0;
                kgdb_skipexception(ks->ex_vector, ks->linux_regs);
                dbg_activate_sw_breakpoints();
-               printk(KERN_CRIT "KGDB: re-enter error: breakpoint removed %lx\n",
-                       addr);
+               pr_crit("re-enter error: breakpoint removed %lx\n", addr);
                WARN_ON_ONCE(1);
 
                return 1;
@@ -444,7 +446,7 @@ static int kgdb_reenter_check(struct kgdb_state *ks)
                panic("Recursive entry to debugger");
        }
 
-       printk(KERN_CRIT "KGDB: re-enter exception: ALL breakpoints killed\n");
+       pr_crit("re-enter exception: ALL breakpoints killed\n");
 #ifdef CONFIG_KGDB_KDB
        /* Allow kdb to debug itself one level */
        return 0;
@@ -471,6 +473,7 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
        int cpu;
        int trace_on = 0;
        int online_cpus = num_online_cpus();
+       u64 time_left;
 
        kgdb_info[ks->cpu].enter_kgdb++;
        kgdb_info[ks->cpu].exception_state |= exception_state;
@@ -595,9 +598,13 @@ return_normal:
        /*
         * Wait for the other CPUs to be notified and be waiting for us:
         */
-       while (kgdb_do_roundup && (atomic_read(&masters_in_kgdb) +
-                               atomic_read(&slaves_in_kgdb)) != online_cpus)
+       time_left = loops_per_jiffy * HZ;
+       while (kgdb_do_roundup && --time_left &&
+              (atomic_read(&masters_in_kgdb) + atomic_read(&slaves_in_kgdb)) !=
+                  online_cpus)
                cpu_relax();
+       if (!time_left)
+               pr_crit("KGDB: Timed out waiting for secondary CPUs.\n");
 
        /*
         * At this point the primary processor is completely
@@ -795,15 +802,15 @@ static struct console kgdbcons = {
 static void sysrq_handle_dbg(int key)
 {
        if (!dbg_io_ops) {
-               printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
+               pr_crit("ERROR: No KGDB I/O module available\n");
                return;
        }
        if (!kgdb_connected) {
 #ifdef CONFIG_KGDB_KDB
                if (!dbg_kdb_mode)
-                       printk(KERN_CRIT "KGDB or $3#33 for KDB\n");
+                       pr_crit("KGDB or $3#33 for KDB\n");
 #else
-               printk(KERN_CRIT "Entering KGDB\n");
+               pr_crit("Entering KGDB\n");
 #endif
        }
 
@@ -945,7 +952,7 @@ static void kgdb_initial_breakpoint(void)
 {
        kgdb_break_asap = 0;
 
-       printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
+       pr_crit("Waiting for connection from remote gdb...\n");
        kgdb_breakpoint();
 }
 
@@ -964,8 +971,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
        if (dbg_io_ops) {
                spin_unlock(&kgdb_registration_lock);
 
-               printk(KERN_ERR "kgdb: Another I/O driver is already "
-                               "registered with KGDB.\n");
+               pr_err("Another I/O driver is already registered with KGDB\n");
                return -EBUSY;
        }
 
@@ -981,8 +987,7 @@ int kgdb_register_io_module(struct kgdb_io *new_dbg_io_ops)
 
        spin_unlock(&kgdb_registration_lock);
 
-       printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",
-              new_dbg_io_ops->name);
+       pr_info("Registered I/O driver %s\n", new_dbg_io_ops->name);
 
        /* Arm KGDB now. */
        kgdb_register_callbacks();
@@ -1017,8 +1022,7 @@ void kgdb_unregister_io_module(struct kgdb_io *old_dbg_io_ops)
 
        spin_unlock(&kgdb_registration_lock);
 
-       printk(KERN_INFO
-               "kgdb: Unregistered I/O driver %s, debugger disabled.\n",
+       pr_info("Unregistered I/O driver %s, debugger disabled\n",
                old_dbg_io_ops->name);
 }
 EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
index b20d544f20c2a12c24ac492c4dae56961e0b959d..e1dbf4a2c69e4ca9721c22184cb9f800325b9194 100644 (file)
@@ -531,22 +531,29 @@ void __init kdb_initbptab(void)
        for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++)
                bp->bp_free = 1;
 
-       kdb_register_repeat("bp", kdb_bp, "[<vaddr>]",
-               "Set/Display breakpoints", 0, KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("bl", kdb_bp, "[<vaddr>]",
-               "Display breakpoints", 0, KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("bp", kdb_bp, "[<vaddr>]",
+               "Set/Display breakpoints", 0,
+               KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("bl", kdb_bp, "[<vaddr>]",
+               "Display breakpoints", 0,
+               KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
        if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)
-               kdb_register_repeat("bph", kdb_bp, "[<vaddr>]",
-               "[datar [length]|dataw [length]]   Set hw brk", 0, KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("bc", kdb_bc, "<bpnum>",
-               "Clear Breakpoint", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("be", kdb_bc, "<bpnum>",
-               "Enable Breakpoint", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("bd", kdb_bc, "<bpnum>",
-               "Disable Breakpoint", 0, KDB_REPEAT_NONE);
-
-       kdb_register_repeat("ss", kdb_ss, "",
-               "Single Step", 1, KDB_REPEAT_NO_ARGS);
+               kdb_register_flags("bph", kdb_bp, "[<vaddr>]",
+               "[datar [length]|dataw [length]]   Set hw brk", 0,
+               KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("bc", kdb_bc, "<bpnum>",
+               "Clear Breakpoint", 0,
+               KDB_ENABLE_FLOW_CTRL);
+       kdb_register_flags("be", kdb_bc, "<bpnum>",
+               "Enable Breakpoint", 0,
+               KDB_ENABLE_FLOW_CTRL);
+       kdb_register_flags("bd", kdb_bc, "<bpnum>",
+               "Disable Breakpoint", 0,
+               KDB_ENABLE_FLOW_CTRL);
+
+       kdb_register_flags("ss", kdb_ss, "",
+               "Single Step", 1,
+               KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS);
        /*
         * Architecture dependent initialization.
         */
index 8859ca34dcfe0a58dbd530b8668d8d88760a3eb4..15e1a7af5dd033f130ef2b4ed96cf1e2809442f5 100644 (file)
@@ -129,6 +129,10 @@ int kdb_stub(struct kgdb_state *ks)
                ks->pass_exception = 1;
                KDB_FLAG_SET(CATASTROPHIC);
        }
+       /* set CATASTROPHIC if the system contains unresponsive processors */
+       for_each_online_cpu(i)
+               if (!kgdb_info[i].enter_kgdb)
+                       KDB_FLAG_SET(CATASTROPHIC);
        if (KDB_STATE(SSBPT) && reason == KDB_REASON_SSTEP) {
                KDB_STATE_CLEAR(SSBPT);
                KDB_STATE_CLEAR(DOING_SS);
index 379650b984f8150bd7ead11fa57767261ce21758..7b40c5f07dce8d09e1ebaba547e401b5655befbb 100644 (file)
@@ -12,6 +12,7 @@
  */
 
 #include <linux/ctype.h>
+#include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/kmsg_dump.h>
@@ -23,6 +24,7 @@
 #include <linux/vmalloc.h>
 #include <linux/atomic.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/kallsyms.h>
 #include <linux/slab.h>
 #include "kdb_private.h"
 
+#undef MODULE_PARAM_PREFIX
+#define        MODULE_PARAM_PREFIX "kdb."
+
+static int kdb_cmd_enabled = CONFIG_KDB_DEFAULT_ENABLE;
+module_param_named(cmd_enable, kdb_cmd_enabled, int, 0600);
+
 #define GREP_LEN 256
 char kdb_grep_string[GREP_LEN];
 int kdb_grepping_flag;
@@ -121,6 +129,7 @@ static kdbmsg_t kdbmsgs[] = {
        KDBMSG(BADLENGTH, "Invalid length field"),
        KDBMSG(NOBP, "No Breakpoint exists"),
        KDBMSG(BADADDR, "Invalid address"),
+       KDBMSG(NOPERM, "Permission denied"),
 };
 #undef KDBMSG
 
@@ -187,6 +196,26 @@ struct task_struct *kdb_curr_task(int cpu)
        return p;
 }
 
+/*
+ * Check whether the flags of the current command and the permissions
+ * of the kdb console has allow a command to be run.
+ */
+static inline bool kdb_check_flags(kdb_cmdflags_t flags, int permissions,
+                                  bool no_args)
+{
+       /* permissions comes from userspace so needs massaging slightly */
+       permissions &= KDB_ENABLE_MASK;
+       permissions |= KDB_ENABLE_ALWAYS_SAFE;
+
+       /* some commands change group when launched with no arguments */
+       if (no_args)
+               permissions |= permissions << KDB_ENABLE_NO_ARGS_SHIFT;
+
+       flags |= KDB_ENABLE_ALL;
+
+       return permissions & flags;
+}
+
 /*
  * kdbgetenv - This function will return the character string value of
  *     an environment variable.
@@ -475,6 +504,15 @@ int kdbgetaddrarg(int argc, const char **argv, int *nextarg,
        char *cp;
        kdb_symtab_t symtab;
 
+       /*
+        * If the enable flags prohibit both arbitrary memory access
+        * and flow control then there are no reasonable grounds to
+        * provide symbol lookup.
+        */
+       if (!kdb_check_flags(KDB_ENABLE_MEM_READ | KDB_ENABLE_FLOW_CTRL,
+                            kdb_cmd_enabled, false))
+               return KDB_NOPERM;
+
        /*
         * Process arguments which follow the following syntax:
         *
@@ -641,8 +679,13 @@ static int kdb_defcmd2(const char *cmdstr, const char *argv0)
                if (!s->count)
                        s->usable = 0;
                if (s->usable)
-                       kdb_register(s->name, kdb_exec_defcmd,
-                                    s->usage, s->help, 0);
+                       /* macros are always safe because when executed each
+                        * internal command re-enters kdb_parse() and is
+                        * safety checked individually.
+                        */
+                       kdb_register_flags(s->name, kdb_exec_defcmd, s->usage,
+                                          s->help, 0,
+                                          KDB_ENABLE_ALWAYS_SAFE);
                return 0;
        }
        if (!s->usable)
@@ -1003,25 +1046,22 @@ int kdb_parse(const char *cmdstr)
 
        if (i < kdb_max_commands) {
                int result;
+
+               if (!kdb_check_flags(tp->cmd_flags, kdb_cmd_enabled, argc <= 1))
+                       return KDB_NOPERM;
+
                KDB_STATE_SET(CMD);
                result = (*tp->cmd_func)(argc-1, (const char **)argv);
                if (result && ignore_errors && result > KDB_CMD_GO)
                        result = 0;
                KDB_STATE_CLEAR(CMD);
-               switch (tp->cmd_repeat) {
-               case KDB_REPEAT_NONE:
-                       argc = 0;
-                       if (argv[0])
-                               *(argv[0]) = '\0';
-                       break;
-               case KDB_REPEAT_NO_ARGS:
-                       argc = 1;
-                       if (argv[1])
-                               *(argv[1]) = '\0';
-                       break;
-               case KDB_REPEAT_WITH_ARGS:
-                       break;
-               }
+
+               if (tp->cmd_flags & KDB_REPEAT_WITH_ARGS)
+                       return result;
+
+               argc = tp->cmd_flags & KDB_REPEAT_NO_ARGS ? 1 : 0;
+               if (argv[argc])
+                       *(argv[argc]) = '\0';
                return result;
        }
 
@@ -1921,10 +1961,14 @@ static int kdb_rm(int argc, const char **argv)
  */
 static int kdb_sr(int argc, const char **argv)
 {
+       bool check_mask =
+           !kdb_check_flags(KDB_ENABLE_ALL, kdb_cmd_enabled, false);
+
        if (argc != 1)
                return KDB_ARGCOUNT;
+
        kdb_trap_printk++;
-       __handle_sysrq(*argv[1], false);
+       __handle_sysrq(*argv[1], check_mask);
        kdb_trap_printk--;
 
        return 0;
@@ -1979,7 +2023,7 @@ static int kdb_lsmod(int argc, const char **argv)
                kdb_printf("%-20s%8u  0x%p ", mod->name,
                           mod->core_size, (void *)mod);
 #ifdef CONFIG_MODULE_UNLOAD
-               kdb_printf("%4ld ", module_refcount(mod));
+               kdb_printf("%4d ", module_refcount(mod));
 #endif
                if (mod->state == MODULE_STATE_GOING)
                        kdb_printf(" (Unloading)");
@@ -2157,6 +2201,8 @@ static void kdb_cpu_status(void)
        for (start_cpu = -1, i = 0; i < NR_CPUS; i++) {
                if (!cpu_online(i)) {
                        state = 'F';    /* cpu is offline */
+               } else if (!kgdb_info[i].enter_kgdb) {
+                       state = 'D';    /* cpu is online but unresponsive */
                } else {
                        state = ' ';    /* cpu is responding to kdb */
                        if (kdb_task_state_char(KDB_TSK(i)) == 'I')
@@ -2210,7 +2256,7 @@ static int kdb_cpu(int argc, const char **argv)
        /*
         * Validate cpunum
         */
-       if ((cpunum > NR_CPUS) || !cpu_online(cpunum))
+       if ((cpunum > NR_CPUS) || !kgdb_info[cpunum].enter_kgdb)
                return KDB_BADCPUNUM;
 
        dbg_switch_cpu = cpunum;
@@ -2375,6 +2421,8 @@ static int kdb_help(int argc, const char **argv)
                        return 0;
                if (!kt->cmd_name)
                        continue;
+               if (!kdb_check_flags(kt->cmd_flags, kdb_cmd_enabled, true))
+                       continue;
                if (strlen(kt->cmd_usage) > 20)
                        space = "\n                                    ";
                kdb_printf("%-15.15s %-20s%s%s\n", kt->cmd_name,
@@ -2629,7 +2677,7 @@ static int kdb_grep_help(int argc, const char **argv)
 }
 
 /*
- * kdb_register_repeat - This function is used to register a kernel
+ * kdb_register_flags - This function is used to register a kernel
  *     debugger command.
  * Inputs:
  *     cmd     Command name
@@ -2641,12 +2689,12 @@ static int kdb_grep_help(int argc, const char **argv)
  *     zero for success, one if a duplicate command.
  */
 #define kdb_command_extend 50  /* arbitrary */
-int kdb_register_repeat(char *cmd,
-                       kdb_func_t func,
-                       char *usage,
-                       char *help,
-                       short minlen,
-                       kdb_repeat_t repeat)
+int kdb_register_flags(char *cmd,
+                      kdb_func_t func,
+                      char *usage,
+                      char *help,
+                      short minlen,
+                      kdb_cmdflags_t flags)
 {
        int i;
        kdbtab_t *kp;
@@ -2694,19 +2742,18 @@ int kdb_register_repeat(char *cmd,
        kp->cmd_func   = func;
        kp->cmd_usage  = usage;
        kp->cmd_help   = help;
-       kp->cmd_flags  = 0;
        kp->cmd_minlen = minlen;
-       kp->cmd_repeat = repeat;
+       kp->cmd_flags  = flags;
 
        return 0;
 }
-EXPORT_SYMBOL_GPL(kdb_register_repeat);
+EXPORT_SYMBOL_GPL(kdb_register_flags);
 
 
 /*
  * kdb_register - Compatibility register function for commands that do
  *     not need to specify a repeat state.  Equivalent to
- *     kdb_register_repeat with KDB_REPEAT_NONE.
+ *     kdb_register_flags with flags set to 0.
  * Inputs:
  *     cmd     Command name
  *     func    Function to execute the command
@@ -2721,8 +2768,7 @@ int kdb_register(char *cmd,
             char *help,
             short minlen)
 {
-       return kdb_register_repeat(cmd, func, usage, help, minlen,
-                                  KDB_REPEAT_NONE);
+       return kdb_register_flags(cmd, func, usage, help, minlen, 0);
 }
 EXPORT_SYMBOL_GPL(kdb_register);
 
@@ -2764,80 +2810,109 @@ static void __init kdb_inittab(void)
        for_each_kdbcmd(kp, i)
                kp->cmd_name = NULL;
 
-       kdb_register_repeat("md", kdb_md, "<vaddr>",
+       kdb_register_flags("md", kdb_md, "<vaddr>",
          "Display Memory Contents, also mdWcN, e.g. md8c1", 1,
-                           KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("mdr", kdb_md, "<vaddr> <bytes>",
-         "Display Raw Memory", 0, KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("mdp", kdb_md, "<paddr> <bytes>",
-         "Display Physical Memory", 0, KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("mds", kdb_md, "<vaddr>",
-         "Display Memory Symbolically", 0, KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("mm", kdb_mm, "<vaddr> <contents>",
-         "Modify Memory Contents", 0, KDB_REPEAT_NO_ARGS);
-       kdb_register_repeat("go", kdb_go, "[<vaddr>]",
-         "Continue Execution", 1, KDB_REPEAT_NONE);
-       kdb_register_repeat("rd", kdb_rd, "",
-         "Display Registers", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("rm", kdb_rm, "<reg> <contents>",
-         "Modify Registers", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("ef", kdb_ef, "<vaddr>",
-         "Display exception frame", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("bt", kdb_bt, "[<vaddr>]",
-         "Stack traceback", 1, KDB_REPEAT_NONE);
-       kdb_register_repeat("btp", kdb_bt, "<pid>",
-         "Display stack for process <pid>", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("bta", kdb_bt, "[D|R|S|T|C|Z|E|U|I|M|A]",
-         "Backtrace all processes matching state flag", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("btc", kdb_bt, "",
-         "Backtrace current process on each cpu", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("btt", kdb_bt, "<vaddr>",
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mdr", kdb_md, "<vaddr> <bytes>",
+         "Display Raw Memory", 0,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mdp", kdb_md, "<paddr> <bytes>",
+         "Display Physical Memory", 0,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mds", kdb_md, "<vaddr>",
+         "Display Memory Symbolically", 0,
+         KDB_ENABLE_MEM_READ | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("mm", kdb_mm, "<vaddr> <contents>",
+         "Modify Memory Contents", 0,
+         KDB_ENABLE_MEM_WRITE | KDB_REPEAT_NO_ARGS);
+       kdb_register_flags("go", kdb_go, "[<vaddr>]",
+         "Continue Execution", 1,
+         KDB_ENABLE_REG_WRITE | KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
+       kdb_register_flags("rd", kdb_rd, "",
+         "Display Registers", 0,
+         KDB_ENABLE_REG_READ);
+       kdb_register_flags("rm", kdb_rm, "<reg> <contents>",
+         "Modify Registers", 0,
+         KDB_ENABLE_REG_WRITE);
+       kdb_register_flags("ef", kdb_ef, "<vaddr>",
+         "Display exception frame", 0,
+         KDB_ENABLE_MEM_READ);
+       kdb_register_flags("bt", kdb_bt, "[<vaddr>]",
+         "Stack traceback", 1,
+         KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS);
+       kdb_register_flags("btp", kdb_bt, "<pid>",
+         "Display stack for process <pid>", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("bta", kdb_bt, "[D|R|S|T|C|Z|E|U|I|M|A]",
+         "Backtrace all processes matching state flag", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("btc", kdb_bt, "",
+         "Backtrace current process on each cpu", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("btt", kdb_bt, "<vaddr>",
          "Backtrace process given its struct task address", 0,
-                           KDB_REPEAT_NONE);
-       kdb_register_repeat("env", kdb_env, "",
-         "Show environment variables", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("set", kdb_set, "",
-         "Set environment variables", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("help", kdb_help, "",
-         "Display Help Message", 1, KDB_REPEAT_NONE);
-       kdb_register_repeat("?", kdb_help, "",
-         "Display Help Message", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("cpu", kdb_cpu, "<cpunum>",
-         "Switch to new cpu", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("kgdb", kdb_kgdb, "",
-         "Enter kgdb mode", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("ps", kdb_ps, "[<flags>|A]",
-         "Display active task list", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("pid", kdb_pid, "<pidnum>",
-         "Switch to another task", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("reboot", kdb_reboot, "",
-         "Reboot the machine immediately", 0, KDB_REPEAT_NONE);
+         KDB_ENABLE_MEM_READ | KDB_ENABLE_INSPECT_NO_ARGS);
+       kdb_register_flags("env", kdb_env, "",
+         "Show environment variables", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("set", kdb_set, "",
+         "Set environment variables", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("help", kdb_help, "",
+         "Display Help Message", 1,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("?", kdb_help, "",
+         "Display Help Message", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("cpu", kdb_cpu, "<cpunum>",
+         "Switch to new cpu", 0,
+         KDB_ENABLE_ALWAYS_SAFE_NO_ARGS);
+       kdb_register_flags("kgdb", kdb_kgdb, "",
+         "Enter kgdb mode", 0, 0);
+       kdb_register_flags("ps", kdb_ps, "[<flags>|A]",
+         "Display active task list", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("pid", kdb_pid, "<pidnum>",
+         "Switch to another task", 0,
+         KDB_ENABLE_INSPECT);
+       kdb_register_flags("reboot", kdb_reboot, "",
+         "Reboot the machine immediately", 0,
+         KDB_ENABLE_REBOOT);
 #if defined(CONFIG_MODULES)
-       kdb_register_repeat("lsmod", kdb_lsmod, "",
-         "List loaded kernel modules", 0, KDB_REPEAT_NONE);
+       kdb_register_flags("lsmod", kdb_lsmod, "",
+         "List loaded kernel modules", 0,
+         KDB_ENABLE_INSPECT);
 #endif
 #if defined(CONFIG_MAGIC_SYSRQ)
-       kdb_register_repeat("sr", kdb_sr, "<key>",
-         "Magic SysRq key", 0, KDB_REPEAT_NONE);
+       kdb_register_flags("sr", kdb_sr, "<key>",
+         "Magic SysRq key", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
 #endif
 #if defined(CONFIG_PRINTK)
-       kdb_register_repeat("dmesg", kdb_dmesg, "[lines]",
-         "Display syslog buffer", 0, KDB_REPEAT_NONE);
+       kdb_register_flags("dmesg", kdb_dmesg, "[lines]",
+         "Display syslog buffer", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
 #endif
        if (arch_kgdb_ops.enable_nmi) {
-               kdb_register_repeat("disable_nmi", kdb_disable_nmi, "",
-                 "Disable NMI entry to KDB", 0, KDB_REPEAT_NONE);
-       }
-       kdb_register_repeat("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
-         "Define a set of commands, down to endefcmd", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("kill", kdb_kill, "<-signal> <pid>",
-         "Send a signal to a process", 0, KDB_REPEAT_NONE);
-       kdb_register_repeat("summary", kdb_summary, "",
-         "Summarize the system", 4, KDB_REPEAT_NONE);
-       kdb_register_repeat("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]",
-         "Display per_cpu variables", 3, KDB_REPEAT_NONE);
-       kdb_register_repeat("grephelp", kdb_grep_help, "",
-         "Display help on | grep", 0, KDB_REPEAT_NONE);
+               kdb_register_flags("disable_nmi", kdb_disable_nmi, "",
+                 "Disable NMI entry to KDB", 0,
+                 KDB_ENABLE_ALWAYS_SAFE);
+       }
+       kdb_register_flags("defcmd", kdb_defcmd, "name \"usage\" \"help\"",
+         "Define a set of commands, down to endefcmd", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("kill", kdb_kill, "<-signal> <pid>",
+         "Send a signal to a process", 0,
+         KDB_ENABLE_SIGNAL);
+       kdb_register_flags("summary", kdb_summary, "",
+         "Summarize the system", 4,
+         KDB_ENABLE_ALWAYS_SAFE);
+       kdb_register_flags("per_cpu", kdb_per_cpu, "<sym> [<bytes>] [<cpu>]",
+         "Display per_cpu variables", 3,
+         KDB_ENABLE_MEM_READ);
+       kdb_register_flags("grephelp", kdb_grep_help, "",
+         "Display help on | grep", 0,
+         KDB_ENABLE_ALWAYS_SAFE);
 }
 
 /* Execute any commands defined in kdb_cmds.  */
index 7afd3c8c41d5d51f17a7a14566551bf2d731d068..eaacd1693954b13aa55c59028c597b6ed91488f3 100644 (file)
@@ -172,10 +172,9 @@ typedef struct _kdbtab {
        kdb_func_t cmd_func;            /* Function to execute command */
        char    *cmd_usage;             /* Usage String for this command */
        char    *cmd_help;              /* Help message for this command */
-       short    cmd_flags;             /* Parsing flags */
        short    cmd_minlen;            /* Minimum legal # command
                                         * chars required */
-       kdb_repeat_t cmd_repeat;        /* Does command auto repeat on enter? */
+       kdb_cmdflags_t cmd_flags;       /* Command behaviour flags */
 } kdbtab_t;
 
 extern int kdb_bt(int, const char **); /* KDB display back trace */
index 4c1ee7f2bebc4bfb1434fe472f0d66f120f8cdc0..19efcf13375a2960e6d8e6994a8aa660d6221253 100644 (file)
@@ -4461,18 +4461,14 @@ perf_output_sample_regs(struct perf_output_handle *handle,
 }
 
 static void perf_sample_regs_user(struct perf_regs *regs_user,
-                                 struct pt_regs *regs)
+                                 struct pt_regs *regs,
+                                 struct pt_regs *regs_user_copy)
 {
-       if (!user_mode(regs)) {
-               if (current->mm)
-                       regs = task_pt_regs(current);
-               else
-                       regs = NULL;
-       }
-
-       if (regs) {
-               regs_user->abi  = perf_reg_abi(current);
+       if (user_mode(regs)) {
+               regs_user->abi = perf_reg_abi(current);
                regs_user->regs = regs;
+       } else if (current->mm) {
+               perf_get_regs_user(regs_user, regs, regs_user_copy);
        } else {
                regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
                regs_user->regs = NULL;
@@ -4951,7 +4947,8 @@ void perf_prepare_sample(struct perf_event_header *header,
        }
 
        if (sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER))
-               perf_sample_regs_user(&data->regs_user, regs);
+               perf_sample_regs_user(&data->regs_user, regs,
+                                     &data->regs_user_copy);
 
        if (sample_type & PERF_SAMPLE_REGS_USER) {
                /* regs dump ABI info */
@@ -6779,7 +6776,6 @@ skip_type:
                __perf_event_init_context(&cpuctx->ctx);
                lockdep_set_class(&cpuctx->ctx.mutex, &cpuctx_mutex);
                lockdep_set_class(&cpuctx->ctx.lock, &cpuctx_lock);
-               cpuctx->ctx.type = cpu_context;
                cpuctx->ctx.pmu = pmu;
 
                __perf_cpu_hrtimer_init(cpuctx, cpu);
@@ -7423,7 +7419,19 @@ SYSCALL_DEFINE5(perf_event_open,
                 * task or CPU context:
                 */
                if (move_group) {
-                       if (group_leader->ctx->type != ctx->type)
+                       /*
+                        * Make sure we're both on the same task, or both
+                        * per-cpu events.
+                        */
+                       if (group_leader->ctx->task != ctx->task)
+                               goto err_context;
+
+                       /*
+                        * Make sure we're both events for the same CPU;
+                        * grouping events for different CPUs is broken; since
+                        * you can never concurrently schedule them anyhow.
+                        */
+                       if (group_leader->cpu != event->cpu)
                                goto err_context;
                } else {
                        if (group_leader->ctx != ctx)
index 1ea4369890a31b6776aeb85bada4bf097594cce2..6806c55475eec17be40b1d6c53cf9fe007376279 100644 (file)
@@ -1287,9 +1287,15 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
 static int wait_consider_task(struct wait_opts *wo, int ptrace,
                                struct task_struct *p)
 {
+       /*
+        * We can race with wait_task_zombie() from another thread.
+        * Ensure that EXIT_ZOMBIE -> EXIT_DEAD/EXIT_TRACE transition
+        * can't confuse the checks below.
+        */
+       int exit_state = ACCESS_ONCE(p->exit_state);
        int ret;
 
-       if (unlikely(p->exit_state == EXIT_DEAD))
+       if (unlikely(exit_state == EXIT_DEAD))
                return 0;
 
        ret = eligible_child(wo, p);
@@ -1310,7 +1316,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
                return 0;
        }
 
-       if (unlikely(p->exit_state == EXIT_TRACE)) {
+       if (unlikely(exit_state == EXIT_TRACE)) {
                /*
                 * ptrace == 0 means we are the natural parent. In this case
                 * we should clear notask_error, debugger will notify us.
@@ -1337,7 +1343,7 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
        }
 
        /* slay zombie? */
-       if (p->exit_state == EXIT_ZOMBIE) {
+       if (exit_state == EXIT_ZOMBIE) {
                /* we don't reap group leaders with subthreads */
                if (!delay_group_leader(p)) {
                        /*
index 06f58309fed2d082b7a859f3effa5b2562e4d447..ee619929cf9091059406e8f82df32c50d609c0d9 100644 (file)
@@ -127,7 +127,7 @@ static void *alloc_insn_page(void)
 
 static void free_insn_page(void *page)
 {
-       module_free(NULL, page);
+       module_memfree(page);
 }
 
 struct kprobe_insn_cache kprobe_insn_slots = {
index 5cf6731b98e9ecf1ffffa754371701613cc64bcb..3ef3736002d895854794a4d940adcd96288640f2 100644 (file)
@@ -80,13 +80,13 @@ void debug_mutex_unlock(struct mutex *lock)
                        DEBUG_LOCKS_WARN_ON(lock->owner != current);
 
                DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next);
-               mutex_clear_owner(lock);
        }
 
        /*
         * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug
         * mutexes so that we can do it here after we've verified state.
         */
+       mutex_clear_owner(lock);
        atomic_set(&lock->count, 1);
 }
 
index 3965511ae1333d5bcf0d50ac43bd031be76a823b..d856e96a3cce440f4c9bb0bc5e7fbf2eee4b1afe 100644 (file)
@@ -772,9 +772,18 @@ static int try_stop_module(struct module *mod, int flags, int *forced)
        return 0;
 }
 
-unsigned long module_refcount(struct module *mod)
+/**
+ * module_refcount - return the refcount or -1 if unloading
+ *
+ * @mod:       the module we're checking
+ *
+ * Returns:
+ *     -1 if the module is in the process of unloading
+ *     otherwise the number of references in the kernel to the module
+ */
+int module_refcount(struct module *mod)
 {
-       return (unsigned long)atomic_read(&mod->refcnt) - MODULE_REF_BASE;
+       return atomic_read(&mod->refcnt) - MODULE_REF_BASE;
 }
 EXPORT_SYMBOL(module_refcount);
 
@@ -856,7 +865,7 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod)
        struct module_use *use;
        int printed_something = 0;
 
-       seq_printf(m, " %lu ", module_refcount(mod));
+       seq_printf(m, " %i ", module_refcount(mod));
 
        /*
         * Always include a trailing , so userspace can differentiate
@@ -908,7 +917,7 @@ EXPORT_SYMBOL_GPL(symbol_put_addr);
 static ssize_t show_refcnt(struct module_attribute *mattr,
                           struct module_kobject *mk, char *buffer)
 {
-       return sprintf(buffer, "%lu\n", module_refcount(mk->mod));
+       return sprintf(buffer, "%i\n", module_refcount(mk->mod));
 }
 
 static struct module_attribute modinfo_refcnt =
@@ -1795,7 +1804,7 @@ static void unset_module_core_ro_nx(struct module *mod) { }
 static void unset_module_init_ro_nx(struct module *mod) { }
 #endif
 
-void __weak module_free(struct module *mod, void *module_region)
+void __weak module_memfree(void *module_region)
 {
        vfree(module_region);
 }
@@ -1804,6 +1813,10 @@ void __weak module_arch_cleanup(struct module *mod)
 {
 }
 
+void __weak module_arch_freeing_init(struct module *mod)
+{
+}
+
 /* Free a module, remove from lists, etc. */
 static void free_module(struct module *mod)
 {
@@ -1841,7 +1854,8 @@ static void free_module(struct module *mod)
 
        /* This may be NULL, but that's OK */
        unset_module_init_ro_nx(mod);
-       module_free(mod, mod->module_init);
+       module_arch_freeing_init(mod);
+       module_memfree(mod->module_init);
        kfree(mod->args);
        percpu_modfree(mod);
 
@@ -1850,7 +1864,7 @@ static void free_module(struct module *mod)
 
        /* Finally, free the core (containing the module structure) */
        unset_module_core_ro_nx(mod);
-       module_free(mod, mod->module_core);
+       module_memfree(mod->module_core);
 
 #ifdef CONFIG_MPU
        update_protections(current->mm);
@@ -2785,7 +2799,7 @@ static int move_module(struct module *mod, struct load_info *info)
                 */
                kmemleak_ignore(ptr);
                if (!ptr) {
-                       module_free(mod, mod->module_core);
+                       module_memfree(mod->module_core);
                        return -ENOMEM;
                }
                memset(ptr, 0, mod->init_size);
@@ -2930,8 +2944,9 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 static void module_deallocate(struct module *mod, struct load_info *info)
 {
        percpu_modfree(mod);
-       module_free(mod, mod->module_init);
-       module_free(mod, mod->module_core);
+       module_arch_freeing_init(mod);
+       module_memfree(mod->module_init);
+       module_memfree(mod->module_core);
 }
 
 int __weak module_finalize(const Elf_Ehdr *hdr,
@@ -2983,10 +2998,31 @@ static void do_mod_ctors(struct module *mod)
 #endif
 }
 
+/* For freeing module_init on success, in case kallsyms traversing */
+struct mod_initfree {
+       struct rcu_head rcu;
+       void *module_init;
+};
+
+static void do_free_init(struct rcu_head *head)
+{
+       struct mod_initfree *m = container_of(head, struct mod_initfree, rcu);
+       module_memfree(m->module_init);
+       kfree(m);
+}
+
 /* This is where the real work happens */
 static int do_init_module(struct module *mod)
 {
        int ret = 0;
+       struct mod_initfree *freeinit;
+
+       freeinit = kmalloc(sizeof(*freeinit), GFP_KERNEL);
+       if (!freeinit) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       freeinit->module_init = mod->module_init;
 
        /*
         * We want to find out whether @mod uses async during init.  Clear
@@ -2999,18 +3035,7 @@ static int do_init_module(struct module *mod)
        if (mod->init != NULL)
                ret = do_one_initcall(mod->init);
        if (ret < 0) {
-               /*
-                * Init routine failed: abort.  Try to protect us from
-                * buggy refcounters.
-                */
-               mod->state = MODULE_STATE_GOING;
-               synchronize_sched();
-               module_put(mod);
-               blocking_notifier_call_chain(&module_notify_list,
-                                            MODULE_STATE_GOING, mod);
-               free_module(mod);
-               wake_up_all(&module_wq);
-               return ret;
+               goto fail_free_freeinit;
        }
        if (ret > 0) {
                pr_warn("%s: '%s'->init suspiciously returned %d, it should "
@@ -3055,15 +3080,35 @@ static int do_init_module(struct module *mod)
        mod->strtab = mod->core_strtab;
 #endif
        unset_module_init_ro_nx(mod);
-       module_free(mod, mod->module_init);
+       module_arch_freeing_init(mod);
        mod->module_init = NULL;
        mod->init_size = 0;
        mod->init_ro_size = 0;
        mod->init_text_size = 0;
+       /*
+        * We want to free module_init, but be aware that kallsyms may be
+        * walking this with preempt disabled.  In all the failure paths,
+        * we call synchronize_rcu/synchronize_sched, but we don't want
+        * to slow down the success path, so use actual RCU here.
+        */
+       call_rcu(&freeinit->rcu, do_free_init);
        mutex_unlock(&module_mutex);
        wake_up_all(&module_wq);
 
        return 0;
+
+fail_free_freeinit:
+       kfree(freeinit);
+fail:
+       /* Try to protect us from buggy refcounters. */
+       mod->state = MODULE_STATE_GOING;
+       synchronize_sched();
+       module_put(mod);
+       blocking_notifier_call_chain(&module_notify_list,
+                                    MODULE_STATE_GOING, mod);
+       free_module(mod);
+       wake_up_all(&module_wq);
+       return ret;
 }
 
 static int may_init_module(void)
index 0af9b2c4e56c6cf604699096d0ac4d44c874b36e..728e05b167de984afe2e815f63207952051c3915 100644 (file)
@@ -642,12 +642,15 @@ static __modinit int add_sysfs_param(struct module_kobject *mk,
        mk->mp->grp.attrs = new_attrs;
 
        /* Tack new one on the end. */
+       memset(&mk->mp->attrs[mk->mp->num], 0, sizeof(mk->mp->attrs[0]));
        sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr);
        mk->mp->attrs[mk->mp->num].param = kp;
        mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show;
        /* Do not allow runtime DAC changes to make param writable. */
        if ((kp->perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0)
                mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store;
+       else
+               mk->mp->attrs[mk->mp->num].mattr.store = NULL;
        mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name;
        mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm;
        mk->mp->num++;
index 322ea8e93e4ba36c11c0348a34c12e58c983da03..82cfc285b046d8e320559a48cf08007a19742dc0 100644 (file)
@@ -113,12 +113,12 @@ static int cmp_range(const void *x1, const void *x2)
 {
        const struct range *r1 = x1;
        const struct range *r2 = x2;
-       s64 start1, start2;
 
-       start1 = r1->start;
-       start2 = r2->start;
-
-       return start1 - start2;
+       if (r1->start < r2->start)
+               return -1;
+       if (r1->start > r2->start)
+               return 1;
+       return 0;
 }
 
 int clean_sort_range(struct range *range, int az)
index b5797b78add65d967ab22f91c9f05182da0de2b4..e628cb11b5606306e11f456471022fa65488976b 100644 (file)
@@ -7112,9 +7112,6 @@ void __init sched_init(void)
 #endif
 #ifdef CONFIG_RT_GROUP_SCHED
        alloc_size += 2 * nr_cpu_ids * sizeof(void **);
-#endif
-#ifdef CONFIG_CPUMASK_OFFSTACK
-       alloc_size += num_possible_cpus() * cpumask_size();
 #endif
        if (alloc_size) {
                ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT);
@@ -7135,13 +7132,13 @@ void __init sched_init(void)
                ptr += nr_cpu_ids * sizeof(void **);
 
 #endif /* CONFIG_RT_GROUP_SCHED */
+       }
 #ifdef CONFIG_CPUMASK_OFFSTACK
-               for_each_possible_cpu(i) {
-                       per_cpu(load_balance_mask, i) = (void *)ptr;
-                       ptr += cpumask_size();
-               }
-#endif /* CONFIG_CPUMASK_OFFSTACK */
+       for_each_possible_cpu(i) {
+               per_cpu(load_balance_mask, i) = (cpumask_var_t)kzalloc_node(
+                       cpumask_size(), GFP_KERNEL, cpu_to_node(i));
        }
+#endif /* CONFIG_CPUMASK_OFFSTACK */
 
        init_rt_bandwidth(&def_rt_bandwidth,
                        global_rt_period(), global_rt_runtime());
@@ -7295,13 +7292,12 @@ void __might_sleep(const char *file, int line, int preempt_offset)
         * since we will exit with TASK_RUNNING make sure we enter with it,
         * otherwise we will destroy state.
         */
-       if (WARN_ONCE(current->state != TASK_RUNNING,
+       WARN_ONCE(current->state != TASK_RUNNING && current->task_state_change,
                        "do not call blocking ops when !TASK_RUNNING; "
                        "state=%lx set at [<%p>] %pS\n",
                        current->state,
                        (void *)current->task_state_change,
-                       (void *)current->task_state_change))
-               __set_current_state(TASK_RUNNING);
+                       (void *)current->task_state_change);
 
        ___might_sleep(file, line, preempt_offset);
 }
index e5db8c6feebd7e319b20b482885a1bd5e8ad3be1..b52092f2636d50e8a816b2e7e20a648b00d6bb70 100644 (file)
@@ -570,24 +570,7 @@ void init_dl_task_timer(struct sched_dl_entity *dl_se)
 static
 int dl_runtime_exceeded(struct rq *rq, struct sched_dl_entity *dl_se)
 {
-       int dmiss = dl_time_before(dl_se->deadline, rq_clock(rq));
-       int rorun = dl_se->runtime <= 0;
-
-       if (!rorun && !dmiss)
-               return 0;
-
-       /*
-        * If we are beyond our current deadline and we are still
-        * executing, then we have already used some of the runtime of
-        * the next instance. Thus, if we do not account that, we are
-        * stealing bandwidth from the system at each deadline miss!
-        */
-       if (dmiss) {
-               dl_se->runtime = rorun ? dl_se->runtime : 0;
-               dl_se->runtime -= rq_clock(rq) - dl_se->deadline;
-       }
-
-       return 1;
+       return (dl_se->runtime <= 0);
 }
 
 extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
@@ -826,10 +809,10 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se,
         * parameters of the task might need updating. Otherwise,
         * we want a replenishment of its runtime.
         */
-       if (!dl_se->dl_new && flags & ENQUEUE_REPLENISH)
-               replenish_dl_entity(dl_se, pi_se);
-       else
+       if (dl_se->dl_new || flags & ENQUEUE_WAKEUP)
                update_dl_entity(dl_se, pi_se);
+       else if (flags & ENQUEUE_REPLENISH)
+               replenish_dl_entity(dl_se, pi_se);
 
        __enqueue_dl_entity(dl_se);
 }
index df2cdf77f8998d46f58cbf4bc0b3693311c96911..40667cbf371ba9e8732e6c30940cc146752ee0c3 100644 (file)
@@ -4005,6 +4005,10 @@ void __start_cfs_bandwidth(struct cfs_bandwidth *cfs_b, bool force)
 
 static void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b)
 {
+       /* init_cfs_bandwidth() was not called */
+       if (!cfs_b->throttled_cfs_rq.next)
+               return;
+
        hrtimer_cancel(&cfs_b->period_timer);
        hrtimer_cancel(&cfs_b->slack_timer);
 }
@@ -4424,7 +4428,7 @@ static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
                 * wl = S * s'_i; see (2)
                 */
                if (W > 0 && w < W)
-                       wl = (w * tg->shares) / W;
+                       wl = (w * (long)tg->shares) / W;
                else
                        wl = tg->shares;
 
index a8c9f5a7dda68f9afd60449a3f9fe0b7d048a6f1..ea9c881098941ecd9bbb42fa69a3ddb958d2ec41 100644 (file)
@@ -2210,9 +2210,13 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                up_write(&me->mm->mmap_sem);
                break;
        case PR_MPX_ENABLE_MANAGEMENT:
+               if (arg2 || arg3 || arg4 || arg5)
+                       return -EINVAL;
                error = MPX_ENABLE_MANAGEMENT(me);
                break;
        case PR_MPX_DISABLE_MANAGEMENT:
+               if (arg2 || arg3 || arg4 || arg5)
+                       return -EINVAL;
                error = MPX_DISABLE_MANAGEMENT(me);
                break;
        default:
index 87a346fd6d61ff1c5c1045c9db063ee3247d2361..28bf91c60a0b412d1c97911659c30d735ba40d78 100644 (file)
@@ -633,6 +633,13 @@ int ntp_validate_timex(struct timex *txc)
        if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
                return -EPERM;
 
+       if (txc->modes & ADJ_FREQUENCY) {
+               if (LONG_MIN / PPM_SCALE > txc->freq)
+                       return -EINVAL;
+               if (LONG_MAX / PPM_SCALE < txc->freq)
+                       return -EINVAL;
+       }
+
        return 0;
 }
 
index 6390517e77d48abb83c0d0ffec27864b4695c4c4..2c85b7724af4b0081a112e1b12cbcce4ef831117 100644 (file)
@@ -196,6 +196,10 @@ SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv,
        if (tv) {
                if (copy_from_user(&user_tv, tv, sizeof(*tv)))
                        return -EFAULT;
+
+               if (!timeval_valid(&user_tv))
+                       return -EINVAL;
+
                new_ts.tv_sec = user_tv.tv_sec;
                new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
        }
index 929a733d302e0d438d2f15f8dfaf6e2e4c56c0d0..224e768bdc738da7c47aca41fcc6d9ecd4c190b4 100644 (file)
@@ -2497,12 +2497,14 @@ static void ftrace_run_update_code(int command)
 }
 
 static void ftrace_run_modify_code(struct ftrace_ops *ops, int command,
-                                  struct ftrace_hash *old_hash)
+                                  struct ftrace_ops_hash *old_hash)
 {
        ops->flags |= FTRACE_OPS_FL_MODIFYING;
-       ops->old_hash.filter_hash = old_hash;
+       ops->old_hash.filter_hash = old_hash->filter_hash;
+       ops->old_hash.notrace_hash = old_hash->notrace_hash;
        ftrace_run_update_code(command);
        ops->old_hash.filter_hash = NULL;
+       ops->old_hash.notrace_hash = NULL;
        ops->flags &= ~FTRACE_OPS_FL_MODIFYING;
 }
 
@@ -3579,7 +3581,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly =
 
 static int ftrace_probe_registered;
 
-static void __enable_ftrace_function_probe(struct ftrace_hash *old_hash)
+static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash)
 {
        int ret;
        int i;
@@ -3637,6 +3639,7 @@ int
 register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
                              void *data)
 {
+       struct ftrace_ops_hash old_hash_ops;
        struct ftrace_func_probe *entry;
        struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;
        struct ftrace_hash *old_hash = *orig_hash;
@@ -3658,6 +3661,10 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
        mutex_lock(&trace_probe_ops.func_hash->regex_lock);
 
+       old_hash_ops.filter_hash = old_hash;
+       /* Probes only have filters */
+       old_hash_ops.notrace_hash = NULL;
+
        hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);
        if (!hash) {
                count = -ENOMEM;
@@ -3718,7 +3725,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
 
        ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash);
 
-       __enable_ftrace_function_probe(old_hash);
+       __enable_ftrace_function_probe(&old_hash_ops);
 
        if (!ret)
                free_ftrace_hash_rcu(old_hash);
@@ -4006,10 +4013,34 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
 }
 
 static void ftrace_ops_update_code(struct ftrace_ops *ops,
-                                  struct ftrace_hash *old_hash)
+                                  struct ftrace_ops_hash *old_hash)
 {
-       if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled)
+       struct ftrace_ops *op;
+
+       if (!ftrace_enabled)
+               return;
+
+       if (ops->flags & FTRACE_OPS_FL_ENABLED) {
                ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash);
+               return;
+       }
+
+       /*
+        * If this is the shared global_ops filter, then we need to
+        * check if there is another ops that shares it, is enabled.
+        * If so, we still need to run the modify code.
+        */
+       if (ops->func_hash != &global_ops.local_hash)
+               return;
+
+       do_for_each_ftrace_op(op, ftrace_ops_list) {
+               if (op->func_hash == &global_ops.local_hash &&
+                   op->flags & FTRACE_OPS_FL_ENABLED) {
+                       ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash);
+                       /* Only need to do this once */
+                       return;
+               }
+       } while_for_each_ftrace_op(op);
 }
 
 static int
@@ -4017,6 +4048,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
                unsigned long ip, int remove, int reset, int enable)
 {
        struct ftrace_hash **orig_hash;
+       struct ftrace_ops_hash old_hash_ops;
        struct ftrace_hash *old_hash;
        struct ftrace_hash *hash;
        int ret;
@@ -4053,9 +4085,11 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
 
        mutex_lock(&ftrace_lock);
        old_hash = *orig_hash;
+       old_hash_ops.filter_hash = ops->func_hash->filter_hash;
+       old_hash_ops.notrace_hash = ops->func_hash->notrace_hash;
        ret = ftrace_hash_move(ops, enable, orig_hash, hash);
        if (!ret) {
-               ftrace_ops_update_code(ops, old_hash);
+               ftrace_ops_update_code(ops, &old_hash_ops);
                free_ftrace_hash_rcu(old_hash);
        }
        mutex_unlock(&ftrace_lock);
@@ -4267,6 +4301,7 @@ static void __init set_ftrace_early_filters(void)
 int ftrace_regex_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = (struct seq_file *)file->private_data;
+       struct ftrace_ops_hash old_hash_ops;
        struct ftrace_iterator *iter;
        struct ftrace_hash **orig_hash;
        struct ftrace_hash *old_hash;
@@ -4300,10 +4335,12 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
 
                mutex_lock(&ftrace_lock);
                old_hash = *orig_hash;
+               old_hash_ops.filter_hash = iter->ops->func_hash->filter_hash;
+               old_hash_ops.notrace_hash = iter->ops->func_hash->notrace_hash;
                ret = ftrace_hash_move(iter->ops, filter_hash,
                                       orig_hash, iter->hash);
                if (!ret) {
-                       ftrace_ops_update_code(iter->ops, old_hash);
+                       ftrace_ops_update_code(iter->ops, &old_hash_ops);
                        free_ftrace_hash_rcu(old_hash);
                }
                mutex_unlock(&ftrace_lock);
index 2e767972e99c2e8791236d10afa717b920543b70..4a9079b9f082fd3bb14e3b46522b1540b001fea1 100644 (file)
@@ -6918,7 +6918,6 @@ void __init trace_init(void)
                        tracepoint_printk = 0;
        }
        tracer_alloc_buffers();
-       init_ftrace_syscalls();
        trace_event_init();     
 }
 
index 366a78a3e61e21a94c06aa96f5b5c02a72c41e78..b03a0ea77b993cf9f175ed7b44fc239832de7def 100644 (file)
@@ -2429,12 +2429,39 @@ static __init int event_trace_memsetup(void)
        return 0;
 }
 
+static __init void
+early_enable_events(struct trace_array *tr, bool disable_first)
+{
+       char *buf = bootup_event_buf;
+       char *token;
+       int ret;
+
+       while (true) {
+               token = strsep(&buf, ",");
+
+               if (!token)
+                       break;
+               if (!*token)
+                       continue;
+
+               /* Restarting syscalls requires that we stop them first */
+               if (disable_first)
+                       ftrace_set_clr_event(tr, token, 0);
+
+               ret = ftrace_set_clr_event(tr, token, 1);
+               if (ret)
+                       pr_warn("Failed to enable trace event: %s\n", token);
+
+               /* Put back the comma to allow this to be called again */
+               if (buf)
+                       *(buf - 1) = ',';
+       }
+}
+
 static __init int event_trace_enable(void)
 {
        struct trace_array *tr = top_trace_array();
        struct ftrace_event_call **iter, *call;
-       char *buf = bootup_event_buf;
-       char *token;
        int ret;
 
        if (!tr)
@@ -2456,18 +2483,7 @@ static __init int event_trace_enable(void)
         */
        __trace_early_add_events(tr);
 
-       while (true) {
-               token = strsep(&buf, ",");
-
-               if (!token)
-                       break;
-               if (!*token)
-                       continue;
-
-               ret = ftrace_set_clr_event(tr, token, 1);
-               if (ret)
-                       pr_warn("Failed to enable trace event: %s\n", token);
-       }
+       early_enable_events(tr, false);
 
        trace_printk_start_comm();
 
@@ -2478,6 +2494,31 @@ static __init int event_trace_enable(void)
        return 0;
 }
 
+/*
+ * event_trace_enable() is called from trace_event_init() first to
+ * initialize events and perhaps start any events that are on the
+ * command line. Unfortunately, there are some events that will not
+ * start this early, like the system call tracepoints that need
+ * to set the TIF_SYSCALL_TRACEPOINT flag of pid 1. But event_trace_enable()
+ * is called before pid 1 starts, and this flag is never set, making
+ * the syscall tracepoint never get reached, but the event is enabled
+ * regardless (and not doing anything).
+ */
+static __init int event_trace_enable_again(void)
+{
+       struct trace_array *tr;
+
+       tr = top_trace_array();
+       if (!tr)
+               return -ENODEV;
+
+       early_enable_events(tr, true);
+
+       return 0;
+}
+
+early_initcall(event_trace_enable_again);
+
 static __init int event_trace_init(void)
 {
        struct trace_array *tr;
index b0b1c44e923a358bffcebda8c24b3d5e861b2693..3ccf5c2c1320131e5b1bc0bfe6a26b02edc402a8 100644 (file)
@@ -132,8 +132,8 @@ static int kdb_ftdump(int argc, const char **argv)
 
 static __init int kdb_ftrace_register(void)
 {
-       kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
-                           "Dump ftrace log", 0, KDB_REPEAT_NONE);
+       kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]",
+                           "Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);
        return 0;
 }
 
index 6202b08f1933bd5eaca37f0e09ff5bbdfbb9f606..beeeac9e0e3e6829faa3fe16304cb3e7adbe8850 100644 (file)
@@ -1841,17 +1841,11 @@ static void pool_mayday_timeout(unsigned long __pool)
  * spin_lock_irq(pool->lock) which may be released and regrabbed
  * multiple times.  Does GFP_KERNEL allocations.  Called only from
  * manager.
- *
- * Return:
- * %false if no action was taken and pool->lock stayed locked, %true
- * otherwise.
  */
-static bool maybe_create_worker(struct worker_pool *pool)
+static void maybe_create_worker(struct worker_pool *pool)
 __releases(&pool->lock)
 __acquires(&pool->lock)
 {
-       if (!need_to_create_worker(pool))
-               return false;
 restart:
        spin_unlock_irq(&pool->lock);
 
@@ -1877,7 +1871,6 @@ restart:
         */
        if (need_to_create_worker(pool))
                goto restart;
-       return true;
 }
 
 /**
@@ -1897,16 +1890,14 @@ restart:
  * multiple times.  Does GFP_KERNEL allocations.
  *
  * Return:
- * %false if the pool don't need management and the caller can safely start
- * processing works, %true indicates that the function released pool->lock
- * and reacquired it to perform some management function and that the
- * conditions that the caller verified while holding the lock before
- * calling the function might no longer be true.
+ * %false if the pool doesn't need management and the caller can safely
+ * start processing works, %true if management function was performed and
+ * the conditions that the caller verified before calling the function may
+ * no longer be true.
  */
 static bool manage_workers(struct worker *worker)
 {
        struct worker_pool *pool = worker->pool;
-       bool ret = false;
 
        /*
         * Anyone who successfully grabs manager_arb wins the arbitration
@@ -1919,12 +1910,12 @@ static bool manage_workers(struct worker *worker)
         * actual management, the pool may stall indefinitely.
         */
        if (!mutex_trylock(&pool->manager_arb))
-               return ret;
+               return false;
 
-       ret |= maybe_create_worker(pool);
+       maybe_create_worker(pool);
 
        mutex_unlock(&pool->manager_arb);
-       return ret;
+       return true;
 }
 
 /**
index 358eb81fa28d1951dc443410a847aeac50ea23bb..c635a107a7dece45eafa5dd30c76b41c4733ffa2 100644 (file)
@@ -73,6 +73,31 @@ config KGDB_KDB
        help
          KDB frontend for kernel
 
+config KDB_DEFAULT_ENABLE
+       hex "KDB: Select kdb command functions to be enabled by default"
+       depends on KGDB_KDB
+       default 0x1
+       help
+         Specifiers which kdb commands are enabled by default. This may
+         be set to 1 or 0 to enable all commands or disable almost all
+         commands.
+
+         Alternatively the following bitmask applies:
+
+           0x0002 - allow arbitrary reads from memory and symbol lookup
+           0x0004 - allow arbitrary writes to memory
+           0x0008 - allow current register state to be inspected
+           0x0010 - allow current register state to be modified
+           0x0020 - allow passive inspection (backtrace, process list, lsmod)
+           0x0040 - allow flow control management (breakpoint, single step)
+           0x0080 - enable signalling of processes
+           0x0100 - allow machine to be rebooted
+
+         The config option merely sets the default at boot time. Both
+         issuing 'echo X > /sys/module/kdb/parameters/cmd_enable' or
+          setting with kdb.cmd_enable=X kernel command line option will
+         override the default settings.
+
 config KDB_KEYBOARD
        bool "KGDB_KDB: keyboard as input device"
        depends on VT && KGDB_KDB
index 2404d03e251a64ae7634d30c46aa22a08f9b4538..03dd576e67730fb2870c44512f55c1c0c39b77f3 100644 (file)
@@ -11,6 +11,7 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 //#define DEBUG
+#include <linux/rcupdate.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/assoc_array_priv.h>
index 56badfc4810a8a4e70597ce82a0532929e6e6dda..957d3da53dddcd53b72da82e39f77d951db57a66 100644 (file)
@@ -14,7 +14,6 @@ config DEBUG_PAGEALLOC
        depends on !KMEMCHECK
        select PAGE_EXTENSION
        select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC
-       select PAGE_GUARD if ARCH_SUPPORTS_DEBUG_PAGEALLOC
        ---help---
          Unmap pages from the kernel linear mapping after free_pages().
          This results in a large slowdown, but helps to find certain types
@@ -27,13 +26,5 @@ config DEBUG_PAGEALLOC
          that would result in incorrect warnings of memory corruption after
          a resume because free pages are not saved to the suspend image.
 
-config WANT_PAGE_DEBUG_FLAGS
-       bool
-
 config PAGE_POISONING
        bool
-       select WANT_PAGE_DEBUG_FLAGS
-
-config PAGE_GUARD
-       bool
-       select WANT_PAGE_DEBUG_FLAGS
index bd8543c6508fd8dfd9e6fce5f4884d1d6ab0b5bb..673e4581a2e541b44b02cd8ef201772dad5311a1 100644 (file)
@@ -1046,8 +1046,7 @@ EXPORT_SYMBOL(find_lock_entry);
  * @mapping: the address_space to search
  * @offset: the page index
  * @fgp_flags: PCG flags
- * @cache_gfp_mask: gfp mask to use for the page cache data page allocation
- * @radix_gfp_mask: gfp mask to use for radix tree node allocation
+ * @gfp_mask: gfp mask to use for the page cache data page allocation
  *
  * Looks up the page cache slot at @mapping & @offset.
  *
@@ -1056,11 +1055,9 @@ EXPORT_SYMBOL(find_lock_entry);
  * FGP_ACCESSED: the page will be marked accessed
  * FGP_LOCK: Page is return locked
  * FGP_CREAT: If page is not present then a new page is allocated using
- *             @cache_gfp_mask and added to the page cache and the VM's LRU
- *             list. If radix tree nodes are allocated during page cache
- *             insertion then @radix_gfp_mask is used. The page is returned
- *             locked and with an increased refcount. Otherwise, %NULL is
- *             returned.
+ *             @gfp_mask and added to the page cache and the VM's LRU
+ *             list. The page is returned locked and with an increased
+ *             refcount. Otherwise, %NULL is returned.
  *
  * If FGP_LOCK or FGP_CREAT are specified then the function may sleep even
  * if the GFP flags specified for FGP_CREAT are atomic.
@@ -1068,7 +1065,7 @@ EXPORT_SYMBOL(find_lock_entry);
  * If there is a page cache page, it is returned with an increased refcount.
  */
 struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset,
-       int fgp_flags, gfp_t cache_gfp_mask, gfp_t radix_gfp_mask)
+       int fgp_flags, gfp_t gfp_mask)
 {
        struct page *page;
 
@@ -1105,13 +1102,11 @@ no_page:
        if (!page && (fgp_flags & FGP_CREAT)) {
                int err;
                if ((fgp_flags & FGP_WRITE) && mapping_cap_account_dirty(mapping))
-                       cache_gfp_mask |= __GFP_WRITE;
-               if (fgp_flags & FGP_NOFS) {
-                       cache_gfp_mask &= ~__GFP_FS;
-                       radix_gfp_mask &= ~__GFP_FS;
-               }
+                       gfp_mask |= __GFP_WRITE;
+               if (fgp_flags & FGP_NOFS)
+                       gfp_mask &= ~__GFP_FS;
 
-               page = __page_cache_alloc(cache_gfp_mask);
+               page = __page_cache_alloc(gfp_mask);
                if (!page)
                        return NULL;
 
@@ -1122,7 +1117,8 @@ no_page:
                if (fgp_flags & FGP_ACCESSED)
                        __SetPageReferenced(page);
 
-               err = add_to_page_cache_lru(page, mapping, offset, radix_gfp_mask);
+               err = add_to_page_cache_lru(page, mapping, offset,
+                               gfp_mask & GFP_RECLAIM_MASK);
                if (unlikely(err)) {
                        page_cache_release(page);
                        page = NULL;
@@ -2443,8 +2439,7 @@ struct page *grab_cache_page_write_begin(struct address_space *mapping,
                fgp_flags |= FGP_NOFS;
 
        page = pagecache_get_page(mapping, index, fgp_flags,
-                       mapping_gfp_mask(mapping),
-                       GFP_KERNEL);
+                       mapping_gfp_mask(mapping));
        if (page)
                wait_for_stable_page(page);
 
index a900759cc8075fc8b0da9a37ebf6f93de34d8d10..8dd50ce6326fd50540b24fe6e93d12546b20594a 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -296,7 +296,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
                        return -ENOMEM;
                if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE))
                        return *flags & FOLL_HWPOISON ? -EHWPOISON : -EFAULT;
-               if (ret & VM_FAULT_SIGBUS)
+               if (ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV))
                        return -EFAULT;
                BUG();
        }
@@ -571,7 +571,7 @@ int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
                        return -ENOMEM;
                if (ret & (VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE))
                        return -EHWPOISON;
-               if (ret & VM_FAULT_SIGBUS)
+               if (ret & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV))
                        return -EFAULT;
                BUG();
        }
index d247efab5073abfaeb9c11e33fb87a2fbb8ebdb0..15647fb0394fabc54b10206bf35590aa69b5830c 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -376,7 +376,7 @@ static int break_ksm(struct vm_area_struct *vma, unsigned long addr)
                else
                        ret = VM_FAULT_WRITE;
                put_page(page);
-       } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_OOM)));
+       } while (!(ret & (VM_FAULT_WRITE | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | VM_FAULT_OOM)));
        /*
         * We must loop because handle_mm_fault() may back out if there's
         * any difficulty e.g. if pte accessed bit gets updated concurrently.
index ef91e856c7e456a0674e7b76e15cbd771a6c9acb..683b4782019b2c32626645155bb8175f3bf3a4a5 100644 (file)
@@ -1477,9 +1477,9 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
 
        pr_info("Task in ");
        pr_cont_cgroup_path(task_cgroup(p, memory_cgrp_id));
-       pr_info(" killed as a result of limit of ");
+       pr_cont(" killed as a result of limit of ");
        pr_cont_cgroup_path(memcg->css.cgroup);
-       pr_info("\n");
+       pr_cont("\n");
 
        rcu_read_unlock();
 
@@ -3043,18 +3043,6 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry,
        if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
                mem_cgroup_swap_statistics(from, false);
                mem_cgroup_swap_statistics(to, true);
-               /*
-                * This function is only called from task migration context now.
-                * It postpones page_counter and refcount handling till the end
-                * of task migration(mem_cgroup_clear_mc()) for performance
-                * improvement. But we cannot postpone css_get(to)  because if
-                * the process that has been moved to @to does swap-in, the
-                * refcount of @to might be decreased to 0.
-                *
-                * We are in attach() phase, so the cgroup is guaranteed to be
-                * alive, so we can just call css_get().
-                */
-               css_get(&to->css);
                return 0;
        }
        return -EINVAL;
@@ -4679,6 +4667,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
        if (parent_css == NULL) {
                root_mem_cgroup = memcg;
                page_counter_init(&memcg->memory, NULL);
+               memcg->soft_limit = PAGE_COUNTER_MAX;
                page_counter_init(&memcg->memsw, NULL);
                page_counter_init(&memcg->kmem, NULL);
        }
@@ -4724,6 +4713,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
 
        if (parent->use_hierarchy) {
                page_counter_init(&memcg->memory, &parent->memory);
+               memcg->soft_limit = PAGE_COUNTER_MAX;
                page_counter_init(&memcg->memsw, &parent->memsw);
                page_counter_init(&memcg->kmem, &parent->kmem);
 
@@ -4733,6 +4723,7 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
                 */
        } else {
                page_counter_init(&memcg->memory, NULL);
+               memcg->soft_limit = PAGE_COUNTER_MAX;
                page_counter_init(&memcg->memsw, NULL);
                page_counter_init(&memcg->kmem, NULL);
                /*
@@ -4807,7 +4798,7 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css)
        mem_cgroup_resize_limit(memcg, PAGE_COUNTER_MAX);
        mem_cgroup_resize_memsw_limit(memcg, PAGE_COUNTER_MAX);
        memcg_update_kmem_limit(memcg, PAGE_COUNTER_MAX);
-       memcg->soft_limit = 0;
+       memcg->soft_limit = PAGE_COUNTER_MAX;
 }
 
 #ifdef CONFIG_MMU
index 649e7d440bd763fa647d47722abb6471cb75ab79..2c3536cc6c6327c9c3e58eddf75c264ddaa11911 100644 (file)
@@ -235,6 +235,9 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long
 
 static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
 {
+       if (!tlb->end)
+               return;
+
        tlb_flush(tlb);
        mmu_notifier_invalidate_range(tlb->mm, tlb->start, tlb->end);
 #ifdef CONFIG_HAVE_RCU_TABLE_FREE
@@ -247,7 +250,7 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)
 {
        struct mmu_gather_batch *batch;
 
-       for (batch = &tlb->local; batch; batch = batch->next) {
+       for (batch = &tlb->local; batch && batch->nr; batch = batch->next) {
                free_pages_and_swap_cache(batch->pages, batch->nr);
                batch->nr = 0;
        }
@@ -256,9 +259,6 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)
 
 void tlb_flush_mmu(struct mmu_gather *tlb)
 {
-       if (!tlb->end)
-               return;
-
        tlb_flush_mmu_tlbonly(tlb);
        tlb_flush_mmu_free(tlb);
 }
@@ -2137,17 +2137,24 @@ reuse:
                if (!dirty_page)
                        return ret;
 
-               /*
-                * Yes, Virginia, this is actually required to prevent a race
-                * with clear_page_dirty_for_io() from clearing the page dirty
-                * bit after it clear all dirty ptes, but before a racing
-                * do_wp_page installs a dirty pte.
-                *
-                * do_shared_fault is protected similarly.
-                */
                if (!page_mkwrite) {
-                       wait_on_page_locked(dirty_page);
-                       set_page_dirty_balance(dirty_page);
+                       struct address_space *mapping;
+                       int dirtied;
+
+                       lock_page(dirty_page);
+                       dirtied = set_page_dirty(dirty_page);
+                       VM_BUG_ON_PAGE(PageAnon(dirty_page), dirty_page);
+                       mapping = dirty_page->mapping;
+                       unlock_page(dirty_page);
+
+                       if (dirtied && mapping) {
+                               /*
+                                * Some device drivers do not set page.mapping
+                                * but still dirty their pages
+                                */
+                               balance_dirty_pages_ratelimited(mapping);
+                       }
+
                        /* file_update_time outside page_lock */
                        if (vma->vm_file)
                                file_update_time(vma->vm_file);
@@ -2378,12 +2385,12 @@ void unmap_mapping_range(struct address_space *mapping,
                details.last_index = ULONG_MAX;
 
 
-       i_mmap_lock_read(mapping);
+       i_mmap_lock_write(mapping);
        if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap)))
                unmap_mapping_range_tree(&mapping->i_mmap, &details);
        if (unlikely(!list_empty(&mapping->i_mmap_nonlinear)))
                unmap_mapping_range_list(&mapping->i_mmap_nonlinear, &details);
-       i_mmap_unlock_read(mapping);
+       i_mmap_unlock_write(mapping);
 }
 EXPORT_SYMBOL(unmap_mapping_range);
 
@@ -2593,7 +2600,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
                if (prev && prev->vm_end == address)
                        return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
 
-               expand_downwards(vma, address - PAGE_SIZE);
+               return expand_downwards(vma, address - PAGE_SIZE);
        }
        if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
                struct vm_area_struct *next = vma->vm_next;
@@ -2602,7 +2609,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
                if (next && next->vm_start == address + PAGE_SIZE)
                        return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
 
-               expand_upwards(vma, address + PAGE_SIZE);
+               return expand_upwards(vma, address + PAGE_SIZE);
        }
        return 0;
 }
@@ -2625,7 +2632,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
 
        /* Check if we need to add a guard page to the stack */
        if (check_stack_guard_page(vma, address) < 0)
-               return VM_FAULT_SIGBUS;
+               return VM_FAULT_SIGSEGV;
 
        /* Use the zero-page for reads */
        if (!(flags & FAULT_FLAG_WRITE) && !mm_forbids_zeropage(mm)) {
index 7b36aa7cc89a43c7c5909b7799b77d13106a2929..7f684d5a808738c3c645798bc6da8b110fbb2383 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -778,10 +778,12 @@ again:                    remove_next = 1 + (end > next->vm_end);
                if (exporter && exporter->anon_vma && !importer->anon_vma) {
                        int error;
 
+                       importer->anon_vma = exporter->anon_vma;
                        error = anon_vma_clone(importer, exporter);
-                       if (error)
+                       if (error) {
+                               importer->anon_vma = NULL;
                                return error;
-                       importer->anon_vma = exporter->anon_vma;
+                       }
                }
        }
 
@@ -2099,14 +2101,17 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns
 {
        struct mm_struct *mm = vma->vm_mm;
        struct rlimit *rlim = current->signal->rlim;
-       unsigned long new_start;
+       unsigned long new_start, actual_size;
 
        /* address space limit tests */
        if (!may_expand_vm(mm, grow))
                return -ENOMEM;
 
        /* Stack limit test */
-       if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur))
+       actual_size = size;
+       if (size && (vma->vm_flags & (VM_GROWSUP | VM_GROWSDOWN)))
+               actual_size -= PAGE_SIZE;
+       if (actual_size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur))
                return -ENOMEM;
 
        /* mlock limit tests */
index d5d81f5384d16f09076fdb4dc06cdf45f6d238ef..6f4335238e33311de251a647fe725d06d5897060 100644 (file)
@@ -1541,16 +1541,6 @@ pause:
                bdi_start_background_writeback(bdi);
 }
 
-void set_page_dirty_balance(struct page *page)
-{
-       if (set_page_dirty(page)) {
-               struct address_space *mapping = page_mapping(page);
-
-               if (mapping)
-                       balance_dirty_pages_ratelimited(mapping);
-       }
-}
-
 static DEFINE_PER_CPU(int, bdp_ratelimits);
 
 /*
@@ -2123,32 +2113,25 @@ EXPORT_SYMBOL(account_page_dirtied);
  * page dirty in that case, but not all the buffers.  This is a "bottom-up"
  * dirtying, whereas __set_page_dirty_buffers() is a "top-down" dirtying.
  *
- * Most callers have locked the page, which pins the address_space in memory.
- * But zap_pte_range() does not lock the page, however in that case the
- * mapping is pinned by the vma's ->vm_file reference.
- *
- * We take care to handle the case where the page was truncated from the
- * mapping by re-checking page_mapping() inside tree_lock.
+ * The caller must ensure this doesn't race with truncation.  Most will simply
+ * hold the page lock, but e.g. zap_pte_range() calls with the page mapped and
+ * the pte lock held, which also locks out truncation.
  */
 int __set_page_dirty_nobuffers(struct page *page)
 {
        if (!TestSetPageDirty(page)) {
                struct address_space *mapping = page_mapping(page);
-               struct address_space *mapping2;
                unsigned long flags;
 
                if (!mapping)
                        return 1;
 
                spin_lock_irqsave(&mapping->tree_lock, flags);
-               mapping2 = page_mapping(page);
-               if (mapping2) { /* Race with truncate? */
-                       BUG_ON(mapping2 != mapping);
-                       WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
-                       account_page_dirtied(page, mapping);
-                       radix_tree_tag_set(&mapping->page_tree,
-                               page_index(page), PAGECACHE_TAG_DIRTY);
-               }
+               BUG_ON(page_mapping(page) != mapping);
+               WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
+               account_page_dirtied(page, mapping);
+               radix_tree_tag_set(&mapping->page_tree, page_index(page),
+                                  PAGECACHE_TAG_DIRTY);
                spin_unlock_irqrestore(&mapping->tree_lock, flags);
                if (mapping->host) {
                        /* !PageAnon && !swapper_space */
@@ -2305,12 +2288,10 @@ int clear_page_dirty_for_io(struct page *page)
                /*
                 * We carefully synchronise fault handlers against
                 * installing a dirty pte and marking the page dirty
-                * at this point. We do this by having them hold the
-                * page lock at some point after installing their
-                * pte, but before marking the page dirty.
-                * Pages are always locked coming in here, so we get
-                * the desired exclusion. See mm/memory.c:do_wp_page()
-                * for more comments.
+                * at this point.  We do this by having them hold the
+                * page lock while dirtying the page, and pages are
+                * always locked coming in here, so we get the desired
+                * exclusion.
                 */
                if (TestClearPageDirty(page)) {
                        dec_zone_page_state(page, NR_FILE_DIRTY);
index 7633c503a116c221e7447614c6d10ebaa38a0b1c..8e20f9c2fa5ab7a89fb29c5dbc3987ccd8690047 100644 (file)
@@ -2332,12 +2332,21 @@ static inline struct page *
 __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
        struct zonelist *zonelist, enum zone_type high_zoneidx,
        nodemask_t *nodemask, struct zone *preferred_zone,
-       int classzone_idx, int migratetype)
+       int classzone_idx, int migratetype, unsigned long *did_some_progress)
 {
        struct page *page;
 
-       /* Acquire the per-zone oom lock for each zone */
+       *did_some_progress = 0;
+
+       if (oom_killer_disabled)
+               return NULL;
+
+       /*
+        * Acquire the per-zone oom lock for each zone.  If that
+        * fails, somebody else is making progress for us.
+        */
        if (!oom_zonelist_trylock(zonelist, gfp_mask)) {
+               *did_some_progress = 1;
                schedule_timeout_uninterruptible(1);
                return NULL;
        }
@@ -2363,12 +2372,18 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
                goto out;
 
        if (!(gfp_mask & __GFP_NOFAIL)) {
+               /* Coredumps can quickly deplete all memory reserves */
+               if (current->flags & PF_DUMPCORE)
+                       goto out;
                /* The OOM killer will not help higher order allocs */
                if (order > PAGE_ALLOC_COSTLY_ORDER)
                        goto out;
                /* The OOM killer does not needlessly kill tasks for lowmem */
                if (high_zoneidx < ZONE_NORMAL)
                        goto out;
+               /* The OOM killer does not compensate for light reclaim */
+               if (!(gfp_mask & __GFP_FS))
+                       goto out;
                /*
                 * GFP_THISNODE contains __GFP_NORETRY and we never hit this.
                 * Sanity check for bare calls of __GFP_THISNODE, not real OOM.
@@ -2381,7 +2396,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order,
        }
        /* Exhausted what can be done so it's blamo time */
        out_of_memory(zonelist, gfp_mask, order, nodemask, false);
-
+       *did_some_progress = 1;
 out:
        oom_zonelist_unlock(zonelist, gfp_mask);
        return page;
@@ -2658,7 +2673,7 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
            (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
                goto nopage;
 
-restart:
+retry:
        if (!(gfp_mask & __GFP_NO_KSWAPD))
                wake_all_kswapds(order, zonelist, high_zoneidx,
                                preferred_zone, nodemask);
@@ -2681,7 +2696,6 @@ restart:
                classzone_idx = zonelist_zone_idx(preferred_zoneref);
        }
 
-rebalance:
        /* This is the last chance, in general, before the goto nopage. */
        page = get_page_from_freelist(gfp_mask, nodemask, order, zonelist,
                        high_zoneidx, alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2788,54 +2802,28 @@ rebalance:
        if (page)
                goto got_pg;
 
-       /*
-        * If we failed to make any progress reclaiming, then we are
-        * running out of options and have to consider going OOM
-        */
-       if (!did_some_progress) {
-               if (oom_gfp_allowed(gfp_mask)) {
-                       if (oom_killer_disabled)
-                               goto nopage;
-                       /* Coredumps can quickly deplete all memory reserves */
-                       if ((current->flags & PF_DUMPCORE) &&
-                           !(gfp_mask & __GFP_NOFAIL))
-                               goto nopage;
-                       page = __alloc_pages_may_oom(gfp_mask, order,
-                                       zonelist, high_zoneidx,
-                                       nodemask, preferred_zone,
-                                       classzone_idx, migratetype);
-                       if (page)
-                               goto got_pg;
-
-                       if (!(gfp_mask & __GFP_NOFAIL)) {
-                               /*
-                                * The oom killer is not called for high-order
-                                * allocations that may fail, so if no progress
-                                * is being made, there are no other options and
-                                * retrying is unlikely to help.
-                                */
-                               if (order > PAGE_ALLOC_COSTLY_ORDER)
-                                       goto nopage;
-                               /*
-                                * The oom killer is not called for lowmem
-                                * allocations to prevent needlessly killing
-                                * innocent tasks.
-                                */
-                               if (high_zoneidx < ZONE_NORMAL)
-                                       goto nopage;
-                       }
-
-                       goto restart;
-               }
-       }
-
        /* Check if we should retry the allocation */
        pages_reclaimed += did_some_progress;
        if (should_alloc_retry(gfp_mask, order, did_some_progress,
                                                pages_reclaimed)) {
+               /*
+                * If we fail to make progress by freeing individual
+                * pages, but the allocation wants us to keep going,
+                * start OOM killing tasks.
+                */
+               if (!did_some_progress) {
+                       page = __alloc_pages_may_oom(gfp_mask, order, zonelist,
+                                               high_zoneidx, nodemask,
+                                               preferred_zone, classzone_idx,
+                                               migratetype,&did_some_progress);
+                       if (page)
+                               goto got_pg;
+                       if (!did_some_progress)
+                               goto nopage;
+               }
                /* Wait for some write requests to complete then retry */
                wait_iff_congested(preferred_zone, BLK_RW_ASYNC, HZ/50);
-               goto rebalance;
+               goto retry;
        } else {
                /*
                 * High-order allocations do not necessarily loop after
index c5bc241127b205734eaef62964d6d152941174cc..71cd5bd0c17d760c6f6ab1af5991165a1ac05844 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -72,6 +72,8 @@ static inline struct anon_vma *anon_vma_alloc(void)
        anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL);
        if (anon_vma) {
                atomic_set(&anon_vma->refcount, 1);
+               anon_vma->degree = 1;   /* Reference for first vma */
+               anon_vma->parent = anon_vma;
                /*
                 * Initialise the anon_vma root to point to itself. If called
                 * from fork, the root will be reset to the parents anon_vma.
@@ -188,6 +190,8 @@ int anon_vma_prepare(struct vm_area_struct *vma)
                if (likely(!vma->anon_vma)) {
                        vma->anon_vma = anon_vma;
                        anon_vma_chain_link(vma, avc, anon_vma);
+                       /* vma reference or self-parent link for new root */
+                       anon_vma->degree++;
                        allocated = NULL;
                        avc = NULL;
                }
@@ -236,6 +240,14 @@ static inline void unlock_anon_vma_root(struct anon_vma *root)
 /*
  * Attach the anon_vmas from src to dst.
  * Returns 0 on success, -ENOMEM on failure.
+ *
+ * If dst->anon_vma is NULL this function tries to find and reuse existing
+ * anon_vma which has no vmas and only one child anon_vma. This prevents
+ * degradation of anon_vma hierarchy to endless linear chain in case of
+ * constantly forking task. On the other hand, an anon_vma with more than one
+ * child isn't reused even if there was no alive vma, thus rmap walker has a
+ * good chance of avoiding scanning the whole hierarchy when it searches where
+ * page is mapped.
  */
 int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
 {
@@ -256,7 +268,21 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
                anon_vma = pavc->anon_vma;
                root = lock_anon_vma_root(root, anon_vma);
                anon_vma_chain_link(dst, avc, anon_vma);
+
+               /*
+                * Reuse existing anon_vma if its degree lower than two,
+                * that means it has no vma and only one anon_vma child.
+                *
+                * Do not chose parent anon_vma, otherwise first child
+                * will always reuse it. Root anon_vma is never reused:
+                * it has self-parent reference and at least one child.
+                */
+               if (!dst->anon_vma && anon_vma != src->anon_vma &&
+                               anon_vma->degree < 2)
+                       dst->anon_vma = anon_vma;
        }
+       if (dst->anon_vma)
+               dst->anon_vma->degree++;
        unlock_anon_vma_root(root);
        return 0;
 
@@ -280,6 +306,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        if (!pvma->anon_vma)
                return 0;
 
+       /* Drop inherited anon_vma, we'll reuse existing or allocate new. */
+       vma->anon_vma = NULL;
+
        /*
         * First, attach the new VMA to the parent VMA's anon_vmas,
         * so rmap can find non-COWed pages in child processes.
@@ -288,6 +317,10 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        if (error)
                return error;
 
+       /* An existing anon_vma has been reused, all done then. */
+       if (vma->anon_vma)
+               return 0;
+
        /* Then add our own anon_vma. */
        anon_vma = anon_vma_alloc();
        if (!anon_vma)
@@ -301,6 +334,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
         * lock any of the anon_vmas in this anon_vma tree.
         */
        anon_vma->root = pvma->anon_vma->root;
+       anon_vma->parent = pvma->anon_vma;
        /*
         * With refcounts, an anon_vma can stay around longer than the
         * process it belongs to. The root anon_vma needs to be pinned until
@@ -311,6 +345,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
        vma->anon_vma = anon_vma;
        anon_vma_lock_write(anon_vma);
        anon_vma_chain_link(vma, avc, anon_vma);
+       anon_vma->parent->degree++;
        anon_vma_unlock_write(anon_vma);
 
        return 0;
@@ -341,12 +376,16 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
                 * Leave empty anon_vmas on the list - we'll need
                 * to free them outside the lock.
                 */
-               if (RB_EMPTY_ROOT(&anon_vma->rb_root))
+               if (RB_EMPTY_ROOT(&anon_vma->rb_root)) {
+                       anon_vma->parent->degree--;
                        continue;
+               }
 
                list_del(&avc->same_vma);
                anon_vma_chain_free(avc);
        }
+       if (vma->anon_vma)
+               vma->anon_vma->degree--;
        unlock_anon_vma_root(root);
 
        /*
@@ -357,6 +396,7 @@ void unlink_anon_vmas(struct vm_area_struct *vma)
        list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) {
                struct anon_vma *anon_vma = avc->anon_vma;
 
+               BUG_ON(anon_vma->degree);
                put_anon_vma(anon_vma);
 
                list_del(&avc->same_vma);
index bd9a72bc4a1b81f5b4a53e630360e725f6e1347b..dcd90c891d8e53895d117f219001329e8cdeab46 100644 (file)
@@ -2656,7 +2656,7 @@ static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist,
         * should make reasonable progress.
         */
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
-                                       gfp_mask, nodemask) {
+                                       gfp_zone(gfp_mask), nodemask) {
                if (zone_idx(zone) > ZONE_NORMAL)
                        continue;
 
@@ -2921,18 +2921,20 @@ static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, long remaining,
                return false;
 
        /*
-        * There is a potential race between when kswapd checks its watermarks
-        * and a process gets throttled. There is also a potential race if
-        * processes get throttled, kswapd wakes, a large process exits therby
-        * balancing the zones that causes kswapd to miss a wakeup. If kswapd
-        * is going to sleep, no process should be sleeping on pfmemalloc_wait
-        * so wake them now if necessary. If necessary, processes will wake
-        * kswapd and get throttled again
+        * The throttled processes are normally woken up in balance_pgdat() as
+        * soon as pfmemalloc_watermark_ok() is true. But there is a potential
+        * race between when kswapd checks the watermarks and a process gets
+        * throttled. There is also a potential race if processes get
+        * throttled, kswapd wakes, a large process exits thereby balancing the
+        * zones, which causes kswapd to exit balance_pgdat() before reaching
+        * the wake up checks. If kswapd is going to sleep, no process should
+        * be sleeping on pfmemalloc_wait, so wake them now if necessary. If
+        * the wake up is premature, processes will wake kswapd and get
+        * throttled again. The difference from wake ups in balance_pgdat() is
+        * that here we are under prepare_to_wait().
         */
-       if (waitqueue_active(&pgdat->pfmemalloc_wait)) {
-               wake_up(&pgdat->pfmemalloc_wait);
-               return false;
-       }
+       if (waitqueue_active(&pgdat->pfmemalloc_wait))
+               wake_up_all(&pgdat->pfmemalloc_wait);
 
        return pgdat_balanced(pgdat, order, classzone_idx);
 }
index fc1835c6bb4099e50e75f964826b0aacdd7200f0..00f9e144cc97b1afe7cefc5b682524103799e4b7 100644 (file)
@@ -251,7 +251,7 @@ batadv_frag_merge_packets(struct hlist_head *chain, struct sk_buff *skb)
        kfree(entry);
 
        /* Make room for the rest of the fragments. */
-       if (pskb_expand_head(skb_out, 0, size - skb->len, GFP_ATOMIC) < 0) {
+       if (pskb_expand_head(skb_out, 0, size - skb_out->len, GFP_ATOMIC) < 0) {
                kfree_skb(skb_out);
                skb_out = NULL;
                goto free;
@@ -434,7 +434,7 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
         * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE
         */
        mtu = min_t(unsigned, mtu, BATADV_FRAG_MAX_FRAG_SIZE);
-       max_fragment_size = (mtu - header_size - ETH_HLEN);
+       max_fragment_size = mtu - header_size;
        max_packet_size = max_fragment_size * BATADV_FRAG_MAX_FRAGMENTS;
 
        /* Don't even try to fragment, if we need more than 16 fragments */
index 90cff585b37d5a3779cdb8f7b3b90a26eb2df88e..e0bcf9e842737427e8dc6d8f5e1be57f92252933 100644 (file)
@@ -810,7 +810,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
                goto out;
 
        gw_node = batadv_gw_node_get(bat_priv, orig_dst_node);
-       if (!gw_node->bandwidth_down == 0)
+       if (!gw_node)
                goto out;
 
        switch (atomic_read(&bat_priv->gw_mode)) {
index ab6bb2af1d45d51a77b93a062b8a5b59cc69b1c0..b24e4bb64fb5fd51c813df7e5801b98d27caf959 100644 (file)
@@ -685,11 +685,13 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
                if (orig_initialized)
                        atomic_dec(&bat_priv->mcast.num_disabled);
                orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST;
-       /* If mcast support is being switched off increase the disabled
-        * mcast node counter.
+       /* If mcast support is being switched off or if this is an initial
+        * OGM without mcast support then increase the disabled mcast
+        * node counter.
         */
        } else if (!orig_mcast_enabled &&
-                  orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) {
+                  (orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST ||
+                   !orig_initialized)) {
                atomic_inc(&bat_priv->mcast.num_disabled);
                orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST;
        }
@@ -738,7 +740,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
 {
        struct batadv_priv *bat_priv = orig->bat_priv;
 
-       if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST))
+       if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) &&
+           orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST)
                atomic_dec(&bat_priv->mcast.num_disabled);
 
        batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
index 8d04d174669ed29c467436d33b099ad5d0ca13c4..fab47f1f3ef9752a4fc6e2caba504631efb510d6 100644 (file)
@@ -133,7 +133,7 @@ int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
        if (!bat_priv->nc.decoding_hash)
                goto err;
 
-       batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
+       batadv_hash_set_lock_class(bat_priv->nc.decoding_hash,
                                   &batadv_nc_decoding_hash_lock_class_key);
 
        INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
index 6a484514cd3e98b9e0b27a924b4dcb92f2682055..bea8198d0198104a2fcbf4253f631fb86708e0d6 100644 (file)
@@ -570,9 +570,6 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
 
        batadv_frag_purge_orig(orig_node, NULL);
 
-       batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, -1,
-                                 "originator timed out");
-
        if (orig_node->bat_priv->bat_algo_ops->bat_orig_free)
                orig_node->bat_priv->bat_algo_ops->bat_orig_free(orig_node);
 
@@ -678,6 +675,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
        atomic_set(&orig_node->last_ttvn, 0);
        orig_node->tt_buff = NULL;
        orig_node->tt_buff_len = 0;
+       orig_node->last_seen = jiffies;
        reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
        orig_node->bcast_seqno_reset = reset_time;
 #ifdef CONFIG_BATMAN_ADV_MCAST
@@ -977,6 +975,9 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv)
                        if (batadv_purge_orig_node(bat_priv, orig_node)) {
                                batadv_gw_node_delete(bat_priv, orig_node);
                                hlist_del_rcu(&orig_node->hash_entry);
+                               batadv_tt_global_del_orig(orig_node->bat_priv,
+                                                         orig_node, -1,
+                                                         "originator timed out");
                                batadv_orig_node_free_ref(orig_node);
                                continue;
                        }
index 35f76f2f7824b8c2756e60bb5249fd4f5502cc8d..6648f321864d8f7b33d258f9ee2c93e339738a93 100644 (file)
@@ -443,11 +443,13 @@ batadv_find_router(struct batadv_priv *bat_priv,
 
        router = batadv_orig_router_get(orig_node, recv_if);
 
+       if (!router)
+               return router;
+
        /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop)
         * and if activated.
         */
-       if (recv_if == BATADV_IF_DEFAULT || !atomic_read(&bat_priv->bonding) ||
-           !router)
+       if (!(recv_if == BATADV_IF_DEFAULT && atomic_read(&bat_priv->bonding)))
                return router;
 
        /* bonding: loop through the list of possible routers found
index 76617be1e797ba6d41c72fbc8f582d5a5614ff3e..c989253737f05985e214fbf2f272a69412f9a0fb 100644 (file)
@@ -390,7 +390,6 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
 
 drop:
        dev->stats.rx_dropped++;
-       kfree_skb(skb);
        return NET_RX_DROP;
 }
 
index 85bcc21e84d2006c4839b2b7f409f2595cb41858..ce82722d049b7c013fd06f66f726fbbf75a01f56 100644 (file)
@@ -533,6 +533,9 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
 
        BT_DBG("");
 
+       if (!l2cap_is_socket(sock))
+               return -EBADFD;
+
        baswap((void *) dst, &l2cap_pi(sock->sk)->chan->dst);
        baswap((void *) src, &l2cap_pi(sock->sk)->chan->src);
 
index 67fe5e84e68f0bffb166bbcfb6cdb736f15ab05e..278a194e6af488f67197c3725ca937f554989498 100644 (file)
@@ -334,6 +334,9 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
 
        BT_DBG("");
 
+       if (!l2cap_is_socket(sock))
+               return -EBADFD;
+
        session = kzalloc(sizeof(struct cmtp_session), GFP_KERNEL);
        if (!session)
                return -ENOMEM;
index 39a5c8a017263694f1dbdca7888abd700c12952b..3f2e8b830cbd1cf37b65431bfd76981bc2447dff 100644 (file)
@@ -242,7 +242,8 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (rp->status)
                return;
 
-       if (test_bit(HCI_SETUP, &hdev->dev_flags))
+       if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
+           test_bit(HCI_CONFIG, &hdev->dev_flags))
                memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH);
 }
 
@@ -509,7 +510,8 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
        if (rp->status)
                return;
 
-       if (test_bit(HCI_SETUP, &hdev->dev_flags)) {
+       if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
+           test_bit(HCI_CONFIG, &hdev->dev_flags)) {
                hdev->hci_ver = rp->hci_ver;
                hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
                hdev->lmp_ver = rp->lmp_ver;
@@ -528,7 +530,8 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
        if (rp->status)
                return;
 
-       if (test_bit(HCI_SETUP, &hdev->dev_flags))
+       if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
+           test_bit(HCI_CONFIG, &hdev->dev_flags))
                memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
 }
 
@@ -2194,7 +2197,12 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
                return;
        }
 
-       if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags) &&
+       /* Require HCI_CONNECTABLE or a whitelist entry to accept the
+        * connection. These features are only touched through mgmt so
+        * only do the checks if HCI_MGMT is set.
+        */
+       if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
+           !test_bit(HCI_CONNECTABLE, &hdev->dev_flags) &&
            !hci_bdaddr_list_lookup(&hdev->whitelist, &ev->bdaddr,
                                    BDADDR_BREDR)) {
                    hci_reject_conn(hdev, &ev->bdaddr);
index cc25d0b74b3609ef800453484eef7e0f55767162..07348e142f16a783b7764d72314830f4b7844330 100644 (file)
@@ -1314,13 +1314,14 @@ int hidp_connection_add(struct hidp_connadd_req *req,
 {
        struct hidp_session *session;
        struct l2cap_conn *conn;
-       struct l2cap_chan *chan = l2cap_pi(ctrl_sock->sk)->chan;
+       struct l2cap_chan *chan;
        int ret;
 
        ret = hidp_verify_sockets(ctrl_sock, intr_sock);
        if (ret)
                return ret;
 
+       chan = l2cap_pi(ctrl_sock->sk)->chan;
        conn = NULL;
        l2cap_chan_lock(chan);
        if (chan->conn)
index 1f1de715197c19ab12f5333e9a518a317754f041..e2aa7be3a847f448a404e0a43f6d1a09f1a0517a 100644 (file)
@@ -154,7 +154,8 @@ int br_handle_frame_finish(struct sk_buff *skb)
        dst = NULL;
 
        if (is_broadcast_ether_addr(dest)) {
-               if (p->flags & BR_PROXYARP &&
+               if (IS_ENABLED(CONFIG_INET) &&
+                   p->flags & BR_PROXYARP &&
                    skb->protocol == htons(ETH_P_ARP))
                        br_do_proxy_arp(skb, br, vid);
 
index 15845814a0f25eaefb95590cb848aa6032a8e038..ba6eb17226da424d59bb462a2089186bbd3233af 100644 (file)
@@ -676,7 +676,7 @@ static int calcu_signature(struct ceph_x_authorizer *au,
        int ret;
        char tmp_enc[40];
        __le32 tmp[5] = {
-               16u, msg->hdr.crc, msg->footer.front_crc,
+               cpu_to_le32(16), msg->hdr.crc, msg->footer.front_crc,
                msg->footer.middle_crc, msg->footer.data_crc,
        };
        ret = ceph_x_encrypt(&au->session_key, &tmp, sizeof(tmp),
index a83062ceeec90660ee5b384fc2a758a70bbf1049..f2148e22b14897727faeba297e045f2b933a52b1 100644 (file)
@@ -717,7 +717,7 @@ static int get_poolop_reply_buf(const char *src, size_t src_len,
        if (src_len != sizeof(u32) + dst_len)
                return -EINVAL;
 
-       buf_len = le32_to_cpu(*(u32 *)src);
+       buf_len = le32_to_cpu(*(__le32 *)src);
        if (buf_len != dst_len)
                return -EINVAL;
 
index f411c28d0a66805661db0a409b140d02e8ca4041..171420e75b03e5b9a020e6d417b72efbed5d5aba 100644 (file)
@@ -1694,6 +1694,7 @@ int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
 
        skb_scrub_packet(skb, true);
        skb->protocol = eth_type_trans(skb, dev);
+       skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
        return 0;
 }
@@ -2522,7 +2523,7 @@ static int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 /* If MPLS offload request, verify we are testing hardware MPLS features
  * instead of standard features for the netdev.
  */
-#ifdef CONFIG_NET_MPLS_GSO
+#if IS_ENABLED(CONFIG_NET_MPLS_GSO)
 static netdev_features_t net_mpls_features(struct sk_buff *skb,
                                           netdev_features_t features,
                                           __be16 type)
@@ -2562,7 +2563,7 @@ static netdev_features_t harmonize_features(struct sk_buff *skb,
 
 netdev_features_t netif_skb_features(struct sk_buff *skb)
 {
-       const struct net_device *dev = skb->dev;
+       struct net_device *dev = skb->dev;
        netdev_features_t features = dev->features;
        u16 gso_segs = skb_shinfo(skb)->gso_segs;
        __be16 protocol = skb->protocol;
@@ -2570,11 +2571,21 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
        if (gso_segs > dev->gso_max_segs || gso_segs < dev->gso_min_segs)
                features &= ~NETIF_F_GSO_MASK;
 
-       if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) {
-               struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
-               protocol = veh->h_vlan_encapsulated_proto;
-       } else if (!vlan_tx_tag_present(skb)) {
-               return harmonize_features(skb, features);
+       /* If encapsulation offload request, verify we are testing
+        * hardware encapsulation features instead of standard
+        * features for the netdev
+        */
+       if (skb->encapsulation)
+               features &= dev->hw_enc_features;
+
+       if (!vlan_tx_tag_present(skb)) {
+               if (unlikely(protocol == htons(ETH_P_8021Q) ||
+                            protocol == htons(ETH_P_8021AD))) {
+                       struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
+                       protocol = veh->h_vlan_encapsulated_proto;
+               } else {
+                       goto finalize;
+               }
        }
 
        features = netdev_intersect_features(features,
@@ -2591,6 +2602,11 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
                                                     NETIF_F_HW_VLAN_CTAG_TX |
                                                     NETIF_F_HW_VLAN_STAG_TX);
 
+finalize:
+       if (dev->netdev_ops->ndo_features_check)
+               features &= dev->netdev_ops->ndo_features_check(skb, dev,
+                                                               features);
+
        return harmonize_features(skb, features);
 }
 EXPORT_SYMBOL(netif_skb_features);
@@ -2661,19 +2677,12 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
        if (unlikely(!skb))
                goto out_null;
 
-       /* If encapsulation offload request, verify we are testing
-        * hardware encapsulation features instead of standard
-        * features for the netdev
-        */
-       if (skb->encapsulation)
-               features &= dev->hw_enc_features;
-
        if (netif_needs_gso(dev, skb, features)) {
                struct sk_buff *segs;
 
                segs = skb_gso_segment(skb, features);
                if (IS_ERR(segs)) {
-                       segs = NULL;
+                       goto out_kfree_skb;
                } else if (segs) {
                        consume_skb(skb);
                        skb = segs;
@@ -4557,6 +4566,68 @@ void netif_napi_del(struct napi_struct *napi)
 }
 EXPORT_SYMBOL(netif_napi_del);
 
+static int napi_poll(struct napi_struct *n, struct list_head *repoll)
+{
+       void *have;
+       int work, weight;
+
+       list_del_init(&n->poll_list);
+
+       have = netpoll_poll_lock(n);
+
+       weight = n->weight;
+
+       /* This NAPI_STATE_SCHED test is for avoiding a race
+        * with netpoll's poll_napi().  Only the entity which
+        * obtains the lock and sees NAPI_STATE_SCHED set will
+        * actually make the ->poll() call.  Therefore we avoid
+        * accidentally calling ->poll() when NAPI is not scheduled.
+        */
+       work = 0;
+       if (test_bit(NAPI_STATE_SCHED, &n->state)) {
+               work = n->poll(n, weight);
+               trace_napi_poll(n);
+       }
+
+       WARN_ON_ONCE(work > weight);
+
+       if (likely(work < weight))
+               goto out_unlock;
+
+       /* Drivers must not modify the NAPI state if they
+        * consume the entire weight.  In such cases this code
+        * still "owns" the NAPI instance and therefore can
+        * move the instance around on the list at-will.
+        */
+       if (unlikely(napi_disable_pending(n))) {
+               napi_complete(n);
+               goto out_unlock;
+       }
+
+       if (n->gro_list) {
+               /* flush too old packets
+                * If HZ < 1000, flush all packets.
+                */
+               napi_gro_flush(n, HZ >= 1000);
+       }
+
+       /* Some drivers may have called napi_schedule
+        * prior to exhausting their budget.
+        */
+       if (unlikely(!list_empty(&n->poll_list))) {
+               pr_warn_once("%s: Budget exhausted after napi rescheduled\n",
+                            n->dev ? n->dev->name : "backlog");
+               goto out_unlock;
+       }
+
+       list_add_tail(&n->poll_list, repoll);
+
+out_unlock:
+       netpoll_poll_unlock(have);
+
+       return work;
+}
+
 static void net_rx_action(struct softirq_action *h)
 {
        struct softnet_data *sd = this_cpu_ptr(&softnet_data);
@@ -4564,74 +4635,34 @@ static void net_rx_action(struct softirq_action *h)
        int budget = netdev_budget;
        LIST_HEAD(list);
        LIST_HEAD(repoll);
-       void *have;
 
        local_irq_disable();
        list_splice_init(&sd->poll_list, &list);
        local_irq_enable();
 
-       while (!list_empty(&list)) {
+       for (;;) {
                struct napi_struct *n;
-               int work, weight;
-
-               /* If softirq window is exhausted then punt.
-                * Allow this to run for 2 jiffies since which will allow
-                * an average latency of 1.5/HZ.
-                */
-               if (unlikely(budget <= 0 || time_after_eq(jiffies, time_limit)))
-                       goto softnet_break;
-
 
-               n = list_first_entry(&list, struct napi_struct, poll_list);
-               list_del_init(&n->poll_list);
-
-               have = netpoll_poll_lock(n);
-
-               weight = n->weight;
-
-               /* This NAPI_STATE_SCHED test is for avoiding a race
-                * with netpoll's poll_napi().  Only the entity which
-                * obtains the lock and sees NAPI_STATE_SCHED set will
-                * actually make the ->poll() call.  Therefore we avoid
-                * accidentally calling ->poll() when NAPI is not scheduled.
-                */
-               work = 0;
-               if (test_bit(NAPI_STATE_SCHED, &n->state)) {
-                       work = n->poll(n, weight);
-                       trace_napi_poll(n);
+               if (list_empty(&list)) {
+                       if (!sd_has_rps_ipi_waiting(sd) && list_empty(&repoll))
+                               return;
+                       break;
                }
 
-               WARN_ON_ONCE(work > weight);
-
-               budget -= work;
+               n = list_first_entry(&list, struct napi_struct, poll_list);
+               budget -= napi_poll(n, &repoll);
 
-               /* Drivers must not modify the NAPI state if they
-                * consume the entire weight.  In such cases this code
-                * still "owns" the NAPI instance and therefore can
-                * move the instance around on the list at-will.
+               /* If softirq window is exhausted then punt.
+                * Allow this to run for 2 jiffies since which will allow
+                * an average latency of 1.5/HZ.
                 */
-               if (unlikely(work == weight)) {
-                       if (unlikely(napi_disable_pending(n))) {
-                               napi_complete(n);
-                       } else {
-                               if (n->gro_list) {
-                                       /* flush too old packets
-                                        * If HZ < 1000, flush all packets.
-                                        */
-                                       napi_gro_flush(n, HZ >= 1000);
-                               }
-                               list_add_tail(&n->poll_list, &repoll);
-                       }
+               if (unlikely(budget <= 0 ||
+                            time_after_eq(jiffies, time_limit))) {
+                       sd->time_squeeze++;
+                       break;
                }
-
-               netpoll_poll_unlock(have);
        }
 
-       if (!sd_has_rps_ipi_waiting(sd) &&
-           list_empty(&list) &&
-           list_empty(&repoll))
-               return;
-out:
        local_irq_disable();
 
        list_splice_tail_init(&sd->poll_list, &list);
@@ -4641,12 +4672,6 @@ out:
                __raise_softirq_irqoff(NET_RX_SOFTIRQ);
 
        net_rps_action_and_irq_enable(sd);
-
-       return;
-
-softnet_break:
-       sd->time_squeeze++;
-       goto out;
 }
 
 struct netdev_adjacent {
@@ -7047,10 +7072,20 @@ static int dev_cpu_callback(struct notifier_block *nfb,
                oldsd->output_queue = NULL;
                oldsd->output_queue_tailp = &oldsd->output_queue;
        }
-       /* Append NAPI poll list from offline CPU. */
-       if (!list_empty(&oldsd->poll_list)) {
-               list_splice_init(&oldsd->poll_list, &sd->poll_list);
-               raise_softirq_irqoff(NET_RX_SOFTIRQ);
+       /* Append NAPI poll list from offline CPU, with one exception :
+        * process_backlog() must be called by cpu owning percpu backlog.
+        * We properly handle process_queue & input_pkt_queue later.
+        */
+       while (!list_empty(&oldsd->poll_list)) {
+               struct napi_struct *napi = list_first_entry(&oldsd->poll_list,
+                                                           struct napi_struct,
+                                                           poll_list);
+
+               list_del_init(&napi->poll_list);
+               if (napi->poll == process_backlog)
+                       napi->state = 0;
+               else
+                       ____napi_schedule(sd, napi);
        }
 
        raise_softirq_irqoff(NET_TX_SOFTIRQ);
@@ -7061,7 +7096,7 @@ static int dev_cpu_callback(struct notifier_block *nfb,
                netif_rx_internal(skb);
                input_queue_head_incr(oldsd);
        }
-       while ((skb = __skb_dequeue(&oldsd->input_pkt_queue))) {
+       while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) {
                netif_rx_internal(skb);
                input_queue_head_incr(oldsd);
        }
index 8e38f17288d3c5a475471b0e56e339d9b6d5bf9e..8d614c93f86a233a5cb3864c600d9c68fe5f9ea1 100644 (file)
@@ -2043,6 +2043,12 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh)
                        case NDTPA_BASE_REACHABLE_TIME:
                                NEIGH_VAR_SET(p, BASE_REACHABLE_TIME,
                                              nla_get_msecs(tbp[i]));
+                               /* update reachable_time as well, otherwise, the change will
+                                * only be effective after the next time neigh_periodic_work
+                                * decides to recompute it (can be multiple minutes)
+                                */
+                               p->reachable_time =
+                                       neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
                                break;
                        case NDTPA_GC_STALETIME:
                                NEIGH_VAR_SET(p, GC_STALETIME,
@@ -2921,6 +2927,31 @@ static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write,
        return ret;
 }
 
+static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write,
+                                         void __user *buffer,
+                                         size_t *lenp, loff_t *ppos)
+{
+       struct neigh_parms *p = ctl->extra2;
+       int ret;
+
+       if (strcmp(ctl->procname, "base_reachable_time") == 0)
+               ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
+       else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0)
+               ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
+       else
+               ret = -1;
+
+       if (write && ret == 0) {
+               /* update reachable_time as well, otherwise, the change will
+                * only be effective after the next time neigh_periodic_work
+                * decides to recompute it
+                */
+               p->reachable_time =
+                       neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME));
+       }
+       return ret;
+}
+
 #define NEIGH_PARMS_DATA_OFFSET(index) \
        (&((struct neigh_parms *) 0)->data[index])
 
@@ -3047,6 +3078,19 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
                t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler;
                /* ReachableTime (in milliseconds) */
                t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler;
+       } else {
+               /* Those handlers will update p->reachable_time after
+                * base_reachable_time(_ms) is set to ensure the new timer starts being
+                * applied after the next neighbour update instead of waiting for
+                * neigh_periodic_work to update its value (can be multiple minutes)
+                * So any handler that replaces them should do this as well
+                */
+               /* ReachableTime */
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler =
+                       neigh_proc_base_reachable_time;
+               /* ReachableTime (in milliseconds) */
+               t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler =
+                       neigh_proc_base_reachable_time;
        }
 
        /* Don't export sysctls to unprivileged users */
index ae13ef6b3ea7f40b6843fa2d5b33fc06de0cb0b5..395c15b82087253cd9905d315cd689a29b89ae4d 100644 (file)
@@ -4148,6 +4148,7 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        skb->ignore_df = 0;
        skb_dst_drop(skb);
        skb->mark = 0;
+       skb_init_secmark(skb);
        secpath_reset(skb);
        nf_reset(skb);
        nf_reset_trace(skb);
index 515569ffde8a16af9eea82cc85ded4f8d5ce59cc..589aafd01fc5256a0fac138bac3240ab191b507e 100644 (file)
@@ -46,6 +46,7 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
        snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "dsa-%d:%.2x",
                        ds->index, ds->pd->sw_addr);
        ds->slave_mii_bus->parent = ds->master_dev;
+       ds->slave_mii_bus->phy_mask = ~ds->phys_mii_mask;
 }
 
 
index 95e47c97585e2e34635976d6a352a1484d5c091c..394a200f93c1f5b5338ccab70286545acad1ebda 100644 (file)
@@ -122,14 +122,18 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt,
        int err;
 
        skb = udp_tunnel_handle_offloads(skb, !gs->sock->sk->sk_no_check_tx);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
 
        min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
                        + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr)
                        + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
 
        err = skb_cow_head(skb, min_headroom);
-       if (unlikely(err))
+       if (unlikely(err)) {
+               kfree_skb(skb);
                return err;
+       }
 
        skb = vlan_hwaccel_push_inside(skb);
        if (unlikely(!skb))
index 3a83ce5efa80e3fc2c062ec08465840018159b14..787b3c294ce672244ce08c5426c03bbd1f71c0f3 100644 (file)
@@ -129,7 +129,8 @@ int ip_forward(struct sk_buff *skb)
         *      We now generate an ICMP HOST REDIRECT giving the route
         *      we calculated.
         */
-       if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb))
+       if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr &&
+           !skb_sec_path(skb))
                ip_rt_send_redirect(skb);
 
        skb->priority = rt_tos2priority(iph->tos);
index 8a89c738b7a3b43407293f521bd6d7e009ee7c80..6b85adb05003cb775b538aacb81a37ec398d8b3c 100644 (file)
@@ -461,17 +461,13 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
-       sin->sin_family = AF_UNSPEC;
+       memset(sin, 0, sizeof(*sin));
 
        if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP ||
            ipv4_pktinfo_prepare_errqueue(sk, skb, serr->ee.ee_origin)) {
-               struct inet_sock *inet = inet_sk(sk);
-
                sin->sin_family = AF_INET;
                sin->sin_addr.s_addr = ip_hdr(skb)->saddr;
-               sin->sin_port = 0;
-               memset(&sin->sin_zero, 0, sizeof(sin->sin_zero));
-               if (inet->cmsg_flags)
+               if (inet_sk(sk)->cmsg_flags)
                        ip_cmsg_recv(msg, skb);
        }
 
index ff2d23d8c87a16964e29f478640dccd5ca527a02..6ecfce63201a2753d4943813d3eccbb951f34d0b 100644 (file)
@@ -27,10 +27,10 @@ static void nft_redir_ipv4_eval(const struct nft_expr *expr,
 
        memset(&mr, 0, sizeof(mr));
        if (priv->sreg_proto_min) {
-               mr.range[0].min.all = (__force __be16)
-                                       data[priv->sreg_proto_min].data[0];
-               mr.range[0].max.all = (__force __be16)
-                                       data[priv->sreg_proto_max].data[0];
+               mr.range[0].min.all =
+                       *(__be16 *)&data[priv->sreg_proto_min].data[0];
+               mr.range[0].max.all =
+                       *(__be16 *)&data[priv->sreg_proto_max].data[0];
                mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
        }
 
index c0d82f78d364fe5561f819f953e3eb48d2f134da..2a3720fb5a5ff5401c5efbef49427fb18dbbfa5e 100644 (file)
@@ -966,8 +966,11 @@ bool ping_rcv(struct sk_buff *skb)
 
        sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
        if (sk != NULL) {
+               struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
                pr_debug("rcv on socket %p\n", sk);
-               ping_queue_rcv_skb(sk, skb_get(skb));
+               if (skb2)
+                       ping_queue_rcv_skb(sk, skb2);
                sock_put(sk);
                return true;
        }
index 6a2155b02602b100c7ce3bbfda28a38090add7a4..d58dd0ec3e5302c2862c8fe53bfd43ca05a3e669 100644 (file)
@@ -1554,11 +1554,10 @@ static int __mkroute_input(struct sk_buff *skb,
 
        do_cache = res->fi && !itag;
        if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) &&
+           skb->protocol == htons(ETH_P_IP) &&
            (IN_DEV_SHARED_MEDIA(out_dev) ||
-            inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) {
-               flags |= RTCF_DOREDIRECT;
-               do_cache = false;
-       }
+            inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res))))
+               IPCB(skb)->flags |= IPSKB_DOREDIRECT;
 
        if (skb->protocol != htons(ETH_P_IP)) {
                /* Not IP (i.e. ARP). Do not create route, if it is
@@ -2303,6 +2302,8 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src,
        r->rtm_flags    = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED;
        if (rt->rt_flags & RTCF_NOTIFY)
                r->rtm_flags |= RTM_F_NOTIFY;
+       if (IPCB(skb)->flags & IPSKB_DOREDIRECT)
+               r->rtm_flags |= RTCF_DOREDIRECT;
 
        if (nla_put_be32(skb, RTA_DST, dst))
                goto nla_put_failure;
index 7f18262e2326ac4d7963347d7458273a325caa64..65caf8b95e1722b62fcdbcfae9526f7d529a6557 100644 (file)
@@ -2019,7 +2019,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now)))
                        break;
 
-               if (tso_segs == 1) {
+               if (tso_segs == 1 || !max_segs) {
                        if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
                                                     (tcp_skb_is_last(sk, skb) ?
                                                      nonagle : TCP_NAGLE_PUSH))))
@@ -2032,7 +2032,7 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                }
 
                limit = mss_now;
-               if (tso_segs > 1 && !tcp_urg_mode(tp))
+               if (tso_segs > 1 && max_segs && !tcp_urg_mode(tp))
                        limit = tcp_mss_split_point(sk, skb, mss_now,
                                                    min_t(unsigned int,
                                                          cwnd_quota,
index 7927db0a927951a20b4502d38fca0bba9e94862c..4a000f1dd75753833b792f6979bf697337f4dd7a 100644 (file)
@@ -99,11 +99,13 @@ static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlin
        s_slot = cb->args[0];
        num = s_num = cb->args[1];
 
-       for (slot = s_slot; slot <= table->mask; num = s_num = 0, slot++) {
+       for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) {
                struct sock *sk;
                struct hlist_nulls_node *node;
                struct udp_hslot *hslot = &table->hash[slot];
 
+               num = 0;
+
                if (hlist_nulls_empty(&hslot->head))
                        continue;
 
index 100c589a2a6cf951bdb8a7a2e56b087fb4fe56bf..49f5e73db1224549c7f3fc156209a85ed6ce4056 100644 (file)
@@ -393,11 +393,10 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
 
        memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
        sin = &errhdr.offender;
-       sin->sin6_family = AF_UNSPEC;
+       memset(sin, 0, sizeof(*sin));
+
        if (serr->ee.ee_origin != SO_EE_ORIGIN_LOCAL) {
                sin->sin6_family = AF_INET6;
-               sin->sin6_flowinfo = 0;
-               sin->sin6_port = 0;
                if (np->rxopt.all) {
                        if (serr->ee.ee_origin != SO_EE_ORIGIN_ICMP &&
                            serr->ee.ee_origin != SO_EE_ORIGIN_ICMP6)
@@ -412,12 +411,9 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
                                ipv6_iface_scope_id(&sin->sin6_addr,
                                                    IP6CB(skb)->iif);
                } else {
-                       struct inet_sock *inet = inet_sk(sk);
-
                        ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr,
                                               &sin->sin6_addr);
-                       sin->sin6_scope_id = 0;
-                       if (inet->cmsg_flags)
+                       if (inet_sk(sk)->cmsg_flags)
                                ip_cmsg_recv(msg, skb);
                }
        }
index b2d1838897c933f6f1ceb2a6f64a2f67495ce3c9..f1c6d5e9832253f15683fca6417255cee78618af 100644 (file)
@@ -659,6 +659,29 @@ static int fib6_commit_metrics(struct dst_entry *dst,
        return 0;
 }
 
+static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn,
+                         struct net *net)
+{
+       if (atomic_read(&rt->rt6i_ref) != 1) {
+               /* This route is used as dummy address holder in some split
+                * nodes. It is not leaked, but it still holds other resources,
+                * which must be released in time. So, scan ascendant nodes
+                * and replace dummy references to this route with references
+                * to still alive ones.
+                */
+               while (fn) {
+                       if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) {
+                               fn->leaf = fib6_find_prefix(net, fn);
+                               atomic_inc(&fn->leaf->rt6i_ref);
+                               rt6_release(rt);
+                       }
+                       fn = fn->parent;
+               }
+               /* No more references are possible at this point. */
+               BUG_ON(atomic_read(&rt->rt6i_ref) != 1);
+       }
+}
+
 /*
  *     Insert routing information in a node.
  */
@@ -807,11 +830,12 @@ add:
                rt->dst.rt6_next = iter->dst.rt6_next;
                atomic_inc(&rt->rt6i_ref);
                inet6_rt_notify(RTM_NEWROUTE, rt, info);
-               rt6_release(iter);
                if (!(fn->fn_flags & RTN_RTINFO)) {
                        info->nl_net->ipv6.rt6_stats->fib_route_nodes++;
                        fn->fn_flags |= RTN_RTINFO;
                }
+               fib6_purge_rt(iter, fn, info->nl_net);
+               rt6_release(iter);
        }
 
        return 0;
@@ -1322,24 +1346,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
                fn = fib6_repair_tree(net, fn);
        }
 
-       if (atomic_read(&rt->rt6i_ref) != 1) {
-               /* This route is used as dummy address holder in some split
-                * nodes. It is not leaked, but it still holds other resources,
-                * which must be released in time. So, scan ascendant nodes
-                * and replace dummy references to this route with references
-                * to still alive ones.
-                */
-               while (fn) {
-                       if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) {
-                               fn->leaf = fib6_find_prefix(net, fn);
-                               atomic_inc(&fn->leaf->rt6i_ref);
-                               rt6_release(rt);
-                       }
-                       fn = fn->parent;
-               }
-               /* No more references are possible at this point. */
-               BUG_ON(atomic_read(&rt->rt6i_ref) != 1);
-       }
+       fib6_purge_rt(rt, fn, net);
 
        inet6_rt_notify(RTM_DELROUTE, rt, info);
        rt6_release(rt);
index 2433a6bfb191c4259bedfe2d697baa618c818b51..11820b6b36130d4ec83af3f173a1ca70df8cbf93 100644 (file)
@@ -27,10 +27,10 @@ static void nft_redir_ipv6_eval(const struct nft_expr *expr,
 
        memset(&range, 0, sizeof(range));
        if (priv->sreg_proto_min) {
-               range.min_proto.all = (__force __be16)
-                                       data[priv->sreg_proto_min].data[0];
-               range.max_proto.all = (__force __be16)
-                                       data[priv->sreg_proto_max].data[0];
+               range.min_proto.all =
+                       *(__be16 *)&data[priv->sreg_proto_min].data[0];
+               range.max_proto.all =
+                       *(__be16 *)&data[priv->sreg_proto_max].data[0];
                range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
        }
 
index c91083156edbe2b631b1fb11e3ead35f1925b8a7..495965358d22d88849d251aa890aaee6caaf4079 100644 (file)
@@ -1160,12 +1160,9 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
                struct net *net = dev_net(dst->dev);
 
                rt6->rt6i_flags |= RTF_MODIFIED;
-               if (mtu < IPV6_MIN_MTU) {
-                       u32 features = dst_metric(dst, RTAX_FEATURES);
+               if (mtu < IPV6_MIN_MTU)
                        mtu = IPV6_MIN_MTU;
-                       features |= RTAX_FEATURE_ALLFRAG;
-                       dst_metric_set(dst, RTAX_FEATURES, features);
-               }
+
                dst_metric_set(dst, RTAX_MTU, mtu);
                rt6_update_expires(rt6, net->ipv6.sysctl.ip6_rt_mtu_expires);
        }
@@ -1245,12 +1242,16 @@ restart:
                rt = net->ipv6.ip6_null_entry;
        else if (rt->dst.error) {
                rt = net->ipv6.ip6_null_entry;
-       } else if (rt == net->ipv6.ip6_null_entry) {
+               goto out;
+       }
+
+       if (rt == net->ipv6.ip6_null_entry) {
                fn = fib6_backtrack(fn, &fl6->saddr);
                if (fn)
                        goto restart;
        }
 
+out:
        dst_hold(&rt->dst);
 
        read_unlock_bh(&table->tb6_lock);
index 5ff87805258eb1f0dfa1ed14967b2e1c8f5c4c6a..9c0b54e87b472390c080857f886a2af4a7a300f8 100644 (file)
@@ -1387,6 +1387,28 @@ ipv6_pktoptions:
        return 0;
 }
 
+static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr,
+                          const struct tcphdr *th)
+{
+       /* This is tricky: we move IP6CB at its correct location into
+        * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because
+        * _decode_session6() uses IP6CB().
+        * barrier() makes sure compiler won't play aliasing games.
+        */
+       memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb),
+               sizeof(struct inet6_skb_parm));
+       barrier();
+
+       TCP_SKB_CB(skb)->seq = ntohl(th->seq);
+       TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
+                                   skb->len - th->doff*4);
+       TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
+       TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
+       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
+       TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
+       TCP_SKB_CB(skb)->sacked = 0;
+}
+
 static int tcp_v6_rcv(struct sk_buff *skb)
 {
        const struct tcphdr *th;
@@ -1418,24 +1440,9 @@ static int tcp_v6_rcv(struct sk_buff *skb)
 
        th = tcp_hdr(skb);
        hdr = ipv6_hdr(skb);
-       /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB()
-        * barrier() makes sure compiler wont play fool^Waliasing games.
-        */
-       memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb),
-               sizeof(struct inet6_skb_parm));
-       barrier();
-
-       TCP_SKB_CB(skb)->seq = ntohl(th->seq);
-       TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
-                                   skb->len - th->doff*4);
-       TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-       TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th);
-       TCP_SKB_CB(skb)->tcp_tw_isn = 0;
-       TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr);
-       TCP_SKB_CB(skb)->sacked = 0;
 
        sk = __inet6_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest,
-                               tcp_v6_iif(skb));
+                               inet6_iif(skb));
        if (!sk)
                goto no_tcp_socket;
 
@@ -1451,6 +1458,8 @@ process:
        if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb))
                goto discard_and_relse;
 
+       tcp_v6_fill_cb(skb, hdr, th);
+
 #ifdef CONFIG_TCP_MD5SIG
        if (tcp_v6_inbound_md5_hash(sk, skb))
                goto discard_and_relse;
@@ -1482,6 +1491,8 @@ no_tcp_socket:
        if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
                goto discard_it;
 
+       tcp_v6_fill_cb(skb, hdr, th);
+
        if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
 csum_error:
                TCP_INC_STATS_BH(net, TCP_MIB_CSUMERRORS);
@@ -1505,6 +1516,8 @@ do_time_wait:
                goto discard_it;
        }
 
+       tcp_v6_fill_cb(skb, hdr, th);
+
        if (skb->len < (th->doff<<2)) {
                inet_twsk_put(inet_twsk(sk));
                goto bad_packet;
index 5f983644373a230890b25189865af73f5e2b3b44..48bf5a06847bd59db7834758b22aa9208d727940 100644 (file)
@@ -130,12 +130,18 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse)
 {
        struct flowi6 *fl6 = &fl->u.ip6;
        int onlyproto = 0;
-       u16 offset = skb_network_header_len(skb);
        const struct ipv6hdr *hdr = ipv6_hdr(skb);
+       u16 offset = sizeof(*hdr);
        struct ipv6_opt_hdr *exthdr;
        const unsigned char *nh = skb_network_header(skb);
-       u8 nexthdr = nh[IP6CB(skb)->nhoff];
+       u16 nhoff = IP6CB(skb)->nhoff;
        int oif = 0;
+       u8 nexthdr;
+
+       if (!nhoff)
+               nhoff = offsetof(struct ipv6hdr, nexthdr);
+
+       nexthdr = nh[nhoff];
 
        if (skb_dst(skb))
                oif = skb_dst(skb)->dev->ifindex;
index 612a5ddaf93b1ab1b5a524c5efef8d6b1f769038..799bafc2af39ea191e3753c88c3f921e44a77162 100644 (file)
@@ -18,28 +18,28 @@ static struct ctl_table llc2_timeout_table[] = {
        {
                .procname       = "ack",
                .data           = &sysctl_llc2_ack_timeout,
-               .maxlen         = sizeof(long),
+               .maxlen         = sizeof(sysctl_llc2_ack_timeout),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "busy",
                .data           = &sysctl_llc2_busy_timeout,
-               .maxlen         = sizeof(long),
+               .maxlen         = sizeof(sysctl_llc2_busy_timeout),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "p",
                .data           = &sysctl_llc2_p_timeout,
-               .maxlen         = sizeof(long),
+               .maxlen         = sizeof(sysctl_llc2_p_timeout),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "rej",
                .data           = &sysctl_llc2_rej_timeout,
-               .maxlen         = sizeof(long),
+               .maxlen         = sizeof(sysctl_llc2_rej_timeout),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
index 0bb7038121ac5557ba90114b706f8cbc0e404af2..bd4e46ec32bd3d43473c2ee3ac2b0b9888d397de 100644 (file)
@@ -140,7 +140,9 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
        if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-               if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                        sdata->crypto_tx_tailroom_needed_cnt--;
 
                WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
@@ -188,7 +190,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sta = key->sta;
        sdata = key->sdata;
 
-       if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+       if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+             (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                increment_tailroom_need_count(sdata);
 
        ret = drv_set_key(key->local, DISABLE_KEY, sdata,
@@ -884,7 +888,9 @@ void ieee80211_remove_key(struct ieee80211_key_conf *keyconf)
        if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) {
                key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 
-               if (!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC))
+               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                        increment_tailroom_need_count(key->sdata);
        }
 
index 2c36c4765f47f28c42d1b2112b59a764ba4ed82f..837a406a9dd67bdf506f98a3ae05be55c06f2211 100644 (file)
@@ -1643,7 +1643,7 @@ __ieee80211_sta_handle_tspec_ac_params(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-       bool ret;
+       bool ret = false;
        int ac;
 
        if (local->hw.queues < IEEE80211_NUM_ACS)
index 4c5192e0d66c7d5ae99913c2e9f2e27ff1626d71..4a95fe3cffbc9bd9e6d2ff6853b36ebe904b94a4 100644 (file)
@@ -86,20 +86,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                }
        }
 
-       /* tear down aggregation sessions and remove STAs */
-       mutex_lock(&local->sta_mtx);
-       list_for_each_entry(sta, &local->sta_list, list) {
-               if (sta->uploaded) {
-                       enum ieee80211_sta_state state;
-
-                       state = sta->sta_state;
-                       for (; state > IEEE80211_STA_NOTEXIST; state--)
-                               WARN_ON(drv_sta_state(local, sta->sdata, sta,
-                                                     state, state - 1));
-               }
-       }
-       mutex_unlock(&local->sta_mtx);
-
        /* remove all interfaces that were created in the driver */
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!ieee80211_sdata_running(sdata))
@@ -111,6 +97,21 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                case NL80211_IFTYPE_STATION:
                        ieee80211_mgd_quiesce(sdata);
                        break;
+               case NL80211_IFTYPE_WDS:
+                       /* tear down aggregation sessions and remove STAs */
+                       mutex_lock(&local->sta_mtx);
+                       sta = sdata->u.wds.sta;
+                       if (sta && sta->uploaded) {
+                               enum ieee80211_sta_state state;
+
+                               state = sta->sta_state;
+                               for (; state > IEEE80211_STA_NOTEXIST; state--)
+                                       WARN_ON(drv_sta_state(local, sta->sdata,
+                                                             sta, state,
+                                                             state - 1));
+                       }
+                       mutex_unlock(&local->sta_mtx);
+                       break;
                default:
                        break;
                }
index 683b10f4650577c7d0172733e935f7c169f20292..d69ca513848e7eda2227a18d0f98b164591532a1 100644 (file)
@@ -272,7 +272,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
                channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
        else if (rate)
-               channel_flags |= IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ;
+               channel_flags |= IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ;
        else
                channel_flags |= IEEE80211_CHAN_2GHZ;
        put_unaligned_le16(channel_flags, pos);
index ca27837974fedd82fffcd9c91aa565c60534b13c..349295d21946d0072fb6a0a6bada3bd45d54f95f 100644 (file)
@@ -31,10 +31,7 @@ static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
                                  SKB_GSO_TCPV6 |
                                  SKB_GSO_UDP |
                                  SKB_GSO_DODGY |
-                                 SKB_GSO_TCP_ECN |
-                                 SKB_GSO_GRE |
-                                 SKB_GSO_GRE_CSUM |
-                                 SKB_GSO_IPIP)))
+                                 SKB_GSO_TCP_ECN)))
                goto out;
 
        /* Setup inner SKB. */
index 1d5341f3761dfe1e57cc6505493bf270cca672de..5d3daae98bf0be1bc0fa699ec96208d2fa3da1d4 100644 (file)
@@ -183,6 +183,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
        struct nf_conn *ct;
        struct net *net;
 
+       *diff = 0;
+
 #ifdef CONFIG_IP_VS_IPV6
        /* This application helper doesn't work with IPv6 yet,
         * so turn this into a no-op for IPv6 packets
@@ -191,8 +193,6 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
                return 1;
 #endif
 
-       *diff = 0;
-
        /* Only useful for established sessions */
        if (cp->state != IP_VS_TCP_S_ESTABLISHED)
                return 1;
@@ -322,6 +322,9 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
        struct ip_vs_conn *n_cp;
        struct net *net;
 
+       /* no diff required for incoming packets */
+       *diff = 0;
+
 #ifdef CONFIG_IP_VS_IPV6
        /* This application helper doesn't work with IPv6 yet,
         * so turn this into a no-op for IPv6 packets
@@ -330,9 +333,6 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
                return 1;
 #endif
 
-       /* no diff required for incoming packets */
-       *diff = 0;
-
        /* Only useful for established sessions */
        if (cp->state != IP_VS_TCP_S_ESTABLISHED)
                return 1;
index a11674806707e18fb9d86860ad0717dfda0b0da2..46d1b26a468ed0d4cd0c9f30c02398f51c922db0 100644 (file)
@@ -611,16 +611,15 @@ __nf_conntrack_confirm(struct sk_buff *skb)
         */
        NF_CT_ASSERT(!nf_ct_is_confirmed(ct));
        pr_debug("Confirming conntrack %p\n", ct);
-       /* We have to check the DYING flag inside the lock to prevent
-          a race against nf_ct_get_next_corpse() possibly called from
-          user context, else we insert an already 'dead' hash, blocking
-          further use of that particular connection -JM */
+       /* We have to check the DYING flag after unlink to prevent
+        * a race against nf_ct_get_next_corpse() possibly called from
+        * user context, else we insert an already 'dead' hash, blocking
+        * further use of that particular connection -JM.
+        */
+       nf_ct_del_from_dying_or_unconfirmed_list(ct);
 
-       if (unlikely(nf_ct_is_dying(ct))) {
-               nf_conntrack_double_unlock(hash, reply_hash);
-               local_bh_enable();
-               return NF_ACCEPT;
-       }
+       if (unlikely(nf_ct_is_dying(ct)))
+               goto out;
 
        /* See if there's one in the list already, including reverse:
           NAT could have grabbed it without realizing, since we're
@@ -636,8 +635,6 @@ __nf_conntrack_confirm(struct sk_buff *skb)
                    zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
                        goto out;
 
-       nf_ct_del_from_dying_or_unconfirmed_list(ct);
-
        /* Timer relative to confirmation time, not original
           setting time, otherwise we'd get timer wrap in
           weird delay cases. */
@@ -673,6 +670,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
        return NF_ACCEPT;
 
 out:
+       nf_ct_add_to_dying_list(ct);
        nf_conntrack_double_unlock(hash, reply_hash);
        NF_CT_STAT_INC(net, insert_failed);
        local_bh_enable();
index 129a8daa4abf31959801e99c4f2fbfc7f1aab230..3b3ddb4fb9ee122a5b6d3a39450be38a64d6f614 100644 (file)
@@ -713,16 +713,12 @@ static int nft_flush_table(struct nft_ctx *ctx)
        struct nft_chain *chain, *nc;
        struct nft_set *set, *ns;
 
-       list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
+       list_for_each_entry(chain, &ctx->table->chains, list) {
                ctx->chain = chain;
 
                err = nft_delrule_by_chain(ctx);
                if (err < 0)
                        goto out;
-
-               err = nft_delchain(ctx);
-               if (err < 0)
-                       goto out;
        }
 
        list_for_each_entry_safe(set, ns, &ctx->table->sets, list) {
@@ -735,6 +731,14 @@ static int nft_flush_table(struct nft_ctx *ctx)
                        goto out;
        }
 
+       list_for_each_entry_safe(chain, nc, &ctx->table->chains, list) {
+               ctx->chain = chain;
+
+               err = nft_delchain(ctx);
+               if (err < 0)
+                       goto out;
+       }
+
        err = nft_deltable(ctx);
 out:
        return err;
index 13c2e17bbe279e6660a0a04fc804a6e1dd0a7707..c421d94c4652625147ba65aebe4c251561cf37ff 100644 (file)
@@ -321,7 +321,8 @@ replay:
                nlh = nlmsg_hdr(skb);
                err = 0;
 
-               if (nlh->nlmsg_len < NLMSG_HDRLEN) {
+               if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) ||
+                   skb->len < nlh->nlmsg_len) {
                        err = -EINVAL;
                        goto ack;
                }
@@ -463,13 +464,13 @@ static void nfnetlink_rcv(struct sk_buff *skb)
 }
 
 #ifdef CONFIG_MODULES
-static int nfnetlink_bind(int group)
+static int nfnetlink_bind(struct net *net, int group)
 {
        const struct nfnetlink_subsystem *ss;
        int type;
 
        if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
-               return -EINVAL;
+               return 0;
 
        type = nfnl_group2type[group];
 
index afe2b0b45ec41f82df6f2430958a4392aa5eb608..aff54fb1c8a09fdb99fd4caab0959a80f28ffc37 100644 (file)
@@ -65,10 +65,10 @@ static void nft_nat_eval(const struct nft_expr *expr,
        }
 
        if (priv->sreg_proto_min) {
-               range.min_proto.all = (__force __be16)
-                                       data[priv->sreg_proto_min].data[0];
-               range.max_proto.all = (__force __be16)
-                                       data[priv->sreg_proto_max].data[0];
+               range.min_proto.all =
+                       *(__be16 *)&data[priv->sreg_proto_min].data[0];
+               range.max_proto.all =
+                       *(__be16 *)&data[priv->sreg_proto_max].data[0];
                range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
        }
 
index 074cf3e91c6f2d5cb27ff7599f42d5b6c0ee1fd4..02fdde28dada498c1715b18ffa166d72ac6807d6 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/rhashtable.h>
 #include <asm/cacheflush.h>
 #include <linux/hash.h>
+#include <linux/genetlink.h>
 
 #include <net/net_namespace.h>
 #include <net/sock.h>
@@ -1091,8 +1092,12 @@ static void netlink_remove(struct sock *sk)
        mutex_unlock(&nl_sk_hash_lock);
 
        netlink_table_grab();
-       if (nlk_sk(sk)->subscriptions)
+       if (nlk_sk(sk)->subscriptions) {
                __sk_del_bind_node(sk);
+               netlink_update_listeners(sk);
+       }
+       if (sk->sk_protocol == NETLINK_GENERIC)
+               atomic_inc(&genl_sk_destructing_cnt);
        netlink_table_ungrab();
 }
 
@@ -1139,8 +1144,8 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol,
        struct module *module = NULL;
        struct mutex *cb_mutex;
        struct netlink_sock *nlk;
-       int (*bind)(int group);
-       void (*unbind)(int group);
+       int (*bind)(struct net *net, int group);
+       void (*unbind)(struct net *net, int group);
        int err = 0;
 
        sock->state = SS_UNCONNECTED;
@@ -1209,6 +1214,20 @@ static int netlink_release(struct socket *sock)
         * will be purged.
         */
 
+       /* must not acquire netlink_table_lock in any way again before unbind
+        * and notifying genetlink is done as otherwise it might deadlock
+        */
+       if (nlk->netlink_unbind) {
+               int i;
+
+               for (i = 0; i < nlk->ngroups; i++)
+                       if (test_bit(i, nlk->groups))
+                               nlk->netlink_unbind(sock_net(sk), i + 1);
+       }
+       if (sk->sk_protocol == NETLINK_GENERIC &&
+           atomic_dec_return(&genl_sk_destructing_cnt) == 0)
+               wake_up(&genl_sk_destructing_waitq);
+
        sock->sk = NULL;
        wake_up_interruptible_all(&nlk->wait);
 
@@ -1226,8 +1245,8 @@ static int netlink_release(struct socket *sock)
 
        module_put(nlk->module);
 
-       netlink_table_grab();
        if (netlink_is_kernel(sk)) {
+               netlink_table_grab();
                BUG_ON(nl_table[sk->sk_protocol].registered == 0);
                if (--nl_table[sk->sk_protocol].registered == 0) {
                        struct listeners *old;
@@ -1241,10 +1260,8 @@ static int netlink_release(struct socket *sock)
                        nl_table[sk->sk_protocol].flags = 0;
                        nl_table[sk->sk_protocol].registered = 0;
                }
-       } else if (nlk->subscriptions) {
-               netlink_update_listeners(sk);
+               netlink_table_ungrab();
        }
-       netlink_table_ungrab();
 
        kfree(nlk->groups);
        nlk->groups = NULL;
@@ -1410,9 +1427,10 @@ static int netlink_realloc_groups(struct sock *sk)
        return err;
 }
 
-static void netlink_unbind(int group, long unsigned int groups,
-                          struct netlink_sock *nlk)
+static void netlink_undo_bind(int group, long unsigned int groups,
+                             struct sock *sk)
 {
+       struct netlink_sock *nlk = nlk_sk(sk);
        int undo;
 
        if (!nlk->netlink_unbind)
@@ -1420,7 +1438,7 @@ static void netlink_unbind(int group, long unsigned int groups,
 
        for (undo = 0; undo < group; undo++)
                if (test_bit(undo, &groups))
-                       nlk->netlink_unbind(undo);
+                       nlk->netlink_unbind(sock_net(sk), undo);
 }
 
 static int netlink_bind(struct socket *sock, struct sockaddr *addr,
@@ -1458,10 +1476,10 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
                for (group = 0; group < nlk->ngroups; group++) {
                        if (!test_bit(group, &groups))
                                continue;
-                       err = nlk->netlink_bind(group);
+                       err = nlk->netlink_bind(net, group);
                        if (!err)
                                continue;
-                       netlink_unbind(group, groups, nlk);
+                       netlink_undo_bind(group, groups, sk);
                        return err;
                }
        }
@@ -1471,7 +1489,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr,
                        netlink_insert(sk, net, nladdr->nl_pid) :
                        netlink_autobind(sock);
                if (err) {
-                       netlink_unbind(nlk->ngroups, groups, nlk);
+                       netlink_undo_bind(nlk->ngroups, groups, sk);
                        return err;
                }
        }
@@ -2122,7 +2140,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                if (!val || val - 1 >= nlk->ngroups)
                        return -EINVAL;
                if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) {
-                       err = nlk->netlink_bind(val);
+                       err = nlk->netlink_bind(sock_net(sk), val);
                        if (err)
                                return err;
                }
@@ -2131,7 +2149,7 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                                         optname == NETLINK_ADD_MEMBERSHIP);
                netlink_table_ungrab();
                if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind)
-                       nlk->netlink_unbind(val);
+                       nlk->netlink_unbind(sock_net(sk), val);
 
                err = 0;
                break;
index b20a1731759b2e6dc8bbe3064933bb3d67134d26..f1c31b39aa3e0f5f8257b0ff72bd8bf909cac481 100644 (file)
@@ -2,6 +2,7 @@
 #define _AF_NETLINK_H
 
 #include <linux/rhashtable.h>
+#include <linux/atomic.h>
 #include <net/sock.h>
 
 #define NLGRPSZ(x)     (ALIGN(x, sizeof(unsigned long) * 8) / 8)
@@ -39,8 +40,8 @@ struct netlink_sock {
        struct mutex            *cb_mutex;
        struct mutex            cb_def_mutex;
        void                    (*netlink_rcv)(struct sk_buff *skb);
-       int                     (*netlink_bind)(int group);
-       void                    (*netlink_unbind)(int group);
+       int                     (*netlink_bind)(struct net *net, int group);
+       void                    (*netlink_unbind)(struct net *net, int group);
        struct module           *module;
 #ifdef CONFIG_NETLINK_MMAP
        struct mutex            pg_vec_lock;
@@ -65,8 +66,8 @@ struct netlink_table {
        unsigned int            groups;
        struct mutex            *cb_mutex;
        struct module           *module;
-       int                     (*bind)(int group);
-       void                    (*unbind)(int group);
+       int                     (*bind)(struct net *net, int group);
+       void                    (*unbind)(struct net *net, int group);
        bool                    (*compare)(struct net *net, struct sock *sock);
        int                     registered;
 };
index 76393f2f4b225713b9c85ee5aae722e109881080..ee57459fc2586842908751d282384dd1d683ed6f 100644 (file)
@@ -23,6 +23,9 @@
 static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */
 static DECLARE_RWSEM(cb_lock);
 
+atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0);
+DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq);
+
 void genl_lock(void)
 {
        mutex_lock(&genl_mutex);
@@ -435,15 +438,18 @@ int genl_unregister_family(struct genl_family *family)
 
        genl_lock_all();
 
-       genl_unregister_mc_groups(family);
-
        list_for_each_entry(rc, genl_family_chain(family->id), family_list) {
                if (family->id != rc->id || strcmp(rc->name, family->name))
                        continue;
 
+               genl_unregister_mc_groups(family);
+
                list_del(&rc->family_list);
                family->n_ops = 0;
-               genl_unlock_all();
+               up_write(&cb_lock);
+               wait_event(genl_sk_destructing_waitq,
+                          atomic_read(&genl_sk_destructing_cnt) == 0);
+               genl_unlock();
 
                kfree(family->attrbuf);
                genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0);
@@ -983,11 +989,63 @@ static struct genl_multicast_group genl_ctrl_groups[] = {
        { .name = "notify", },
 };
 
+static int genl_bind(struct net *net, int group)
+{
+       int i, err = -ENOENT;
+
+       down_read(&cb_lock);
+       for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
+               struct genl_family *f;
+
+               list_for_each_entry(f, genl_family_chain(i), family_list) {
+                       if (group >= f->mcgrp_offset &&
+                           group < f->mcgrp_offset + f->n_mcgrps) {
+                               int fam_grp = group - f->mcgrp_offset;
+
+                               if (!f->netnsok && net != &init_net)
+                                       err = -ENOENT;
+                               else if (f->mcast_bind)
+                                       err = f->mcast_bind(net, fam_grp);
+                               else
+                                       err = 0;
+                               break;
+                       }
+               }
+       }
+       up_read(&cb_lock);
+
+       return err;
+}
+
+static void genl_unbind(struct net *net, int group)
+{
+       int i;
+
+       down_read(&cb_lock);
+       for (i = 0; i < GENL_FAM_TAB_SIZE; i++) {
+               struct genl_family *f;
+
+               list_for_each_entry(f, genl_family_chain(i), family_list) {
+                       if (group >= f->mcgrp_offset &&
+                           group < f->mcgrp_offset + f->n_mcgrps) {
+                               int fam_grp = group - f->mcgrp_offset;
+
+                               if (f->mcast_unbind)
+                                       f->mcast_unbind(net, fam_grp);
+                               break;
+                       }
+               }
+       }
+       up_read(&cb_lock);
+}
+
 static int __net_init genl_pernet_init(struct net *net)
 {
        struct netlink_kernel_cfg cfg = {
                .input          = genl_rcv,
                .flags          = NL_CFG_F_NONROOT_RECV,
+               .bind           = genl_bind,
+               .unbind         = genl_unbind,
        };
 
        /* we'll bump the group number right afterwards */
index 764fdc39c63b6565d29d2c4a1d1ed7629924c412..770064c837112ca23fb1bbecf75b2d84643e88b0 100644 (file)
@@ -147,7 +147,8 @@ static int push_mpls(struct sk_buff *skb, struct sw_flow_key *key,
        hdr = eth_hdr(skb);
        hdr->h_proto = mpls->mpls_ethertype;
 
-       skb_set_inner_protocol(skb, skb->protocol);
+       if (!skb->inner_protocol)
+               skb_set_inner_protocol(skb, skb->protocol);
        skb->protocol = mpls->mpls_ethertype;
 
        invalidate_flow_key(key);
index 332b5a0317392002a18b86dadfd4671e18fb6896..b07349e82d788dba64e768cf3ea1da77b08a9652 100644 (file)
@@ -83,8 +83,7 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
                            unsigned int group)
 {
        return info->nlhdr->nlmsg_flags & NLM_F_ECHO ||
-              genl_has_listeners(family, genl_info_net(info)->genl_sock,
-                                 group);
+              genl_has_listeners(family, genl_info_net(info), group);
 }
 
 static void ovs_notify(struct genl_family *family,
@@ -525,7 +524,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        struct vport *input_vport;
        int len;
        int err;
-       bool log = !a[OVS_FLOW_ATTR_PROBE];
+       bool log = !a[OVS_PACKET_ATTR_PROBE];
 
        err = -EINVAL;
        if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
@@ -611,6 +610,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
        [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
        [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
+       [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
 };
 
 static const struct genl_ops dp_packet_genl_ops[] = {
index 70bef2ab7f2bc6017081ad780a8c5cb1aa9feb67..da2fae0873a5d7f4ad56a85b81575152ec1727bc 100644 (file)
@@ -70,6 +70,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
 {
        struct flow_stats *stats;
        int node = numa_node_id();
+       int len = skb->len + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
 
        stats = rcu_dereference(flow->stats[node]);
 
@@ -105,7 +106,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
                                if (likely(new_stats)) {
                                        new_stats->used = jiffies;
                                        new_stats->packet_count = 1;
-                                       new_stats->byte_count = skb->len;
+                                       new_stats->byte_count = len;
                                        new_stats->tcp_flags = tcp_flags;
                                        spin_lock_init(&new_stats->lock);
 
@@ -120,7 +121,7 @@ void ovs_flow_stats_update(struct sw_flow *flow, __be16 tcp_flags,
 
        stats->used = jiffies;
        stats->packet_count++;
-       stats->byte_count += skb->len;
+       stats->byte_count += len;
        stats->tcp_flags |= tcp_flags;
 unlock:
        spin_unlock(&stats->lock);
index 9645a21d9eaa316057c0ed137a43bce11f34b70a..d1eecf707613eb5cb0c68531f63cf46ff6f82c63 100644 (file)
@@ -1753,7 +1753,6 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                                  __be16 eth_type, __be16 vlan_tci, bool log)
 {
        const struct nlattr *a;
-       bool out_tnl_port = false;
        int rem, err;
 
        if (depth >= SAMPLE_ACTION_DEPTH)
@@ -1796,8 +1795,6 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                case OVS_ACTION_ATTR_OUTPUT:
                        if (nla_get_u32(a) >= DP_MAX_PORTS)
                                return -EINVAL;
-                       out_tnl_port = false;
-
                        break;
 
                case OVS_ACTION_ATTR_HASH: {
@@ -1832,12 +1829,6 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                case OVS_ACTION_ATTR_PUSH_MPLS: {
                        const struct ovs_action_push_mpls *mpls = nla_data(a);
 
-                       /* Networking stack do not allow simultaneous Tunnel
-                        * and MPLS GSO.
-                        */
-                       if (out_tnl_port)
-                               return -EINVAL;
-
                        if (!eth_p_mpls(mpls->mpls_ethertype))
                                return -EINVAL;
                        /* Prohibit push MPLS other than to a white list
@@ -1873,11 +1864,9 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
 
                case OVS_ACTION_ATTR_SET:
                        err = validate_set(a, key, sfa,
-                                          &out_tnl_port, eth_type, log);
+                                          &skip_copy, eth_type, log);
                        if (err)
                                return err;
-
-                       skip_copy = out_tnl_port;
                        break;
 
                case OVS_ACTION_ATTR_SAMPLE:
index 347fa2325b226309b8e3cfb239f2e1d0a6631a50..484864dd0e689290dfca8a2c204e984de1b33184 100644 (file)
@@ -219,7 +219,10 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb)
                              false);
        if (err < 0)
                ip_rt_put(rt);
+       return err;
+
 error:
+       kfree_skb(skb);
        return err;
 }
 
index 6b69df545b1da3dba7ffedb92e106855106fd8d6..d4168c442db5af8683c72bfb24ce95c789dadcf8 100644 (file)
@@ -73,7 +73,7 @@ static struct sk_buff *__build_header(struct sk_buff *skb,
 
        skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM));
        if (IS_ERR(skb))
-               return NULL;
+               return skb;
 
        tpi.flags = filter_tnl_flags(tun_key->tun_flags);
        tpi.proto = htons(ETH_P_TEB);
@@ -144,7 +144,7 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
 
        if (unlikely(!OVS_CB(skb)->egress_tun_info)) {
                err = -EINVAL;
-               goto error;
+               goto err_free_skb;
        }
 
        tun_key = &OVS_CB(skb)->egress_tun_info->tunnel;
@@ -157,8 +157,10 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
        fl.flowi4_proto = IPPROTO_GRE;
 
        rt = ip_route_output_key(net, &fl);
-       if (IS_ERR(rt))
-               return PTR_ERR(rt);
+       if (IS_ERR(rt)) {
+               err = PTR_ERR(rt);
+               goto err_free_skb;
+       }
 
        tunnel_hlen = ip_gre_calc_hlen(tun_key->tun_flags);
 
@@ -183,8 +185,9 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
 
        /* Push Tunnel header. */
        skb = __build_header(skb, tunnel_hlen);
-       if (unlikely(!skb)) {
-               err = 0;
+       if (IS_ERR(skb)) {
+               err = PTR_ERR(skb);
+               skb = NULL;
                goto err_free_rt;
        }
 
@@ -198,7 +201,8 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb)
                             tun_key->ipv4_tos, tun_key->ipv4_ttl, df, false);
 err_free_rt:
        ip_rt_put(rt);
-error:
+err_free_skb:
+       kfree_skb(skb);
        return err;
 }
 
index 38f95a52241bd53af8de06b76079e403de8413cf..d7c46b301024906cf748453d24b91d2790f2e272 100644 (file)
@@ -187,7 +187,9 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb)
                             false);
        if (err < 0)
                ip_rt_put(rt);
+       return err;
 error:
+       kfree_skb(skb);
        return err;
 }
 
index 9584526c077804f21d22726d4bb5bd7cc4260d36..2034c6d9cb5a51f3094747e768c93522024bea96 100644 (file)
@@ -480,7 +480,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
        stats = this_cpu_ptr(vport->percpu_stats);
        u64_stats_update_begin(&stats->syncp);
        stats->rx_packets++;
-       stats->rx_bytes += skb->len;
+       stats->rx_bytes += skb->len + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
        u64_stats_update_end(&stats->syncp);
 
        OVS_CB(skb)->input_vport = vport;
@@ -519,10 +519,9 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
                u64_stats_update_end(&stats->syncp);
        } else if (sent < 0) {
                ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
-               kfree_skb(skb);
-       } else
+       } else {
                ovs_vport_record_error(vport, VPORT_E_TX_DROPPED);
-
+       }
        return sent;
 }
 
index e52a4478568198e88d1d8f8ee6a8506284c36323..9cfe2e1dd8b5099bbac7d824241bd0d06cb01cf7 100644 (file)
@@ -785,6 +785,7 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
 
        struct tpacket3_hdr *last_pkt;
        struct tpacket_hdr_v1 *h1 = &pbd1->hdr.bh1;
+       struct sock *sk = &po->sk;
 
        if (po->stats.stats3.tp_drops)
                status |= TP_STATUS_LOSING;
@@ -809,6 +810,8 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1,
        /* Flush the block */
        prb_flush_block(pkc1, pbd1, status);
 
+       sk->sk_data_ready(sk);
+
        pkc1->kactive_blk_num = GET_NEXT_PRB_BLK_NUM(pkc1);
 }
 
@@ -2052,12 +2055,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        smp_wmb();
 #endif
 
-       if (po->tp_version <= TPACKET_V2)
+       if (po->tp_version <= TPACKET_V2) {
                __packet_set_status(po, h.raw, status);
-       else
+               sk->sk_data_ready(sk);
+       } else {
                prb_clear_blk_fill_status(&po->rx_ring);
-
-       sk->sk_data_ready(sk);
+       }
 
 drop_n_restore:
        if (skb_head != skb->data && skb_shared(skb)) {
@@ -2514,7 +2517,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
        err = -EINVAL;
        if (sock->type == SOCK_DGRAM) {
                offset = dev_hard_header(skb, dev, ntohs(proto), addr, NULL, len);
-               if (unlikely(offset) < 0)
+               if (unlikely(offset < 0))
                        goto out_free;
        } else {
                if (ll_header_truncated(dev, len))
index 84c8219c3e1ce18867466786ae061d13178d7519..f59adf8a4cd780738187d5a50622f1ff9d50a20b 100644 (file)
@@ -180,6 +180,11 @@ static int cls_bpf_modify_existing(struct net *net, struct tcf_proto *tp,
        }
 
        bpf_size = bpf_len * sizeof(*bpf_ops);
+       if (bpf_size != nla_len(tb[TCA_BPF_OPS])) {
+               ret = -EINVAL;
+               goto errout;
+       }
+
        bpf_ops = kzalloc(bpf_size, GFP_KERNEL);
        if (bpf_ops == NULL) {
                ret = -ENOMEM;
@@ -215,15 +220,21 @@ static u32 cls_bpf_grab_new_handle(struct tcf_proto *tp,
                                   struct cls_bpf_head *head)
 {
        unsigned int i = 0x80000000;
+       u32 handle;
 
        do {
                if (++head->hgen == 0x7FFFFFFF)
                        head->hgen = 1;
        } while (--i > 0 && cls_bpf_get(tp, head->hgen));
-       if (i == 0)
+
+       if (unlikely(i == 0)) {
                pr_err("Insufficient number of handles\n");
+               handle = 0;
+       } else {
+               handle = head->hgen;
+       }
 
-       return i;
+       return handle;
 }
 
 static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
index f791edd64d6c0c76dea92888c44530cd1af21a23..26d06dbcc1c8e137798be5071848990fe00a7fe6 100644 (file)
@@ -1182,7 +1182,6 @@ void sctp_assoc_update(struct sctp_association *asoc,
        asoc->peer.peer_hmacs = new->peer.peer_hmacs;
        new->peer.peer_hmacs = NULL;
 
-       sctp_auth_key_put(asoc->asoc_shared_key);
        sctp_auth_asoc_init_active_key(asoc, GFP_ATOMIC);
 }
 
index 2625eccb77d5d7738f9e50930ab37a6db6a80760..aafe94bf292e73ecb765a31ae3456c3c11fe932f 100644 (file)
@@ -1603,7 +1603,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        sctp_assoc_t associd = 0;
        sctp_cmsgs_t cmsgs = { NULL };
        sctp_scope_t scope;
-       bool fill_sinfo_ttl = false;
+       bool fill_sinfo_ttl = false, wait_connect = false;
        struct sctp_datamsg *datamsg;
        int msg_flags = msg->msg_flags;
        __u16 sinfo_flags = 0;
@@ -1943,6 +1943,7 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                if (err < 0)
                        goto out_free;
 
+               wait_connect = true;
                pr_debug("%s: we associated primitively\n", __func__);
        }
 
@@ -1980,6 +1981,11 @@ static int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
        sctp_datamsg_put(datamsg);
        err = msg_len;
 
+       if (unlikely(wait_connect)) {
+               timeo = sock_sndtimeo(sk, msg_flags & MSG_DONTWAIT);
+               sctp_wait_for_connect(asoc, &timeo);
+       }
+
        /* If we are already past ASSOCIATE, the lower
         * layers are responsible for association cleanup.
         */
index a2c33a4dc7bab45e520556557924b62d24951d85..418795caa8979fd0eb5d19e4d1fe3376fc0e9b20 100644 (file)
@@ -869,9 +869,6 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
 static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
                                         struct sock_iocb *siocb)
 {
-       if (!is_sync_kiocb(iocb))
-               BUG();
-
        siocb->kiocb = iocb;
        iocb->private = siocb;
        return siocb;
index 1cb61242e55e47e66d5e50e9ad1b0fafd127ac40..4439ac4c1b53fcaf12a8a06723b4a51330dddeae 100644 (file)
@@ -606,7 +606,7 @@ void xdr_truncate_encode(struct xdr_stream *xdr, size_t len)
        struct kvec *head = buf->head;
        struct kvec *tail = buf->tail;
        int fraglen;
-       int new, old;
+       int new;
 
        if (len > buf->len) {
                WARN_ON_ONCE(1);
@@ -629,8 +629,8 @@ void xdr_truncate_encode(struct xdr_stream *xdr, size_t len)
        buf->len -= fraglen;
 
        new = buf->page_base + buf->page_len;
-       old = new + fraglen;
-       xdr->page_ptr -= (old >> PAGE_SHIFT) - (new >> PAGE_SHIFT);
+
+       xdr->page_ptr = buf->pages + (new >> PAGE_SHIFT);
 
        if (buf->page_len) {
                xdr->p = page_address(*xdr->page_ptr);
index 96ceefeb9daf4eb780cd168b4d008418c0055dd9..a9e174fc0f91fd672eb3779f23fff9ef7decdb74 100644 (file)
@@ -220,10 +220,11 @@ static void bclink_retransmit_pkt(u32 after, u32 to)
        struct sk_buff *skb;
 
        skb_queue_walk(&bcl->outqueue, skb) {
-               if (more(buf_seqno(skb), after))
+               if (more(buf_seqno(skb), after)) {
+                       tipc_link_retransmit(bcl, skb, mod(to - after));
                        break;
+               }
        }
-       tipc_link_retransmit(bcl, skb, mod(to - after));
 }
 
 /**
index 22ba971741e5c998c5f314e083ceead4b2f6a94f..29c8675f9a1189db65c185f2ad04f96a67702989 100644 (file)
@@ -175,7 +175,7 @@ config CFG80211_INTERNAL_REGDB
          Most distributions have a CRDA package.  So if unsure, say N.
 
 config CFG80211_WEXT
-       bool
+       bool "cfg80211 wireless extensions compatibility"
        depends on CFG80211
        select WEXT_CORE
        help
index 7ca4b5133123f4464e289976d152ac1d2fc1769c..8887c6e5fca85c3e417fc21052d117ac72adccd4 100644 (file)
@@ -2854,6 +2854,9 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
        if (!rdev->ops->get_key)
                return -EOPNOTSUPP;
 
+       if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
+               return -ENOENT;
+
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
@@ -2873,10 +2876,6 @@ static int nl80211_get_key(struct sk_buff *skb, struct genl_info *info)
            nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
                goto nla_put_failure;
 
-       if (pairwise && mac_addr &&
-           !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
-               return -ENOENT;
-
        err = rdev_get_key(rdev, dev, key_idx, pairwise, mac_addr, &cookie,
                           get_key_callback);
 
@@ -3047,7 +3046,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
        wdev_lock(dev->ieee80211_ptr);
        err = nl80211_key_allowed(dev->ieee80211_ptr);
 
-       if (key.type == NL80211_KEYTYPE_PAIRWISE && mac_addr &&
+       if (key.type == NL80211_KEYTYPE_GROUP && mac_addr &&
            !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
                err = -ENOENT;
 
index 7b8309840d4e1b499cc7efbd73bc07222c0d5def..d39d1cbc86b1663f1902e6662dfe372c50978327 100644 (file)
@@ -1530,45 +1530,40 @@ static void reg_call_notifier(struct wiphy *wiphy,
 
 static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
 {
-       struct ieee80211_channel *ch;
        struct cfg80211_chan_def chandef;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-       bool ret = true;
+       enum nl80211_iftype iftype;
 
        wdev_lock(wdev);
+       iftype = wdev->iftype;
 
+       /* make sure the interface is active */
        if (!wdev->netdev || !netif_running(wdev->netdev))
-               goto out;
+               goto wdev_inactive_unlock;
 
-       switch (wdev->iftype) {
+       switch (iftype) {
        case NL80211_IFTYPE_AP:
        case NL80211_IFTYPE_P2P_GO:
                if (!wdev->beacon_interval)
-                       goto out;
-
-               ret = cfg80211_reg_can_beacon(wiphy,
-                                             &wdev->chandef, wdev->iftype);
+                       goto wdev_inactive_unlock;
+               chandef = wdev->chandef;
                break;
        case NL80211_IFTYPE_ADHOC:
                if (!wdev->ssid_len)
-                       goto out;
-
-               ret = cfg80211_reg_can_beacon(wiphy,
-                                             &wdev->chandef, wdev->iftype);
+                       goto wdev_inactive_unlock;
+               chandef = wdev->chandef;
                break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_P2P_CLIENT:
                if (!wdev->current_bss ||
                    !wdev->current_bss->pub.channel)
-                       goto out;
+                       goto wdev_inactive_unlock;
 
-               ch = wdev->current_bss->pub.channel;
-               if (rdev->ops->get_channel &&
-                   !rdev_get_channel(rdev, wdev, &chandef))
-                       ret = cfg80211_chandef_usable(wiphy, &chandef,
-                                                     IEEE80211_CHAN_DISABLED);
-               else
-                       ret = !(ch->flags & IEEE80211_CHAN_DISABLED);
+               if (!rdev->ops->get_channel ||
+                   rdev_get_channel(rdev, wdev, &chandef))
+                       cfg80211_chandef_create(&chandef,
+                                               wdev->current_bss->pub.channel,
+                                               NL80211_CHAN_NO_HT);
                break;
        case NL80211_IFTYPE_MONITOR:
        case NL80211_IFTYPE_AP_VLAN:
@@ -1581,9 +1576,26 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
                break;
        }
 
-out:
        wdev_unlock(wdev);
-       return ret;
+
+       switch (iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_ADHOC:
+               return cfg80211_reg_can_beacon(wiphy, &chandef, iftype);
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
+               return cfg80211_chandef_usable(wiphy, &chandef,
+                                              IEEE80211_CHAN_DISABLED);
+       default:
+               break;
+       }
+
+       return true;
+
+wdev_inactive_unlock:
+       wdev_unlock(wdev);
+       return true;
 }
 
 static void reg_leave_invalid_chans(struct wiphy *wiphy)
index d0ac795445b7e40dc92ebb1e0bd9095fc4bab048..5488c3662f7d7671c184215ae1d74faf0190b126 100644 (file)
@@ -308,6 +308,12 @@ unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
                goto out;
        }
 
+       if (ieee80211_is_mgmt(fc)) {
+               if (ieee80211_has_order(fc))
+                       hdrlen += IEEE80211_HT_CTL_LEN;
+               goto out;
+       }
+
        if (ieee80211_is_ctl(fc)) {
                /*
                 * ACK and CTS are 10 bytes, all others 16. To see how
index e286b42307f30dfe840267be16c53b0580150905..6299ee95cd11b63112ae5b7875872cb72ca91208 100644 (file)
@@ -69,9 +69,9 @@ static void test_hashmap_sanity(int i, void *data)
 
        /* iterate over two elements */
        assert(bpf_get_next_key(map_fd, &key, &next_key) == 0 &&
-              next_key == 2);
+              (next_key == 1 || next_key == 2));
        assert(bpf_get_next_key(map_fd, &next_key, &next_key) == 0 &&
-              next_key == 1);
+              (next_key == 1 || next_key == 2));
        assert(bpf_get_next_key(map_fd, &next_key, &next_key) == -1 &&
               errno == ENOENT);
 
index 1bca180db8ad0b6475464f3ca8ea78c881c1b1c5..627f8cbbedb88ca29667bbf1f88eb2004d5ee461 100644 (file)
@@ -42,19 +42,19 @@ __clean-files       := $(extra-y) $(extra-m) $(extra-)       \
 
 __clean-files   := $(filter-out $(no-clean-files), $(__clean-files))
 
-# as clean-files is given relative to the current directory, this adds
-# a $(obj) prefix, except for absolute paths
+# clean-files is given relative to the current directory, unless it
+# starts with $(objtree)/ (which means "./", so do not add "./" unless
+# you want to delete a file from the toplevel object directory).
 
 __clean-files   := $(wildcard                                               \
-                   $(addprefix $(obj)/, $(filter-out /%, $(__clean-files))) \
-                  $(filter /%, $(__clean-files)))
+                  $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(__clean-files))) \
+                  $(filter $(objtree)/%, $(__clean-files)))
 
-# as clean-dirs is given relative to the current directory, this adds
-# a $(obj) prefix, except for absolute paths
+# same as clean-files
 
 __clean-dirs    := $(wildcard                                               \
-                   $(addprefix $(obj)/, $(filter-out /%, $(clean-dirs)))    \
-                  $(filter /%, $(clean-dirs)))
+                  $(addprefix $(obj)/, $(filter-out $(objtree)/%, $(clean-dirs)))    \
+                  $(filter $(objtree)/%, $(clean-dirs)))
 
 # ==========================================================================
 
index 56ea99a12ab79c82e062b54cfd34d9a39ef6a867..537c38ca2e1c7008b2f0f98d4e172c714162eb79 100755 (executable)
@@ -255,7 +255,6 @@ if ($arch eq "x86_64") {
     # force flags for this arch
     $ld .= " -m shlelf_linux";
     $objcopy .= " -O elf32-sh-linux";
-    $cc .= " -m32";
 
 } elsif ($arch eq "powerpc") {
     $local_regex = "^[0-9a-fA-F]+\\s+t\\s+(\\.?\\S+)";
index 9609a7f0faea2d53d2ca7c642cf24935012cdaae..c7952375ac5325cfb4c403fa1020671b5f31a150 100644 (file)
@@ -148,12 +148,12 @@ static noinline void key_gc_unused_keys(struct list_head *keys)
                if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                        atomic_dec(&key->user->nikeys);
 
-               key_user_put(key->user);
-
                /* now throw away the key memory */
                if (key->type->destroy)
                        key->type->destroy(key);
 
+               key_user_put(key->user);
+
                kfree(key->description);
 
 #ifdef KEY_DEBUGGING
index ec9e7866177feff13db582abc6007fa6f4a40932..446c00bd908bed1931dad01ac0d4920ed8c000de 100644 (file)
@@ -1015,6 +1015,60 @@ int snd_interval_list(struct snd_interval *i, unsigned int count,
 
 EXPORT_SYMBOL(snd_interval_list);
 
+/**
+ * snd_interval_ranges - refine the interval value from the list of ranges
+ * @i: the interval value to refine
+ * @count: the number of elements in the list of ranges
+ * @ranges: the ranges list
+ * @mask: the bit-mask to evaluate
+ *
+ * Refines the interval value from the list of ranges.
+ * When mask is non-zero, only the elements corresponding to bit 1 are
+ * evaluated.
+ *
+ * Return: Positive if the value is changed, zero if it's not changed, or a
+ * negative error code.
+ */
+int snd_interval_ranges(struct snd_interval *i, unsigned int count,
+                       const struct snd_interval *ranges, unsigned int mask)
+{
+       unsigned int k;
+       struct snd_interval range_union;
+       struct snd_interval range;
+
+       if (!count) {
+               snd_interval_none(i);
+               return -EINVAL;
+       }
+       snd_interval_any(&range_union);
+       range_union.min = UINT_MAX;
+       range_union.max = 0;
+       for (k = 0; k < count; k++) {
+               if (mask && !(mask & (1 << k)))
+                       continue;
+               snd_interval_copy(&range, &ranges[k]);
+               if (snd_interval_refine(&range, i) < 0)
+                       continue;
+               if (snd_interval_empty(&range))
+                       continue;
+
+               if (range.min < range_union.min) {
+                       range_union.min = range.min;
+                       range_union.openmin = 1;
+               }
+               if (range.min == range_union.min && !range.openmin)
+                       range_union.openmin = 0;
+               if (range.max > range_union.max) {
+                       range_union.max = range.max;
+                       range_union.openmax = 1;
+               }
+               if (range.max == range_union.max && !range.openmax)
+                       range_union.openmax = 0;
+       }
+       return snd_interval_refine(i, &range_union);
+}
+EXPORT_SYMBOL(snd_interval_ranges);
+
 static int snd_interval_step(struct snd_interval *i, unsigned int step)
 {
        unsigned int n;
@@ -1221,6 +1275,37 @@ int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
 
 EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
 
+static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
+                                 struct snd_pcm_hw_rule *rule)
+{
+       struct snd_pcm_hw_constraint_ranges *r = rule->private;
+       return snd_interval_ranges(hw_param_interval(params, rule->var),
+                                  r->count, r->ranges, r->mask);
+}
+
+
+/**
+ * snd_pcm_hw_constraint_ranges - apply list of range constraints to a parameter
+ * @runtime: PCM runtime instance
+ * @cond: condition bits
+ * @var: hw_params variable to apply the list of range constraints
+ * @r: ranges
+ *
+ * Apply the list of range constraints to an interval parameter.
+ *
+ * Return: Zero if successful, or a negative error code on failure.
+ */
+int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
+                                unsigned int cond,
+                                snd_pcm_hw_param_t var,
+                                const struct snd_pcm_hw_constraint_ranges *r)
+{
+       return snd_pcm_hw_rule_add(runtime, cond, var,
+                                  snd_pcm_hw_rule_ranges, (void *)r,
+                                  var, -1);
+}
+EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
+
 static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
                                   struct snd_pcm_hw_rule *rule)
 {
index ec667f158f192c4467e020164ecd4adf30a5ce04..5d905d90d504c0d588b62bb856e7314e23488ec0 100644 (file)
@@ -81,36 +81,6 @@ struct snd_seq_dummy_port {
 
 static int my_client = -1;
 
-/*
- * unuse callback - send ALL_SOUNDS_OFF and RESET_CONTROLLERS events
- * to subscribers.
- * Note: this callback is called only after all subscribers are removed.
- */
-static int
-dummy_unuse(void *private_data, struct snd_seq_port_subscribe *info)
-{
-       struct snd_seq_dummy_port *p;
-       int i;
-       struct snd_seq_event ev;
-
-       p = private_data;
-       memset(&ev, 0, sizeof(ev));
-       if (p->duplex)
-               ev.source.port = p->connect;
-       else
-               ev.source.port = p->port;
-       ev.dest.client = SNDRV_SEQ_ADDRESS_SUBSCRIBERS;
-       ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
-       for (i = 0; i < 16; i++) {
-               ev.data.control.channel = i;
-               ev.data.control.param = MIDI_CTL_ALL_SOUNDS_OFF;
-               snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0);
-               ev.data.control.param = MIDI_CTL_RESET_CONTROLLERS;
-               snd_seq_kernel_client_dispatch(p->client, &ev, 0, 0);
-       }
-       return 0;
-}
-
 /*
  * event input callback - just redirect events to subscribers
  */
@@ -175,7 +145,6 @@ create_port(int idx, int type)
                | SNDRV_SEQ_PORT_TYPE_PORT;
        memset(&pcb, 0, sizeof(pcb));
        pcb.owner = THIS_MODULE;
-       pcb.unuse = dummy_unuse;
        pcb.event_input = dummy_input;
        pcb.private_free = dummy_free;
        pcb.private_data = rec;
index 3badc70124ab19d9b2e6115198e88c46718676e9..0d580186ef1ac379bcd2cb699ac2f33baeac9029 100644 (file)
 #define CYCLES_PER_SECOND      8000
 #define TICKS_PER_SECOND       (TICKS_PER_CYCLE * CYCLES_PER_SECOND)
 
-#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 Âµs */
+/*
+ * Nominally 3125 bytes/second, but the MIDI port's clock might be
+ * 1% too slow, and the bus clock 100 ppm too fast.
+ */
+#define MIDI_BYTES_PER_SECOND  3093
+
+/*
+ * Several devices look only at the first eight data blocks.
+ * In any case, this is more than enough for the MIDI data rate.
+ */
+#define MAX_MIDI_RX_BLOCKS     8
+
+#define TRANSFER_DELAY_TICKS   0x2e00 /* 479.17 Ã‚µs */
 
 /* isochronous header parameters */
 #define ISO_DATA_LENGTH_SHIFT  16
@@ -78,8 +90,6 @@ int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
        s->callbacked = false;
        s->sync_slave = NULL;
 
-       s->rx_blocks_for_midi = UINT_MAX;
-
        return 0;
 }
 EXPORT_SYMBOL(amdtp_stream_init);
@@ -222,6 +232,14 @@ sfc_found:
        for (i = 0; i < pcm_channels; i++)
                s->pcm_positions[i] = i;
        s->midi_position = s->pcm_channels;
+
+       /*
+        * We do not know the actual MIDI FIFO size of most devices.  Just
+        * assume two bytes, i.e., one byte can be received over the bus while
+        * the previous one is transmitted over MIDI.
+        * (The value here is adjusted for midi_ratelimit_per_packet().)
+        */
+       s->midi_fifo_limit = rate - MIDI_BYTES_PER_SECOND * s->syt_interval + 1;
 }
 EXPORT_SYMBOL(amdtp_stream_set_parameters);
 
@@ -463,6 +481,36 @@ static void amdtp_fill_pcm_silence(struct amdtp_stream *s,
        }
 }
 
+/*
+ * To avoid sending MIDI bytes at too high a rate, assume that the receiving
+ * device has a FIFO, and track how much it is filled.  This values increases
+ * by one whenever we send one byte in a packet, but the FIFO empties at
+ * a constant rate independent of our packet rate.  One packet has syt_interval
+ * samples, so the number of bytes that empty out of the FIFO, per packet(!),
+ * is MIDI_BYTES_PER_SECOND * syt_interval / sample_rate.  To avoid storing
+ * fractional values, the values in midi_fifo_used[] are measured in bytes
+ * multiplied by the sample rate.
+ */
+static bool midi_ratelimit_per_packet(struct amdtp_stream *s, unsigned int port)
+{
+       int used;
+
+       used = s->midi_fifo_used[port];
+       if (used == 0) /* common shortcut */
+               return true;
+
+       used -= MIDI_BYTES_PER_SECOND * s->syt_interval;
+       used = max(used, 0);
+       s->midi_fifo_used[port] = used;
+
+       return used < s->midi_fifo_limit;
+}
+
+static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
+{
+       s->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
+}
+
 static void amdtp_fill_midi(struct amdtp_stream *s,
                            __be32 *buffer, unsigned int frames)
 {
@@ -470,16 +518,21 @@ static void amdtp_fill_midi(struct amdtp_stream *s,
        u8 *b;
 
        for (f = 0; f < frames; f++) {
-               buffer[s->midi_position] = 0;
                b = (u8 *)&buffer[s->midi_position];
 
                port = (s->data_block_counter + f) % 8;
-               if ((f >= s->rx_blocks_for_midi) ||
-                   (s->midi[port] == NULL) ||
-                   (snd_rawmidi_transmit(s->midi[port], b + 1, 1) <= 0))
-                       b[0] = 0x80;
-               else
+               if (f < MAX_MIDI_RX_BLOCKS &&
+                   midi_ratelimit_per_packet(s, port) &&
+                   s->midi[port] != NULL &&
+                   snd_rawmidi_transmit(s->midi[port], &b[1], 1) == 1) {
+                       midi_rate_use_one_byte(s, port);
                        b[0] = 0x81;
+               } else {
+                       b[0] = 0x80;
+                       b[1] = 0;
+               }
+               b[2] = 0;
+               b[3] = 0;
 
                buffer += s->data_block_quadlets;
        }
index e6e8926275b0542c9891373e2d3d473cbd682286..8a03a91e728b0f9bc4feb23a4bdd9f22fdf5952d 100644 (file)
@@ -148,13 +148,12 @@ struct amdtp_stream {
        bool double_pcm_frames;
 
        struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
+       int midi_fifo_limit;
+       int midi_fifo_used[AMDTP_MAX_CHANNELS_FOR_MIDI * 8];
 
        /* quirk: fixed interval of dbc between previos/current packets. */
        unsigned int tx_dbc_interval;
 
-       /* quirk: the first count of data blocks in an rx packet for MIDI */
-       unsigned int rx_blocks_for_midi;
-
        bool callbacked;
        wait_queue_head_t callback_wait;
        struct amdtp_stream *sync_slave;
index 1aab0a32870c84d20a0c5b87f46d625299b34fd4..0ebcabfdc7ce0162c9a77ed30ca038e6588cae63 100644 (file)
@@ -484,13 +484,6 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
                amdtp_stream_destroy(&bebob->rx_stream);
                destroy_both_connections(bebob);
        }
-       /*
-        * The firmware for these devices ignore MIDI messages in more than
-        * first 8 data blocks of an received AMDTP packet.
-        */
-       if (bebob->spec == &maudio_fw410_spec ||
-           bebob->spec == &maudio_special_spec)
-               bebob->rx_stream.rx_blocks_for_midi = 8;
 end:
        return err;
 }
index b985fc5ebdc6b9cc490e41695d76b579a7b3fe3d..4f440e16366780f097d8c03daeb45e01fb5e7eb0 100644 (file)
@@ -179,11 +179,6 @@ int snd_efw_stream_init_duplex(struct snd_efw *efw)
                destroy_stream(efw, &efw->tx_stream);
                goto end;
        }
-       /*
-        * Fireworks ignores MIDI messages in more than first 8 data
-        * blocks of an received AMDTP packet.
-        */
-       efw->rx_stream.rx_blocks_for_midi = 8;
 
        /* set IEC61883 compliant mode (actually not fully compliant...) */
        err = snd_efw_command_set_tx_mode(efw, SND_EFW_TRANSPORT_MODE_IEC61883);
index 255dabc6fc3313debc4b943d02e80a15b9e7f70a..2a85e4209f0b74d6f169dd705ffbf6fc9a2d3402 100644 (file)
@@ -124,7 +124,7 @@ copy_resp_to_buf(struct snd_efw *efw, void *data, size_t length, int *rcode)
        spin_lock_irq(&efw->lock);
 
        t = (struct snd_efw_transaction *)data;
-       length = min_t(size_t, t->length * sizeof(t->length), length);
+       length = min_t(size_t, be32_to_cpu(t->length) * sizeof(u32), length);
 
        if (efw->push_ptr < efw->pull_ptr)
                capacity = (unsigned int)(efw->pull_ptr - efw->push_ptr);
index 8276a743e22ef2e1c234dcc291106fa627858b14..0cfc9c8c4b4e811ac6f0b6bbeb0d24377c95232d 100644 (file)
@@ -1922,10 +1922,18 @@ int azx_mixer_create(struct azx *chip)
 EXPORT_SYMBOL_GPL(azx_mixer_create);
 
 
+static bool is_input_stream(struct azx *chip, unsigned char index)
+{
+       return (index >= chip->capture_index_offset &&
+               index < chip->capture_index_offset + chip->capture_streams);
+}
+
 /* initialize SD streams */
 int azx_init_stream(struct azx *chip)
 {
        int i;
+       int in_stream_tag = 0;
+       int out_stream_tag = 0;
 
        /* initialize each stream (aka device)
         * assign the starting bdl address to each stream (device)
@@ -1938,9 +1946,21 @@ int azx_init_stream(struct azx *chip)
                azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80);
                /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */
                azx_dev->sd_int_sta_mask = 1 << i;
-               /* stream tag: must be non-zero and unique */
                azx_dev->index = i;
-               azx_dev->stream_tag = i + 1;
+
+               /* stream tag must be unique throughout
+                * the stream direction group,
+                * valid values 1...15
+                * use separate stream tag if the flag
+                * AZX_DCAPS_SEPARATE_STREAM_TAG is used
+                */
+               if (chip->driver_caps & AZX_DCAPS_SEPARATE_STREAM_TAG)
+                       azx_dev->stream_tag =
+                               is_input_stream(chip, i) ?
+                               ++in_stream_tag :
+                               ++out_stream_tag;
+               else
+                       azx_dev->stream_tag = i + 1;
        }
 
        return 0;
index 2bf0b568e3de40bfcaebd77914371f6800c125da..d426a0bd6a5f7e86adf482c83ad86e3203a8a3ad 100644 (file)
@@ -299,6 +299,9 @@ enum {
         AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
         AZX_DCAPS_SNOOP_TYPE(SCH))
 
+#define AZX_DCAPS_INTEL_SKYLAKE \
+       (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG)
+
 /* quirks for ATI SB / AMD Hudson */
 #define AZX_DCAPS_PRESET_ATI_SB \
        (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\
@@ -2027,7 +2030,7 @@ static const struct pci_device_id azx_ids[] = {
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
        /* Sunrise Point-LP */
        { PCI_DEVICE(0x8086, 0x9d70),
-         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0a0c),
          .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
index aa484fdf43389d476742aea16ee95a03318028ae..166e3e84b963875eec1d854e9ef8e2d434df0edb 100644 (file)
@@ -171,6 +171,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
 #define AZX_DCAPS_I915_POWERWELL (1 << 27)     /* HSW i915 powerwell support */
 #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28)  /* CORBRP clears itself after reset */
 #define AZX_DCAPS_NO_MSI64      (1 << 29)      /* Stick to 32-bit MSIs */
+#define AZX_DCAPS_SEPARATE_STREAM_TAG  (1 << 30) /* capture and playback use separate stream tag */
 
 enum {
        AZX_SNOOP_TYPE_NONE ,
index 5f13d2d180791fb4cd674ee52ffcdb84ffc9c2d3..b422e406a9cb3ba284772d4fbd6d42854de40b95 100644 (file)
@@ -3353,6 +3353,7 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = {
 { .id = 0x10de0067, .name = "MCP67 HDMI",      .patch = patch_nvhdmi_2ch },
 { .id = 0x10de0070, .name = "GPU 70 HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de0071, .name = "GPU 71 HDMI/DP",  .patch = patch_nvhdmi },
+{ .id = 0x10de0072, .name = "GPU 72 HDMI/DP",  .patch = patch_nvhdmi },
 { .id = 0x10de8001, .name = "MCP73 HDMI",      .patch = patch_nvhdmi_2ch },
 { .id = 0x11069f80, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
 { .id = 0x11069f81, .name = "VX900 HDMI/DP",   .patch = patch_via_hdmi },
@@ -3413,6 +3414,7 @@ MODULE_ALIAS("snd-hda-codec-id:10de0060");
 MODULE_ALIAS("snd-hda-codec-id:10de0067");
 MODULE_ALIAS("snd-hda-codec-id:10de0070");
 MODULE_ALIAS("snd-hda-codec-id:10de0071");
+MODULE_ALIAS("snd-hda-codec-id:10de0072");
 MODULE_ALIAS("snd-hda-codec-id:10de8001");
 MODULE_ALIAS("snd-hda-codec-id:11069f80");
 MODULE_ALIAS("snd-hda-codec-id:11069f81");
index 4f6413e01c133567a2c01ccee10543d6fc82a864..605d14003d257cb645b3519541d18a9b3045790a 100644 (file)
@@ -568,9 +568,9 @@ static void stac_store_hints(struct hda_codec *codec)
                        spec->gpio_mask;
        }
        if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
-               spec->gpio_mask &= spec->gpio_mask;
-       if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
                spec->gpio_dir &= spec->gpio_mask;
+       if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
+               spec->gpio_data &= spec->gpio_mask;
        if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
                spec->eapd_mask &= spec->gpio_mask;
        if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
index 7752860f7230e2821ac906715c06007543e84499..4c23381727a1ed1c53406b596ff04d9cd2e68577 100644 (file)
@@ -240,6 +240,8 @@ static int axi_i2s_probe(struct platform_device *pdev)
        if (ret)
                goto err_clk_disable;
 
+       return 0;
+
 err_clk_disable:
        clk_disable_unprepare(i2s->clk);
        return ret;
index fb3878312bf80b2b99c1b22344e498e7fb3a4434..1579e994acf881dfacb1aae23afb6095f32ff13f 100644 (file)
@@ -45,7 +45,7 @@ config SND_ATMEL_SOC_WM8904
 
 config SND_AT91_SOC_SAM9X5_WM8731
        tristate "SoC Audio support for WM8731-based at91sam9x5 board"
-       depends on ATMEL_SSC && SND_ATMEL_SOC && SOC_AT91SAM9X5
+       depends on ARCH_AT91 && ATMEL_SSC && SND_ATMEL_SOC
        select SND_ATMEL_SOC_SSC
        select SND_ATMEL_SOC_DMA
        select SND_SOC_WM8731
index 33fb3bb133df281429be1be2914006e575f011f1..b8e7bad05eb14a9ef7e6393646f776c910c0f898 100644 (file)
@@ -105,13 +105,11 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               slave_config->dst_addr = ssc->phybase + SSC_THR;
-               slave_config->dst_maxburst = 1;
-       } else {
-               slave_config->src_addr = ssc->phybase + SSC_RHR;
-               slave_config->src_maxburst = 1;
-       }
+       slave_config->dst_addr = ssc->phybase + SSC_THR;
+       slave_config->dst_maxburst = 1;
+
+       slave_config->src_addr = ssc->phybase + SSC_RHR;
+       slave_config->src_maxburst = 1;
 
        prtd->dma_intr_handler = atmel_pcm_dma_irq;
 
index 99ff35e2a25d012ba052b00fef7c2d1963a8e5c3..fb0b7e8b08ff4cd11a2656fe76fe10898aeded6b 100644 (file)
@@ -204,6 +204,13 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
        pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
                ssc_readl(ssc_p->ssc->regs, SR));
 
+       /* Enable PMC peripheral clock for this SSC */
+       pr_debug("atmel_ssc_dai: Starting clock\n");
+       clk_enable(ssc_p->ssc->clk);
+
+       /* Reset the SSC to keep it at a clean status */
+       ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
+
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                dir = 0;
                dir_mask = SSC_DIR_MASK_PLAYBACK;
@@ -250,11 +257,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
        dma_params = ssc_p->dma_params[dir];
 
        if (dma_params != NULL) {
-               ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_disable);
-               pr_debug("atmel_ssc_shutdown: %s disabled SSC_SR=0x%08x\n",
-                       (dir ? "receive" : "transmit"),
-                       ssc_readl(ssc_p->ssc->regs, SR));
-
                dma_params->ssc = NULL;
                dma_params->substream = NULL;
                ssc_p->dma_params[dir] = NULL;
@@ -266,10 +268,6 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
        ssc_p->dir_mask &= ~dir_mask;
        if (!ssc_p->dir_mask) {
                if (ssc_p->initialized) {
-                       /* Shutdown the SSC clock. */
-                       pr_debug("atmel_ssc_dai: Stopping clock\n");
-                       clk_disable(ssc_p->ssc->clk);
-
                        free_irq(ssc_p->ssc->irq, ssc_p);
                        ssc_p->initialized = 0;
                }
@@ -280,6 +278,10 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
                ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
        }
        spin_unlock_irq(&ssc_p->lock);
+
+       /* Shutdown the SSC clock. */
+       pr_debug("atmel_ssc_dai: Stopping clock\n");
+       clk_disable(ssc_p->ssc->clk);
 }
 
 
@@ -348,7 +350,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
        struct atmel_pcm_dma_params *dma_params;
        int dir, channels, bits;
        u32 tfmr, rfmr, tcmr, rcmr;
-       int start_event;
        int ret;
        int fslen, fslen_ext;
 
@@ -451,25 +452,10 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                break;
 
        case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM:
-               /*
-                * I2S format, CODEC supplies BCLK and LRC clocks.
-                *
-                * The SSC transmit clock is obtained from the BCLK signal on
-                * on the TK line, and the SSC receive clock is
-                * generated from the transmit clock.
-                *
-                *  For single channel data, one sample is transferred
-                * on the falling edge of the LRC clock.
-                * For two channel data, one sample is
-                * transferred on both edges of the LRC clock.
-                */
-               start_event = ((channels == 1)
-                               ? SSC_START_FALLING_RF
-                               : SSC_START_EDGE_RF);
-
+               /* I2S format, CODEC supplies BCLK and LRC clocks. */
                rcmr =    SSC_BF(RCMR_PERIOD, 0)
                        | SSC_BF(RCMR_STTDLY, START_DELAY)
-                       | SSC_BF(RCMR_START, start_event)
+                       | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
                        | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
                        | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
                        | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
@@ -478,14 +464,14 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                rfmr =    SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
                        | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE)
                        | SSC_BF(RFMR_FSLEN, 0)
-                       | SSC_BF(RFMR_DATNB, 0)
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
                        | SSC_BIT(RFMR_MSBF)
                        | SSC_BF(RFMR_LOOP, 0)
                        | SSC_BF(RFMR_DATLEN, (bits - 1));
 
                tcmr =    SSC_BF(TCMR_PERIOD, 0)
                        | SSC_BF(TCMR_STTDLY, START_DELAY)
-                       | SSC_BF(TCMR_START, start_event)
+                       | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
                        | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
                        | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
                        | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
@@ -495,7 +481,55 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        | SSC_BF(TFMR_FSDEN, 0)
                        | SSC_BF(TFMR_FSOS, SSC_FSOS_NONE)
                        | SSC_BF(TFMR_FSLEN, 0)
-                       | SSC_BF(TFMR_DATNB, 0)
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
+                       | SSC_BIT(TFMR_MSBF)
+                       | SSC_BF(TFMR_DATDEF, 0)
+                       | SSC_BF(TFMR_DATLEN, (bits - 1));
+               break;
+
+       case SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFS:
+               /* I2S format, CODEC supplies BCLK, SSC supplies LRCLK. */
+               if (bits > 16 && !ssc->pdata->has_fslen_ext) {
+                       dev_err(dai->dev,
+                               "sample size %d is too large for SSC device\n",
+                               bits);
+                       return -EINVAL;
+               }
+
+               fslen_ext = (bits - 1) / 16;
+               fslen = (bits - 1) % 16;
+
+               rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
+                       | SSC_BF(RCMR_STTDLY, START_DELAY)
+                       | SSC_BF(RCMR_START, SSC_START_FALLING_RF)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_PIN : SSC_CKS_CLOCK);
+
+               rfmr =    SSC_BF(RFMR_FSLEN_EXT, fslen_ext)
+                       | SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE)
+                       | SSC_BF(RFMR_FSOS, SSC_FSOS_NEGATIVE)
+                       | SSC_BF(RFMR_FSLEN, fslen)
+                       | SSC_BF(RFMR_DATNB, (channels - 1))
+                       | SSC_BIT(RFMR_MSBF)
+                       | SSC_BF(RFMR_LOOP, 0)
+                       | SSC_BF(RFMR_DATLEN, (bits - 1));
+
+               tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
+                       | SSC_BF(TCMR_STTDLY, START_DELAY)
+                       | SSC_BF(TCMR_START, SSC_START_FALLING_RF)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
+                       | SSC_BF(TCMR_CKO, SSC_CKO_NONE)
+                       | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ?
+                                          SSC_CKS_CLOCK : SSC_CKS_PIN);
+
+               tfmr =    SSC_BF(TFMR_FSLEN_EXT, fslen_ext)
+                       | SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_NEGATIVE)
+                       | SSC_BF(TFMR_FSDEN, 0)
+                       | SSC_BF(TFMR_FSOS, SSC_FSOS_NEGATIVE)
+                       | SSC_BF(TFMR_FSLEN, fslen)
+                       | SSC_BF(TFMR_DATNB, (channels - 1))
                        | SSC_BIT(TFMR_MSBF)
                        | SSC_BF(TFMR_DATDEF, 0)
                        | SSC_BF(TFMR_DATLEN, (bits - 1));
@@ -512,7 +546,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                rcmr =    SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
                        | SSC_BF(RCMR_STTDLY, 1)
                        | SSC_BF(RCMR_START, SSC_START_RISING_RF)
-                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_FALLING)
                        | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
                        | SSC_BF(RCMR_CKS, SSC_CKS_DIV);
 
@@ -527,7 +561,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                tcmr =    SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
                        | SSC_BF(TCMR_STTDLY, 1)
                        | SSC_BF(TCMR_START, SSC_START_RISING_RF)
-                       | SSC_BF(TCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
                        | SSC_BF(TCMR_CKO, SSC_CKO_CONTINUOUS)
                        | SSC_BF(TCMR_CKS, SSC_CKS_DIV);
 
@@ -545,10 +579,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                /*
                 * DSP/PCM Mode A format, CODEC supplies BCLK and LRC clocks.
                 *
-                * The SSC transmit clock is obtained from the BCLK signal on
-                * on the TK line, and the SSC receive clock is
-                * generated from the transmit clock.
-                *
                 * Data is transferred on first BCLK after LRC pulse rising
                 * edge.If stereo, the right channel data is contiguous with
                 * the left channel data.
@@ -556,7 +586,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                rcmr =    SSC_BF(RCMR_PERIOD, 0)
                        | SSC_BF(RCMR_STTDLY, START_DELAY)
                        | SSC_BF(RCMR_START, SSC_START_RISING_RF)
-                       | SSC_BF(RCMR_CKI, SSC_CKI_RISING)
+                       | SSC_BF(RCMR_CKI, SSC_CKI_FALLING)
                        | SSC_BF(RCMR_CKO, SSC_CKO_NONE)
                        | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ?
                                           SSC_CKS_PIN : SSC_CKS_CLOCK);
@@ -597,23 +627,17 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
                        rcmr, rfmr, tcmr, tfmr);
 
        if (!ssc_p->initialized) {
-
-               /* Enable PMC peripheral clock for this SSC */
-               pr_debug("atmel_ssc_dai: Starting clock\n");
-               clk_enable(ssc_p->ssc->clk);
-
-               /* Reset the SSC and its PDC registers */
-               ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
-
-               ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
-
-               ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
-               ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+               if (!ssc_p->ssc->pdata->use_dma) {
+                       ssc_writel(ssc_p->ssc->regs, PDC_RPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_RCR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_RNPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_RNCR, 0);
+
+                       ssc_writel(ssc_p->ssc->regs, PDC_TPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_TCR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_TNPR, 0);
+                       ssc_writel(ssc_p->ssc->regs, PDC_TNCR, 0);
+               }
 
                ret = request_irq(ssc_p->ssc->irq, atmel_ssc_interrupt, 0,
                                ssc_p->name, ssc_p);
index 66b66d0e751474358f6eff03d0a2ae897dddc1ad..f5ad214663f98b4dbbdc3c2a4180d6142d09688c 100644 (file)
@@ -47,7 +47,6 @@
 #include <sound/soc.h>
 
 #include <asm/mach-types.h>
-#include <mach/hardware.h>
 
 #include "../codecs/wm8731.h"
 #include "atmel-pcm.h"
 
 static struct clk *mclk;
 
-static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
-       struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       return 0;
-}
-
-static struct snd_soc_ops at91sam9g20ek_ops = {
-       .hw_params = at91sam9g20ek_hw_params,
-};
-
 static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card,
                                        struct snd_soc_dapm_context *dapm,
                                        enum snd_soc_bias_level level)
@@ -173,7 +145,8 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
        .init = at91sam9g20ek_wm8731_init,
        .platform_name = "at91rm9200_ssc.0",
        .codec_name = "wm8731.0-001b",
-       .ops = &at91sam9g20ek_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
index a747ac0b399fae766ddbe85695d2db9140f42884..c75995f2779cf57604de8d1ef37c4aa42c31d2a5 100644 (file)
@@ -91,27 +91,12 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int ret;
 
        /* WM8731 has its own 12MHz crystal */
        snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
                                12000000, SND_SOC_CLOCK_IN);
 
-       /* codec is bitclock and lrclk master */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               goto out;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               goto out;
-
-       ret = 0;
-out:
-       return ret;
+       return 0;
 }
 
 static struct snd_soc_ops db1200_i2s_wm8731_ops = {
@@ -125,6 +110,8 @@ static struct snd_soc_dai_link db1200_i2s_dai = {
        .cpu_dai_name   = "au1xpsc_i2s.1",
        .platform_name  = "au1xpsc-pcm.1",
        .codec_name     = "wm8731.0-001b",
+       .dai_fmt        = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBM_CFM,
        .ops            = &db1200_i2s_wm8731_ops,
 };
 
index b06b8d8128c661d3c8645672224147164122f36e..dd94fea72d5d240cf8d6c37f344dbabe10b55e0f 100644 (file)
@@ -315,11 +315,6 @@ static struct snd_pcm_ops au1xpsc_pcm_ops = {
        .pointer        = au1xpsc_pcm_pointer,
 };
 
-static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
@@ -335,7 +330,6 @@ static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver au1xpsc_soc_platform = {
        .ops            = &au1xpsc_pcm_ops,
        .pcm_new        = au1xpsc_pcm_new,
-       .pcm_free       = au1xpsc_pcm_free_dma_buffers,
 };
 
 static int au1xpsc_pcm_drvprobe(struct platform_device *pdev)
index 6ffaaff469c7d13ecc623833a14c18838486b3f0..24cc7f40d87a61ba16850a57566a395455f302f2 100644 (file)
@@ -287,11 +287,6 @@ static struct snd_pcm_ops alchemy_pcm_ops = {
        .pointer                = alchemy_pcm_pointer,
 };
 
-static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -305,7 +300,6 @@ static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
        .ops            = &alchemy_pcm_ops,
        .pcm_new        = alchemy_pcm_new,
-       .pcm_free       = alchemy_pcm_free_dma_buffers,
 };
 
 static int alchemy_pcm_drvprobe(struct platform_device *pdev)
index a2bf27f4baab6339f03fc2b040fe81b80bdb9714..a0f265327fdf8949e15b17187732d1da8702a7a9 100644 (file)
@@ -386,7 +386,7 @@ static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
 static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
                              struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        /*
         * In order to avoid current on the load, mute power-on and power-off
@@ -403,7 +403,7 @@ static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
 static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int dac = 0;
        int data;
 
index 8349f982a586841a3ac9e7b0526af05699c7deaf..3190eed43c38d8145536d1804f7686b108f97641 100644 (file)
@@ -525,7 +525,7 @@ config SND_SOC_RT5677
 
 config SND_SOC_RT5677_SPI
        tristate
-       default SND_SOC_RT5677
+       default SND_SOC_RT5677 && SPI
 
 #Freescale sgtl5000 codec
 config SND_SOC_SGTL5000
@@ -580,7 +580,9 @@ config SND_SOC_SSM4567
        depends on I2C
 
 config SND_SOC_STA32X
-       tristate
+       tristate "STA326, STA328 and STA329 speaker amplifier"
+       depends on I2C
+       select REGMAP_I2C
 
 config SND_SOC_STA350
        tristate "STA350 speaker amplifier"
index 387530b0b0fd91058bbf08e663207867c693d9b5..17c9535956609c0df1a04f631da8f79a25a1e044 100644 (file)
@@ -333,8 +333,8 @@ static int ad193x_codec_probe(struct snd_soc_codec *codec)
        regmap_write(ad193x->regmap, AD193X_DAC_CHNL_MUTE, 0x0);
        /* de-emphasis: 48kHz, powedown dac */
        regmap_write(ad193x->regmap, AD193X_DAC_CTRL2, 0x1A);
-       /* powerdown dac, dac in tdm mode */
-       regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x41);
+       /* dac in tdm mode */
+       regmap_write(ad193x->regmap, AD193X_DAC_CTRL0, 0x40);
        /* high-pass filter enable */
        regmap_write(ad193x->regmap, AD193X_ADC_CTRL0, 0x3);
        /* sata delay=1, adc aux mode */
index 686cacb0e835aad904f79778ea83f65fabfab16b..632e89f793a78d2691dfb2e33b3516f0f483aeee 100644 (file)
@@ -163,7 +163,7 @@ static const struct snd_kcontrol_new ak4671_snd_controls[] = {
 static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index bdf8c5ac8ca460b8e07310674f90109cc6e6965a..0e357996864bd141f4d57283c03fba3b0e11b8d7 100644 (file)
@@ -55,18 +55,20 @@ static inline int alc5623_reset(struct snd_soc_codec *codec)
 static int amp_mixer_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        /* to power-on/off class-d amp generators/speaker */
        /* need to write to 'index-46h' register :        */
        /* so write index num (here 0x46) to reg 0x6a     */
        /* and then 0xffff/0 to reg 0x6c                  */
-       snd_soc_write(w->codec, ALC5623_HID_CTRL_INDEX, 0x46);
+       snd_soc_write(codec, ALC5623_HID_CTRL_INDEX, 0x46);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
+               snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0xFFFF);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               snd_soc_write(w->codec, ALC5623_HID_CTRL_DATA, 0);
+               snd_soc_write(codec, ALC5623_HID_CTRL_DATA, 0);
                break;
        }
 
index d1fdbc266631b36aebf4c249bf2bea9e94c8064c..db3283abbe180788f10b3d7e5b70df996087867b 100644 (file)
@@ -116,18 +116,20 @@ static inline int alc5632_reset(struct regmap *map)
 static int amp_mixer_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        /* to power-on/off class-d amp generators/speaker */
        /* need to write to 'index-46h' register :        */
        /* so write index num (here 0x46) to reg 0x6a     */
        /* and then 0xffff/0 to reg 0x6c                  */
-       snd_soc_write(w->codec, ALC5632_HID_CTRL_INDEX, 0x46);
+       snd_soc_write(codec, ALC5632_HID_CTRL_INDEX, 0x46);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
+               snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0xFFFF);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               snd_soc_write(w->codec, ALC5632_HID_CTRL_DATA, 0);
+               snd_soc_write(codec, ALC5632_HID_CTRL_DATA, 0);
                break;
        }
 
@@ -1066,7 +1068,7 @@ static int alc5632_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
+static const struct snd_soc_codec_driver soc_codec_device_alc5632 = {
        .probe = alc5632_probe,
        .resume = alc5632_resume,
        .set_bias_level = alc5632_set_bias_level,
@@ -1080,7 +1082,7 @@ static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
        .num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
 };
 
-static struct regmap_config alc5632_regmap = {
+static const struct regmap_config alc5632_regmap = {
        .reg_bits = 8,
        .val_bits = 16,
 
index 9550d7433ad0e391708a85c88a0adfc6fb2d1831..29202610dd0dd90d72329265633844a3d833d640 100644 (file)
@@ -84,7 +84,7 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        bool manual_ena = false;
@@ -692,7 +692,8 @@ static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena)
 int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                  int event)
 {
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        unsigned int reg;
 
        if (w->shift % 2)
@@ -705,25 +706,25 @@ int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol,
                priv->in_pending++;
                break;
        case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(w->codec, reg, ARIZONA_IN1L_MUTE, 0);
+               snd_soc_update_bits(codec, reg, ARIZONA_IN1L_MUTE, 0);
 
                /* If this is the last input pending then allow VU */
                priv->in_pending--;
                if (priv->in_pending == 0) {
                        msleep(1);
-                       arizona_in_set_vu(w->codec, 1);
+                       arizona_in_set_vu(codec, 1);
                }
                break;
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, reg,
+               snd_soc_update_bits(codec, reg,
                                    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU,
                                    ARIZONA_IN1L_MUTE | ARIZONA_IN_VU);
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* Disable volume updates if no inputs are enabled */
-               reg = snd_soc_read(w->codec, ARIZONA_INPUT_ENABLES);
+               reg = snd_soc_read(codec, ARIZONA_INPUT_ENABLES);
                if (reg == 0)
-                       arizona_in_set_vu(w->codec, 0);
+                       arizona_in_set_vu(codec, 0);
        }
 
        return 0;
@@ -734,7 +735,25 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+
        switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       priv->out_up_pending++;
+                       priv->out_up_delay += 17;
+                       break;
+               default:
+                       break;
+               }
+               break;
        case SND_SOC_DAPM_POST_PMU:
                switch (w->shift) {
                case ARIZONA_OUT1L_ENA_SHIFT:
@@ -743,13 +762,50 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
                case ARIZONA_OUT2R_ENA_SHIFT:
                case ARIZONA_OUT3L_ENA_SHIFT:
                case ARIZONA_OUT3R_ENA_SHIFT:
-                       msleep(17);
+                       priv->out_up_pending--;
+                       if (!priv->out_up_pending) {
+                               msleep(priv->out_up_delay);
+                               priv->out_up_delay = 0;
+                       }
                        break;
 
                default:
                        break;
                }
                break;
+       case SND_SOC_DAPM_PRE_PMD:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       priv->out_down_pending++;
+                       priv->out_down_delay++;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               switch (w->shift) {
+               case ARIZONA_OUT1L_ENA_SHIFT:
+               case ARIZONA_OUT1R_ENA_SHIFT:
+               case ARIZONA_OUT2L_ENA_SHIFT:
+               case ARIZONA_OUT2R_ENA_SHIFT:
+               case ARIZONA_OUT3L_ENA_SHIFT:
+               case ARIZONA_OUT3R_ENA_SHIFT:
+                       priv->out_down_pending--;
+                       if (!priv->out_down_pending) {
+                               msleep(priv->out_down_delay);
+                               priv->out_down_delay = 0;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
        }
 
        return 0;
@@ -760,7 +816,8 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
-       struct arizona_priv *priv = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
        unsigned int mask = 1 << w->shift;
        unsigned int val;
@@ -772,6 +829,9 @@ int arizona_hp_ev(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_PRE_PMD:
                val = 0;
                break;
+       case SND_SOC_DAPM_PRE_PMU:
+       case SND_SOC_DAPM_POST_PMD:
+               return arizona_out_ev(w, kcontrol, event);
        default:
                return -EINVAL;
        }
index 942cfb197b6daafa74de6fa64975bed128600c0a..11ff899b02724fae943d2bc1ce98550b26a62985 100644 (file)
@@ -77,6 +77,11 @@ struct arizona_priv {
        int num_inputs;
        unsigned int in_pending;
 
+       unsigned int out_up_pending;
+       unsigned int out_up_delay;
+       unsigned int out_down_pending;
+       unsigned int out_down_delay;
+
        unsigned int spk_ena:2;
        unsigned int spk_ena_pending:1;
 };
index 5075bf0a7276b02417d9ae7346f887075c8b653d..e7238b8904bceec6f0903bd2974d00b4c6c262aa 100644 (file)
@@ -86,5 +86,5 @@ static struct platform_driver bt_sco_driver = {
 module_platform_driver(bt_sco_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("ASoC generic bluethooth sco link driver");
+MODULE_DESCRIPTION("ASoC generic bluetooth sco link driver");
 MODULE_LICENSE("GPL");
index ec55c590afd00b90e9bee89bcfa1fb96f765ec7d..f2b8aad21274aec951fdabc20887b970ef2e1aaa 100644 (file)
@@ -264,7 +264,7 @@ static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec,
                        CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val);
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
        .set_sysclk = cs35l32_codec_set_sysclk,
 
        .dapm_widgets = cs35l32_dapm_widgets,
@@ -288,7 +288,7 @@ static const struct reg_default cs35l32_monitor_patch[] = {
        { 0x00, 0x00 },
 };
 
-static struct regmap_config cs35l32_regmap = {
+static const struct regmap_config cs35l32_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 35fbef743fbe21883db9d2e645ea018a5c8c9080..1589e7a881d817ab403f7a7a149cecfda4797a92 100644 (file)
@@ -1103,7 +1103,7 @@ static int cs42l52_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
        .probe = cs42l52_probe,
        .remove = cs42l52_remove,
        .set_bias_level = cs42l52_set_bias_level,
@@ -1130,7 +1130,7 @@ static const struct reg_default cs42l52_threshold_patch[] = {
 
 };
 
-static struct regmap_config cs42l52_regmap = {
+static const struct regmap_config cs42l52_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 2ddc7ac10ad7a311ccda24f7add9613891b068c9..cbc654fe48c76d7fa1c231a874f0e60588ecfc2f 100644 (file)
@@ -1164,7 +1164,7 @@ static int cs42l56_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
        .probe = cs42l56_probe,
        .remove = cs42l56_remove,
        .set_bias_level = cs42l56_set_bias_level,
@@ -1179,7 +1179,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = {
        .num_controls = ARRAY_SIZE(cs42l56_snd_controls),
 };
 
-static struct regmap_config cs42l56_regmap = {
+static const struct regmap_config cs42l56_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 7c55537c69cf0804bcb03a3afa573660fbaee304..8ecedba79606c561c0a385e04091513074662210 100644 (file)
@@ -1347,7 +1347,7 @@ static int cs42l73_probe(struct snd_soc_codec *codec)
        return 0;
 }
 
-static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
+static const struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
        .probe = cs42l73_probe,
        .set_bias_level = cs42l73_set_bias_level,
        .suspend_bias_off = true,
@@ -1361,7 +1361,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = {
        .num_controls = ARRAY_SIZE(cs42l73_snd_controls),
 };
 
-static struct regmap_config cs42l73_regmap = {
+static const struct regmap_config cs42l73_regmap = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 61b2f9a2eef1b87d8daea13ab83d90779a883fc5..ffe96175a8a5ac62ee4721c1f17a54c305d447c7 100644 (file)
@@ -609,7 +609,7 @@ static const struct snd_kcontrol_new da732x_snd_controls[] = {
 static int da732x_adc_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -663,7 +663,7 @@ static int da732x_adc_event(struct snd_soc_dapm_widget *w,
 static int da732x_out_pga_event(struct snd_soc_dapm_widget *w,
                                struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index c1e441c2c8af5326b3125188fd4ecf19f0b740e1..2ffb9a0570dc8db3625cc8224f034995ea88d7dd 100644 (file)
@@ -328,16 +328,16 @@ static int mc13783_set_tdm_slot_dac(struct snd_soc_dai *dai,
        }
 
        switch (rx_mask) {
-       case 0xfffffffc:
+       case 0x03:
                val |= SSI_NETWORK_DAC_RXSLOT_0_1;
                break;
-       case 0xfffffff3:
+       case 0x0c:
                val |= SSI_NETWORK_DAC_RXSLOT_2_3;
                break;
-       case 0xffffffcf:
+       case 0x30:
                val |= SSI_NETWORK_DAC_RXSLOT_4_5;
                break;
-       case 0xffffff3f:
+       case 0xc0:
                val |= SSI_NETWORK_DAC_RXSLOT_6_7;
                break;
        default:
@@ -360,7 +360,7 @@ static int mc13783_set_tdm_slot_codec(struct snd_soc_dai *dai,
        if (slots != 4)
                return -EINVAL;
 
-       if (tx_mask != 0xfffffffc)
+       if (tx_mask != 0x3)
                return -EINVAL;
 
        val |= (0x00 << 2);     /* primary timeslot RX/TX(?) is 0 */
index 7e73fa4b3183851f55d5660ce3e7ee4d95c549d5..8fb445f33f6f2a23c0d30f15c37ef590609c91cc 100644 (file)
@@ -32,7 +32,7 @@ static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value_cansleep(setup->pdda_pin,
@@ -45,7 +45,7 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct pcm3008_setup_data *setup = codec->dev->platform_data;
 
        gpio_set_value_cansleep(setup->pdad_pin,
index d0547fa275fc307d8ff40b7d6dcf2585061dc317..dcdfac0ffeb15c2fbe6c91883af6bf7bfb156dc6 100644 (file)
@@ -46,6 +46,8 @@ static int pcm512x_i2c_remove(struct i2c_client *i2c)
 static const struct i2c_device_id pcm512x_i2c_id[] = {
        { "pcm5121", },
        { "pcm5122", },
+       { "pcm5141", },
+       { "pcm5142", },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
@@ -53,6 +55,8 @@ MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id);
 static const struct of_device_id pcm512x_of_match[] = {
        { .compatible = "ti,pcm5121", },
        { .compatible = "ti,pcm5122", },
+       { .compatible = "ti,pcm5141", },
+       { .compatible = "ti,pcm5142", },
        { }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
index f297058c0038d1a7c2a7bd999fe664cbf4282433..7b64a9cef70481bab82875f4589f68e4fb63508f 100644 (file)
@@ -43,6 +43,8 @@ static int pcm512x_spi_remove(struct spi_device *spi)
 static const struct spi_device_id pcm512x_spi_id[] = {
        { "pcm5121", },
        { "pcm5122", },
+       { "pcm5141", },
+       { "pcm5142", },
        { },
 };
 MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
@@ -50,6 +52,8 @@ MODULE_DEVICE_TABLE(spi, pcm512x_spi_id);
 static const struct of_device_id pcm512x_of_match[] = {
        { .compatible = "ti,pcm5121", },
        { .compatible = "ti,pcm5122", },
+       { .compatible = "ti,pcm5141", },
+       { .compatible = "ti,pcm5142", },
        { }
 };
 MODULE_DEVICE_TABLE(of, pcm512x_of_match);
index e5f2fb884bf34688bc42add58e0b93cc5b863a9b..9974f201a08f44ee25b109c7ff78e13440146c4b 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gcd.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
+#include <sound/pcm_params.h>
 #include <sound/tlv.h>
 
 #include "pcm512x.h"
 
+#define DIV_ROUND_DOWN_ULL(ll, d) \
+       ({ unsigned long long _tmp = (ll); do_div(_tmp, d); _tmp; })
+#define DIV_ROUND_CLOSEST_ULL(ll, d) \
+       ({ unsigned long long _tmp = (ll)+(d)/2; do_div(_tmp, d); _tmp; })
+
 #define PCM512x_NUM_SUPPLIES 3
 static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
        "AVDD",
@@ -39,6 +46,14 @@ struct pcm512x_priv {
        struct clk *sclk;
        struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
        struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
+       int fmt;
+       int pll_in;
+       int pll_out;
+       int pll_r;
+       int pll_j;
+       int pll_d;
+       int pll_p;
+       unsigned long real_pll;
 };
 
 /*
@@ -69,6 +84,7 @@ static const struct reg_default pcm512x_reg_defaults[] = {
        { PCM512x_MUTE,              0x00 },
        { PCM512x_DSP,               0x00 },
        { PCM512x_PLL_REF,           0x00 },
+       { PCM512x_DAC_REF,           0x00 },
        { PCM512x_DAC_ROUTING,       0x11 },
        { PCM512x_DSP_PROGRAM,       0x01 },
        { PCM512x_CLKDET,            0x00 },
@@ -87,6 +103,25 @@ static const struct reg_default pcm512x_reg_defaults[] = {
        { PCM512x_ANALOG_GAIN_BOOST, 0x00 },
        { PCM512x_VCOM_CTRL_1,       0x00 },
        { PCM512x_VCOM_CTRL_2,       0x01 },
+       { PCM512x_BCLK_LRCLK_CFG,    0x00 },
+       { PCM512x_MASTER_MODE,       0x7c },
+       { PCM512x_GPIO_DACIN,        0x00 },
+       { PCM512x_GPIO_PLLIN,        0x00 },
+       { PCM512x_SYNCHRONIZE,       0x10 },
+       { PCM512x_PLL_COEFF_0,       0x00 },
+       { PCM512x_PLL_COEFF_1,       0x00 },
+       { PCM512x_PLL_COEFF_2,       0x00 },
+       { PCM512x_PLL_COEFF_3,       0x00 },
+       { PCM512x_PLL_COEFF_4,       0x00 },
+       { PCM512x_DSP_CLKDIV,        0x00 },
+       { PCM512x_DAC_CLKDIV,        0x00 },
+       { PCM512x_NCP_CLKDIV,        0x00 },
+       { PCM512x_OSR_CLKDIV,        0x00 },
+       { PCM512x_MASTER_CLKDIV_1,   0x00 },
+       { PCM512x_MASTER_CLKDIV_2,   0x00 },
+       { PCM512x_FS_SPEED_MODE,     0x00 },
+       { PCM512x_IDAC_1,            0x01 },
+       { PCM512x_IDAC_2,            0x00 },
 };
 
 static bool pcm512x_readable(struct device *dev, unsigned int reg)
@@ -103,6 +138,10 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
        case PCM512x_DSP_GPIO_INPUT:
        case PCM512x_MASTER_MODE:
        case PCM512x_PLL_REF:
+       case PCM512x_DAC_REF:
+       case PCM512x_GPIO_DACIN:
+       case PCM512x_GPIO_PLLIN:
+       case PCM512x_SYNCHRONIZE:
        case PCM512x_PLL_COEFF_0:
        case PCM512x_PLL_COEFF_1:
        case PCM512x_PLL_COEFF_2:
@@ -143,6 +182,7 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
        case PCM512x_RATE_DET_2:
        case PCM512x_RATE_DET_3:
        case PCM512x_RATE_DET_4:
+       case PCM512x_CLOCK_STATUS:
        case PCM512x_ANALOG_MUTE_DET:
        case PCM512x_GPIN:
        case PCM512x_DIGITAL_MUTE_DET:
@@ -154,6 +194,8 @@ static bool pcm512x_readable(struct device *dev, unsigned int reg)
        case PCM512x_VCOM_CTRL_1:
        case PCM512x_VCOM_CTRL_2:
        case PCM512x_CRAM_CTRL:
+       case PCM512x_FLEX_A:
+       case PCM512x_FLEX_B:
                return true;
        default:
                /* There are 256 raw register addresses */
@@ -170,6 +212,7 @@ static bool pcm512x_volatile(struct device *dev, unsigned int reg)
        case PCM512x_RATE_DET_2:
        case PCM512x_RATE_DET_3:
        case PCM512x_RATE_DET_4:
+       case PCM512x_CLOCK_STATUS:
        case PCM512x_ANALOG_MUTE_DET:
        case PCM512x_GPIN:
        case PCM512x_DIGITAL_MUTE_DET:
@@ -188,8 +231,8 @@ static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0);
 static const char * const pcm512x_dsp_program_texts[] = {
        "FIR interpolation with de-emphasis",
        "Low latency IIR with de-emphasis",
-       "Fixed process flow",
        "High attenuation with de-emphasis",
+       "Fixed process flow",
        "Ringing-less low latency FIR",
 };
 
@@ -277,7 +320,7 @@ SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r),
 SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3,
           PCM512x_ACTL_SHIFT, 1, 0),
 SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT,
-          PCM512x_AMLR_SHIFT, 1, 0),
+          PCM512x_AMRE_SHIFT, 1, 0),
 
 SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf),
 SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds),
@@ -303,6 +346,136 @@ static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = {
        { "OUTR", NULL, "DACR" },
 };
 
+static const u32 pcm512x_dai_rates[] = {
+       8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
+       88200, 96000, 176400, 192000, 384000,
+};
+
+static const struct snd_pcm_hw_constraint_list constraints_slave = {
+       .count = ARRAY_SIZE(pcm512x_dai_rates),
+       .list  = pcm512x_dai_rates,
+};
+
+static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
+                               struct snd_pcm_hw_rule *rule)
+{
+       struct snd_interval ranges[2];
+       int frame_size;
+
+       frame_size = snd_soc_params_to_frame_size(params);
+       if (frame_size < 0)
+               return frame_size;
+
+       switch (frame_size) {
+       case 32:
+               /* No hole when the frame size is 32. */
+               return 0;
+       case 48:
+       case 64:
+               /* There is only one hole in the range of supported
+                * rates, but it moves with the frame size.
+                */
+               memset(ranges, 0, sizeof(ranges));
+               ranges[0].min = 8000;
+               ranges[0].max = 25000000 / frame_size / 2;
+               ranges[1].min = DIV_ROUND_UP(16000000, frame_size);
+               ranges[1].max = 384000;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return snd_interval_ranges(hw_param_interval(params, rule->var),
+                                  ARRAY_SIZE(ranges), ranges, 0);
+}
+
+static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
+                                     struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       struct device *dev = dai->dev;
+       struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
+       struct snd_ratnum *rats_no_pll;
+
+       if (IS_ERR(pcm512x->sclk)) {
+               dev_err(dev, "Need SCLK for master mode: %ld\n",
+                       PTR_ERR(pcm512x->sclk));
+               return PTR_ERR(pcm512x->sclk);
+       }
+
+       if (pcm512x->pll_out)
+               return snd_pcm_hw_rule_add(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_RATE,
+                                          pcm512x_hw_rule_rate,
+                                          NULL,
+                                          SNDRV_PCM_HW_PARAM_FRAME_BITS,
+                                          SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+
+       constraints_no_pll = devm_kzalloc(dev, sizeof(*constraints_no_pll),
+                                         GFP_KERNEL);
+       if (!constraints_no_pll)
+               return -ENOMEM;
+       constraints_no_pll->nrats = 1;
+       rats_no_pll = devm_kzalloc(dev, sizeof(*rats_no_pll), GFP_KERNEL);
+       if (!rats_no_pll)
+               return -ENOMEM;
+       constraints_no_pll->rats = rats_no_pll;
+       rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
+       rats_no_pll->den_min = 1;
+       rats_no_pll->den_max = 128;
+       rats_no_pll->den_step = 1;
+
+       return snd_pcm_hw_constraint_ratnums(substream->runtime, 0,
+                                            SNDRV_PCM_HW_PARAM_RATE,
+                                            constraints_no_pll);
+}
+
+static int pcm512x_dai_startup_slave(struct snd_pcm_substream *substream,
+                                    struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       struct device *dev = dai->dev;
+       struct regmap *regmap = pcm512x->regmap;
+
+       if (IS_ERR(pcm512x->sclk)) {
+               dev_info(dev, "No SCLK, using BCLK: %ld\n",
+                        PTR_ERR(pcm512x->sclk));
+
+               /* Disable reporting of missing SCLK as an error */
+               regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
+                                  PCM512x_IDCH, PCM512x_IDCH);
+
+               /* Switch PLL input to BCLK */
+               regmap_update_bits(regmap, PCM512x_PLL_REF,
+                                  PCM512x_SREF, PCM512x_SREF_BCK);
+       }
+
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_RATE,
+                                         &constraints_slave);
+}
+
+static int pcm512x_dai_startup(struct snd_pcm_substream *substream,
+                              struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBM_CFM:
+       case SND_SOC_DAIFMT_CBM_CFS:
+               return pcm512x_dai_startup_master(substream, dai);
+
+       case SND_SOC_DAIFMT_CBS_CFS:
+               return pcm512x_dai_startup_slave(substream, dai);
+
+       default:
+               return -EINVAL;
+       }
+}
+
 static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
                                  enum snd_soc_bias_level level)
 {
@@ -340,17 +513,717 @@ static int pcm512x_set_bias_level(struct snd_soc_codec *codec,
        return 0;
 }
 
+static unsigned long pcm512x_find_sck(struct snd_soc_dai *dai,
+                                     unsigned long bclk_rate)
+{
+       struct device *dev = dai->dev;
+       unsigned long sck_rate;
+       int pow2;
+
+       /* 64 MHz <= pll_rate <= 100 MHz, VREF mode */
+       /* 16 MHz <= sck_rate <=  25 MHz, VREF mode */
+
+       /* select sck_rate as a multiple of bclk_rate but still with
+        * as many factors of 2 as possible, as that makes it easier
+        * to find a fast DAC rate
+        */
+       pow2 = 1 << fls((25000000 - 16000000) / bclk_rate);
+       for (; pow2; pow2 >>= 1) {
+               sck_rate = rounddown(25000000, bclk_rate * pow2);
+               if (sck_rate >= 16000000)
+                       break;
+       }
+       if (!pow2) {
+               dev_err(dev, "Impossible to generate a suitable SCK\n");
+               return 0;
+       }
+
+       dev_dbg(dev, "sck_rate %lu\n", sck_rate);
+       return sck_rate;
+}
+
+/* pll_rate = pllin_rate * R * J.D / P
+ * 1 <= R <= 16
+ * 1 <= J <= 63
+ * 0 <= D <= 9999
+ * 1 <= P <= 15
+ * 64 MHz <= pll_rate <= 100 MHz
+ * if D == 0
+ *     1 MHz <= pllin_rate / P <= 20 MHz
+ * else if D > 0
+ *     6.667 MHz <= pllin_rate / P <= 20 MHz
+ *     4 <= J <= 11
+ *     R = 1
+ */
+static int pcm512x_find_pll_coeff(struct snd_soc_dai *dai,
+                                 unsigned long pllin_rate,
+                                 unsigned long pll_rate)
+{
+       struct device *dev = dai->dev;
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       unsigned long common;
+       int R, J, D, P;
+       unsigned long K; /* 10000 * J.D */
+       unsigned long num;
+       unsigned long den;
+
+       common = gcd(pll_rate, pllin_rate);
+       dev_dbg(dev, "pll %lu pllin %lu common %lu\n",
+               pll_rate, pllin_rate, common);
+       num = pll_rate / common;
+       den = pllin_rate / common;
+
+       /* pllin_rate / P (or here, den) cannot be greater than 20 MHz */
+       if (pllin_rate / den > 20000000 && num < 8) {
+               num *= 20000000 / (pllin_rate / den);
+               den *= 20000000 / (pllin_rate / den);
+       }
+       dev_dbg(dev, "num / den = %lu / %lu\n", num, den);
+
+       P = den;
+       if (den <= 15 && num <= 16 * 63
+           && 1000000 <= pllin_rate / P && pllin_rate / P <= 20000000) {
+               /* Try the case with D = 0 */
+               D = 0;
+               /* factor 'num' into J and R, such that R <= 16 and J <= 63 */
+               for (R = 16; R; R--) {
+                       if (num % R)
+                               continue;
+                       J = num / R;
+                       if (J == 0 || J > 63)
+                               continue;
+
+                       dev_dbg(dev, "R * J / P = %d * %d / %d\n", R, J, P);
+                       pcm512x->real_pll = pll_rate;
+                       goto done;
+               }
+               /* no luck */
+       }
+
+       R = 1;
+
+       if (num > 0xffffffffUL / 10000)
+               goto fallback;
+
+       /* Try to find an exact pll_rate using the D > 0 case */
+       common = gcd(10000 * num, den);
+       num = 10000 * num / common;
+       den /= common;
+       dev_dbg(dev, "num %lu den %lu common %lu\n", num, den, common);
+
+       for (P = den; P <= 15; P++) {
+               if (pllin_rate / P < 6667000 || 200000000 < pllin_rate / P)
+                       continue;
+               if (num * P % den)
+                       continue;
+               K = num * P / den;
+               /* J == 12 is ok if D == 0 */
+               if (K < 40000 || K > 120000)
+                       continue;
+
+               J = K / 10000;
+               D = K % 10000;
+               dev_dbg(dev, "J.D / P = %d.%04d / %d\n", J, D, P);
+               pcm512x->real_pll = pll_rate;
+               goto done;
+       }
+
+       /* Fall back to an approximate pll_rate */
+
+fallback:
+       /* find smallest possible P */
+       P = DIV_ROUND_UP(pllin_rate, 20000000);
+       if (!P)
+               P = 1;
+       else if (P > 15) {
+               dev_err(dev, "Need a slower clock as pll-input\n");
+               return -EINVAL;
+       }
+       if (pllin_rate / P < 6667000) {
+               dev_err(dev, "Need a faster clock as pll-input\n");
+               return -EINVAL;
+       }
+       K = DIV_ROUND_CLOSEST_ULL(10000ULL * pll_rate * P, pllin_rate);
+       if (K < 40000)
+               K = 40000;
+       /* J == 12 is ok if D == 0 */
+       if (K > 120000)
+               K = 120000;
+       J = K / 10000;
+       D = K % 10000;
+       dev_dbg(dev, "J.D / P ~ %d.%04d / %d\n", J, D, P);
+       pcm512x->real_pll = DIV_ROUND_DOWN_ULL((u64)K * pllin_rate, 10000 * P);
+
+done:
+       pcm512x->pll_r = R;
+       pcm512x->pll_j = J;
+       pcm512x->pll_d = D;
+       pcm512x->pll_p = P;
+       return 0;
+}
+
+static unsigned long pcm512x_pllin_dac_rate(struct snd_soc_dai *dai,
+                                           unsigned long osr_rate,
+                                           unsigned long pllin_rate)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       unsigned long dac_rate;
+
+       if (!pcm512x->pll_out)
+               return 0; /* no PLL to bypass, force SCK as DAC input */
+
+       if (pllin_rate % osr_rate)
+               return 0; /* futile, quit early */
+
+       /* run DAC no faster than 6144000 Hz */
+       for (dac_rate = rounddown(6144000, osr_rate);
+            dac_rate;
+            dac_rate -= osr_rate) {
+
+               if (pllin_rate / dac_rate > 128)
+                       return 0; /* DAC divider would be too big */
+
+               if (!(pllin_rate % dac_rate))
+                       return dac_rate;
+
+               dac_rate -= osr_rate;
+       }
+
+       return 0;
+}
+
+static int pcm512x_set_dividers(struct snd_soc_dai *dai,
+                               struct snd_pcm_hw_params *params)
+{
+       struct device *dev = dai->dev;
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       unsigned long pllin_rate = 0;
+       unsigned long pll_rate;
+       unsigned long sck_rate;
+       unsigned long mck_rate;
+       unsigned long bclk_rate;
+       unsigned long sample_rate;
+       unsigned long osr_rate;
+       unsigned long dacsrc_rate;
+       int bclk_div;
+       int lrclk_div;
+       int dsp_div;
+       int dac_div;
+       unsigned long dac_rate;
+       int ncp_div;
+       int osr_div;
+       int ret;
+       int idac;
+       int fssp;
+       int gpio;
+
+       lrclk_div = snd_soc_params_to_frame_size(params);
+       if (lrclk_div == 0) {
+               dev_err(dev, "No LRCLK?\n");
+               return -EINVAL;
+       }
+
+       if (!pcm512x->pll_out) {
+               sck_rate = clk_get_rate(pcm512x->sclk);
+               bclk_div = params->rate_den * 64 / lrclk_div;
+               bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div);
+
+               mck_rate = sck_rate;
+       } else {
+               ret = snd_soc_params_to_bclk(params);
+               if (ret < 0) {
+                       dev_err(dev, "Failed to find suitable BCLK: %d\n", ret);
+                       return ret;
+               }
+               if (ret == 0) {
+                       dev_err(dev, "No BCLK?\n");
+                       return -EINVAL;
+               }
+               bclk_rate = ret;
+
+               pllin_rate = clk_get_rate(pcm512x->sclk);
+
+               sck_rate = pcm512x_find_sck(dai, bclk_rate);
+               if (!sck_rate)
+                       return -EINVAL;
+               pll_rate = 4 * sck_rate;
+
+               ret = pcm512x_find_pll_coeff(dai, pllin_rate, pll_rate);
+               if (ret != 0)
+                       return ret;
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_0, pcm512x->pll_p - 1);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL P: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_1, pcm512x->pll_j);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL J: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_2, pcm512x->pll_d >> 8);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL D msb: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_3, pcm512x->pll_d & 0xff);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL D lsb: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap,
+                                  PCM512x_PLL_COEFF_4, pcm512x->pll_r - 1);
+               if (ret != 0) {
+                       dev_err(dev, "Failed to write PLL R: %d\n", ret);
+                       return ret;
+               }
+
+               mck_rate = pcm512x->real_pll;
+
+               bclk_div = DIV_ROUND_CLOSEST(sck_rate, bclk_rate);
+       }
+
+       if (bclk_div > 128) {
+               dev_err(dev, "Failed to find BCLK divider\n");
+               return -EINVAL;
+       }
+
+       /* the actual rate */
+       sample_rate = sck_rate / bclk_div / lrclk_div;
+       osr_rate = 16 * sample_rate;
+
+       /* run DSP no faster than 50 MHz */
+       dsp_div = mck_rate > 50000000 ? 2 : 1;
+
+       dac_rate = pcm512x_pllin_dac_rate(dai, osr_rate, pllin_rate);
+       if (dac_rate) {
+               /* the desired clock rate is "compatible" with the pll input
+                * clock, so use that clock as dac input instead of the pll
+                * output clock since the pll will introduce jitter and thus
+                * noise.
+                */
+               dev_dbg(dev, "using pll input as dac input\n");
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+                                        PCM512x_SDAC, PCM512x_SDAC_GPIO);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio as dacref: %d\n", ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_DACIN,
+                                        PCM512x_GREF, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio %d as dacin: %d\n",
+                               pcm512x->pll_in, ret);
+                       return ret;
+               }
+
+               dacsrc_rate = pllin_rate;
+       } else {
+               /* run DAC no faster than 6144000 Hz */
+               unsigned long dac_mul = 6144000 / osr_rate;
+               unsigned long sck_mul = sck_rate / osr_rate;
+
+               for (; dac_mul; dac_mul--) {
+                       if (!(sck_mul % dac_mul))
+                               break;
+               }
+               if (!dac_mul) {
+                       dev_err(dev, "Failed to find DAC rate\n");
+                       return -EINVAL;
+               }
+
+               dac_rate = dac_mul * osr_rate;
+               dev_dbg(dev, "dac_rate %lu sample_rate %lu\n",
+                       dac_rate, sample_rate);
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_DAC_REF,
+                                        PCM512x_SDAC, PCM512x_SDAC_SCK);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set sck as dacref: %d\n", ret);
+                       return ret;
+               }
+
+               dacsrc_rate = sck_rate;
+       }
+
+       dac_div = DIV_ROUND_CLOSEST(dacsrc_rate, dac_rate);
+       if (dac_div > 128) {
+               dev_err(dev, "Failed to find DAC divider\n");
+               return -EINVAL;
+       }
+
+       ncp_div = DIV_ROUND_CLOSEST(dacsrc_rate / dac_div, 1536000);
+       if (ncp_div > 128 || dacsrc_rate / dac_div / ncp_div > 2048000) {
+               /* run NCP no faster than 2048000 Hz, but why? */
+               ncp_div = DIV_ROUND_UP(dacsrc_rate / dac_div, 2048000);
+               if (ncp_div > 128) {
+                       dev_err(dev, "Failed to find NCP divider\n");
+                       return -EINVAL;
+               }
+       }
+
+       osr_div = DIV_ROUND_CLOSEST(dac_rate, osr_rate);
+       if (osr_div > 128) {
+               dev_err(dev, "Failed to find OSR divider\n");
+               return -EINVAL;
+       }
+
+       idac = mck_rate / (dsp_div * sample_rate);
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_DSP_CLKDIV, dsp_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write DSP divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_DAC_CLKDIV, dac_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write DAC divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_NCP_CLKDIV, ncp_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write NCP divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_OSR_CLKDIV, osr_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write OSR divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap,
+                          PCM512x_MASTER_CLKDIV_1, bclk_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write BCLK divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap,
+                          PCM512x_MASTER_CLKDIV_2, lrclk_div - 1);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write LRCLK divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_1, idac >> 8);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write IDAC msb divider: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_write(pcm512x->regmap, PCM512x_IDAC_2, idac & 0xff);
+       if (ret != 0) {
+               dev_err(dev, "Failed to write IDAC lsb divider: %d\n", ret);
+               return ret;
+       }
+
+       if (sample_rate <= 48000)
+               fssp = PCM512x_FSSP_48KHZ;
+       else if (sample_rate <= 96000)
+               fssp = PCM512x_FSSP_96KHZ;
+       else if (sample_rate <= 192000)
+               fssp = PCM512x_FSSP_192KHZ;
+       else
+               fssp = PCM512x_FSSP_384KHZ;
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_FS_SPEED_MODE,
+                                PCM512x_FSSP, fssp);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set fs speed: %d\n", ret);
+               return ret;
+       }
+
+       dev_dbg(codec->dev, "DSP divider %d\n", dsp_div);
+       dev_dbg(codec->dev, "DAC divider %d\n", dac_div);
+       dev_dbg(codec->dev, "NCP divider %d\n", ncp_div);
+       dev_dbg(codec->dev, "OSR divider %d\n", osr_div);
+       dev_dbg(codec->dev, "BCK divider %d\n", bclk_div);
+       dev_dbg(codec->dev, "LRCK divider %d\n", lrclk_div);
+       dev_dbg(codec->dev, "IDAC %d\n", idac);
+       dev_dbg(codec->dev, "1<<FSSP %d\n", 1 << fssp);
+
+       return 0;
+}
+
+static int pcm512x_hw_params(struct snd_pcm_substream *substream,
+                            struct snd_pcm_hw_params *params,
+                            struct snd_soc_dai *dai)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+       int alen;
+       int gpio;
+       int clock_output;
+       int master_mode;
+       int ret;
+
+       dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n",
+               params_rate(params),
+               params_channels(params));
+
+       switch (snd_pcm_format_width(params_format(params))) {
+       case 16:
+               alen = PCM512x_ALEN_16;
+               break;
+       case 20:
+               alen = PCM512x_ALEN_20;
+               break;
+       case 24:
+               alen = PCM512x_ALEN_24;
+               break;
+       case 32:
+               alen = PCM512x_ALEN_32;
+               break;
+       default:
+               dev_err(codec->dev, "Bad frame size: %d\n",
+                       snd_pcm_format_width(params_format(params)));
+               return -EINVAL;
+       }
+
+       switch (pcm512x->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+       case SND_SOC_DAIFMT_CBS_CFS:
+               ret = regmap_update_bits(pcm512x->regmap,
+                                        PCM512x_BCLK_LRCLK_CFG,
+                                        PCM512x_BCKP
+                                        | PCM512x_BCKO | PCM512x_LRKO,
+                                        0);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to enable slave mode: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+                                        PCM512x_DCAS, 0);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to enable clock divider autoset: %d\n",
+                               ret);
+                       return ret;
+               }
+               return 0;
+       case SND_SOC_DAIFMT_CBM_CFM:
+               clock_output = PCM512x_BCKO | PCM512x_LRKO;
+               master_mode = PCM512x_RLRK | PCM512x_RBCK;
+               break;
+       case SND_SOC_DAIFMT_CBM_CFS:
+               clock_output = PCM512x_BCKO;
+               master_mode = PCM512x_RBCK;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_I2S_1,
+                                PCM512x_ALEN, alen);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set frame size: %d\n", ret);
+               return ret;
+       }
+
+       if (pcm512x->pll_out) {
+               ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_A, 0x11);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to set FLEX_A: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_write(pcm512x->regmap, PCM512x_FLEX_B, 0xff);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to set FLEX_B: %d\n", ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_IDCM | PCM512x_DCAS
+                                        | PCM512x_IPLK,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_DCAS);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to ignore auto-clock failures: %d\n",
+                               ret);
+                       return ret;
+               }
+       } else {
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_ERROR_DETECT,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_IDCM | PCM512x_DCAS
+                                        | PCM512x_IPLK,
+                                        PCM512x_IDFS | PCM512x_IDBK
+                                        | PCM512x_IDSK | PCM512x_IDCH
+                                        | PCM512x_DCAS | PCM512x_IPLK);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to ignore auto-clock failures: %d\n",
+                               ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+                                        PCM512x_PLLE, 0);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to disable pll: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = pcm512x_set_dividers(dai, params);
+       if (ret != 0)
+               return ret;
+
+       if (pcm512x->pll_out) {
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_REF,
+                                        PCM512x_SREF, PCM512x_SREF_GPIO);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio as pllref: %d\n", ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GREF_GPIO1 + pcm512x->pll_in - 1;
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_PLLIN,
+                                        PCM512x_GREF, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to set gpio %d as pllin: %d\n",
+                               pcm512x->pll_in, ret);
+                       return ret;
+               }
+
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_PLL_EN,
+                                        PCM512x_PLLE, PCM512x_PLLE);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to enable pll: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_BCLK_LRCLK_CFG,
+                                PCM512x_BCKP | PCM512x_BCKO | PCM512x_LRKO,
+                                clock_output);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable clock output: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_MASTER_MODE,
+                                PCM512x_RLRK | PCM512x_RBCK,
+                                master_mode);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to enable master mode: %d\n", ret);
+               return ret;
+       }
+
+       if (pcm512x->pll_out) {
+               gpio = PCM512x_G1OE << (pcm512x->pll_out - 1);
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+                                        gpio, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+                               pcm512x->pll_out, ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GPIO_OUTPUT_1 + pcm512x->pll_out - 1;
+               ret = regmap_update_bits(pcm512x->regmap, gpio,
+                                        PCM512x_GxSL, PCM512x_GxSL_PLLCK);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to output pll on %d: %d\n",
+                               ret, pcm512x->pll_out);
+                       return ret;
+               }
+
+               gpio = PCM512x_G1OE << (4 - 1);
+               ret = regmap_update_bits(pcm512x->regmap, PCM512x_GPIO_EN,
+                                        gpio, gpio);
+               if (ret != 0) {
+                       dev_err(codec->dev, "Failed to enable gpio %d: %d\n",
+                               4, ret);
+                       return ret;
+               }
+
+               gpio = PCM512x_GPIO_OUTPUT_1 + 4 - 1;
+               ret = regmap_update_bits(pcm512x->regmap, gpio,
+                                        PCM512x_GxSL, PCM512x_GxSL_PLLLK);
+               if (ret != 0) {
+                       dev_err(codec->dev,
+                               "Failed to output pll lock on %d: %d\n",
+                               ret, 4);
+                       return ret;
+               }
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+                                PCM512x_RQSY, PCM512x_RQSY_HALT);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to halt clocks: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_update_bits(pcm512x->regmap, PCM512x_SYNCHRONIZE,
+                                PCM512x_RQSY, PCM512x_RQSY_RESUME);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to resume clocks: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int pcm512x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+       struct snd_soc_codec *codec = dai->codec;
+       struct pcm512x_priv *pcm512x = snd_soc_codec_get_drvdata(codec);
+
+       pcm512x->fmt = fmt;
+
+       return 0;
+}
+
+static const struct snd_soc_dai_ops pcm512x_dai_ops = {
+       .startup = pcm512x_dai_startup,
+       .hw_params = pcm512x_hw_params,
+       .set_fmt = pcm512x_set_fmt,
+};
+
 static struct snd_soc_dai_driver pcm512x_dai = {
        .name = "pcm512x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
                .channels_max = 2,
-               .rates = SNDRV_PCM_RATE_8000_192000,
+               .rates = SNDRV_PCM_RATE_CONTINUOUS,
+               .rate_min = 8000,
+               .rate_max = 384000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE |
                           SNDRV_PCM_FMTBIT_S24_LE |
                           SNDRV_PCM_FMTBIT_S32_LE
        },
+       .ops = &pcm512x_dai_ops,
 };
 
 static struct snd_soc_codec_driver pcm512x_codec_driver = {
@@ -448,21 +1321,9 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        }
 
        pcm512x->sclk = devm_clk_get(dev, NULL);
-       if (IS_ERR(pcm512x->sclk)) {
-               if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
-
-               dev_info(dev, "No SCLK, using BCLK: %ld\n",
-                        PTR_ERR(pcm512x->sclk));
-
-               /* Disable reporting of missing SCLK as an error */
-               regmap_update_bits(regmap, PCM512x_ERROR_DETECT,
-                                  PCM512x_IDCH, PCM512x_IDCH);
-
-               /* Switch PLL input to BCLK */
-               regmap_update_bits(regmap, PCM512x_PLL_REF,
-                                  PCM512x_SREF, PCM512x_SREF);
-       } else {
+       if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (!IS_ERR(pcm512x->sclk)) {
                ret = clk_prepare_enable(pcm512x->sclk);
                if (ret != 0) {
                        dev_err(dev, "Failed to enable SCLK: %d\n", ret);
@@ -483,6 +1344,43 @@ int pcm512x_probe(struct device *dev, struct regmap *regmap)
        pm_runtime_enable(dev);
        pm_runtime_idle(dev);
 
+#ifdef CONFIG_OF
+       if (dev->of_node) {
+               const struct device_node *np = dev->of_node;
+               u32 val;
+
+               if (of_property_read_u32(np, "pll-in", &val) >= 0) {
+                       if (val > 6) {
+                               dev_err(dev, "Invalid pll-in\n");
+                               ret = -EINVAL;
+                               goto err_clk;
+                       }
+                       pcm512x->pll_in = val;
+               }
+
+               if (of_property_read_u32(np, "pll-out", &val) >= 0) {
+                       if (val > 6) {
+                               dev_err(dev, "Invalid pll-out\n");
+                               ret = -EINVAL;
+                               goto err_clk;
+                       }
+                       pcm512x->pll_out = val;
+               }
+
+               if (!pcm512x->pll_in != !pcm512x->pll_out) {
+                       dev_err(dev,
+                               "Error: both pll-in and pll-out, or none\n");
+                       ret = -EINVAL;
+                       goto err_clk;
+               }
+               if (pcm512x->pll_in && pcm512x->pll_in == pcm512x->pll_out) {
+                       dev_err(dev, "Error: pll-in == pll-out\n");
+                       ret = -EINVAL;
+                       goto err_clk;
+               }
+       }
+#endif
+
        ret = snd_soc_register_codec(dev, &pcm512x_codec_driver,
                                    &pcm512x_dai, 1);
        if (ret != 0) {
index 6ee76aaca09a0a5ebca6fde6b885e7d10cb558b0..b7c3102072232336feedc6e9af7dc5e14bfffdb6 100644 (file)
 #define PCM512x_DSP_GPIO_INPUT    (PCM512x_PAGE_BASE(0) +  10)
 #define PCM512x_MASTER_MODE       (PCM512x_PAGE_BASE(0) +  12)
 #define PCM512x_PLL_REF           (PCM512x_PAGE_BASE(0) +  13)
+#define PCM512x_DAC_REF           (PCM512x_PAGE_BASE(0) +  14)
+#define PCM512x_GPIO_DACIN        (PCM512x_PAGE_BASE(0) +  16)
+#define PCM512x_GPIO_PLLIN        (PCM512x_PAGE_BASE(0) +  18)
+#define PCM512x_SYNCHRONIZE       (PCM512x_PAGE_BASE(0) +  19)
 #define PCM512x_PLL_COEFF_0       (PCM512x_PAGE_BASE(0) +  20)
 #define PCM512x_PLL_COEFF_1       (PCM512x_PAGE_BASE(0) +  21)
 #define PCM512x_PLL_COEFF_2       (PCM512x_PAGE_BASE(0) +  22)
@@ -77,6 +81,7 @@
 #define PCM512x_RATE_DET_2        (PCM512x_PAGE_BASE(0) +  92)
 #define PCM512x_RATE_DET_3        (PCM512x_PAGE_BASE(0) +  93)
 #define PCM512x_RATE_DET_4        (PCM512x_PAGE_BASE(0) +  94)
+#define PCM512x_CLOCK_STATUS      (PCM512x_PAGE_BASE(0) +  95)
 #define PCM512x_ANALOG_MUTE_DET   (PCM512x_PAGE_BASE(0) + 108)
 #define PCM512x_GPIN              (PCM512x_PAGE_BASE(0) + 119)
 #define PCM512x_DIGITAL_MUTE_DET  (PCM512x_PAGE_BASE(0) + 120)
 
 #define PCM512x_CRAM_CTRL         (PCM512x_PAGE_BASE(44) +  1)
 
-#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(44) +  1)
+#define PCM512x_FLEX_A            (PCM512x_PAGE_BASE(253) + 63)
+#define PCM512x_FLEX_B            (PCM512x_PAGE_BASE(253) + 64)
+
+#define PCM512x_MAX_REGISTER      (PCM512x_PAGE_BASE(253) + 64)
 
 /* Page 0, Register 1 - reset */
 #define PCM512x_RSTR (1 << 0)
 #define PCM512x_RQML_SHIFT 4
 
 /* Page 0, Register 4 - PLL */
-#define PCM512x_PLCE       (1 << 0)
-#define PCM512x_RLCE_SHIFT 0
+#define PCM512x_PLLE       (1 << 0)
+#define PCM512x_PLLE_SHIFT 0
 #define PCM512x_PLCK       (1 << 4)
 #define PCM512x_PLCK_SHIFT 4
 
 #define PCM512x_DEMP       (1 << 4)
 #define PCM512x_DEMP_SHIFT 4
 
+/* Page 0, Register 8 - GPIO output enable */
+#define PCM512x_G1OE       (1 << 0)
+#define PCM512x_G2OE       (1 << 1)
+#define PCM512x_G3OE       (1 << 2)
+#define PCM512x_G4OE       (1 << 3)
+#define PCM512x_G5OE       (1 << 4)
+#define PCM512x_G6OE       (1 << 5)
+
+/* Page 0, Register 9 - BCK, LRCLK configuration */
+#define PCM512x_LRKO       (1 << 0)
+#define PCM512x_LRKO_SHIFT 0
+#define PCM512x_BCKO       (1 << 4)
+#define PCM512x_BCKO_SHIFT 4
+#define PCM512x_BCKP       (1 << 5)
+#define PCM512x_BCKP_SHIFT 5
+
+/* Page 0, Register 12 - Master mode BCK, LRCLK reset */
+#define PCM512x_RLRK       (1 << 0)
+#define PCM512x_RLRK_SHIFT 0
+#define PCM512x_RBCK       (1 << 1)
+#define PCM512x_RBCK_SHIFT 1
+
 /* Page 0, Register 13 - PLL reference */
-#define PCM512x_SREF (1 << 4)
+#define PCM512x_SREF        (7 << 4)
+#define PCM512x_SREF_SHIFT  4
+#define PCM512x_SREF_SCK    (0 << 4)
+#define PCM512x_SREF_BCK    (1 << 4)
+#define PCM512x_SREF_GPIO   (3 << 4)
+
+/* Page 0, Register 14 - DAC reference */
+#define PCM512x_SDAC        (7 << 4)
+#define PCM512x_SDAC_SHIFT  4
+#define PCM512x_SDAC_MCK    (0 << 4)
+#define PCM512x_SDAC_PLL    (1 << 4)
+#define PCM512x_SDAC_SCK    (3 << 4)
+#define PCM512x_SDAC_BCK    (4 << 4)
+#define PCM512x_SDAC_GPIO   (5 << 4)
+
+/* Page 0, Register 16, 18 - GPIO source for DAC, PLL */
+#define PCM512x_GREF        (7 << 0)
+#define PCM512x_GREF_SHIFT  0
+#define PCM512x_GREF_GPIO1  (0 << 0)
+#define PCM512x_GREF_GPIO2  (1 << 0)
+#define PCM512x_GREF_GPIO3  (2 << 0)
+#define PCM512x_GREF_GPIO4  (3 << 0)
+#define PCM512x_GREF_GPIO5  (4 << 0)
+#define PCM512x_GREF_GPIO6  (5 << 0)
+
+/* Page 0, Register 19 - synchronize */
+#define PCM512x_RQSY        (1 << 0)
+#define PCM512x_RQSY_RESUME (0 << 0)
+#define PCM512x_RQSY_HALT   (1 << 0)
+
+/* Page 0, Register 34 - fs speed mode */
+#define PCM512x_FSSP        (3 << 0)
+#define PCM512x_FSSP_SHIFT  0
+#define PCM512x_FSSP_48KHZ  (0 << 0)
+#define PCM512x_FSSP_96KHZ  (1 << 0)
+#define PCM512x_FSSP_192KHZ (2 << 0)
+#define PCM512x_FSSP_384KHZ (3 << 0)
 
 /* Page 0, Register 37 - Error detection */
 #define PCM512x_IPLK (1 << 0)
 #define PCM512x_IDBK (1 << 5)
 #define PCM512x_IDFS (1 << 6)
 
+/* Page 0, Register 40 - I2S configuration */
+#define PCM512x_ALEN       (3 << 0)
+#define PCM512x_ALEN_SHIFT 0
+#define PCM512x_ALEN_16    (0 << 0)
+#define PCM512x_ALEN_20    (1 << 0)
+#define PCM512x_ALEN_24    (2 << 0)
+#define PCM512x_ALEN_32    (3 << 0)
+#define PCM512x_AFMT       (3 << 4)
+#define PCM512x_AFMT_SHIFT 4
+#define PCM512x_AFMT_I2S   (0 << 4)
+#define PCM512x_AFMT_DSP   (1 << 4)
+#define PCM512x_AFMT_RTJ   (2 << 4)
+#define PCM512x_AFMT_LTJ   (3 << 4)
+
 /* Page 0, Register 42 - DAC routing */
 #define PCM512x_AUPR_SHIFT 0
 #define PCM512x_AUPL_SHIFT 4
 /* Page 0, Register 65 - Digital mute enables */
 #define PCM512x_ACTL_SHIFT 2
 #define PCM512x_AMLE_SHIFT 1
-#define PCM512x_AMLR_SHIFT 0
+#define PCM512x_AMRE_SHIFT 0
+
+/* Page 0, Register 80-85, GPIO output selection */
+#define PCM512x_GxSL       (31 << 0)
+#define PCM512x_GxSL_SHIFT 0
+#define PCM512x_GxSL_OFF   (0 << 0)
+#define PCM512x_GxSL_DSP   (1 << 0)
+#define PCM512x_GxSL_REG   (2 << 0)
+#define PCM512x_GxSL_AMUTB (3 << 0)
+#define PCM512x_GxSL_AMUTL (4 << 0)
+#define PCM512x_GxSL_AMUTR (5 << 0)
+#define PCM512x_GxSL_CLKI  (6 << 0)
+#define PCM512x_GxSL_SDOUT (7 << 0)
+#define PCM512x_GxSL_ANMUL (8 << 0)
+#define PCM512x_GxSL_ANMUR (9 << 0)
+#define PCM512x_GxSL_PLLLK (10 << 0)
+#define PCM512x_GxSL_CPCLK (11 << 0)
+#define PCM512x_GxSL_UV0_7 (14 << 0)
+#define PCM512x_GxSL_UV0_3 (15 << 0)
+#define PCM512x_GxSL_PLLCK (16 << 0)
 
 /* Page 1, Register 2 - analog volume control */
 #define PCM512x_RAGN_SHIFT 0
index 2cd4fe463102d4532458e1ed3402abd276be8fc1..8104d2285602b9fcedbbfa440c2f9a1f22960105 100644 (file)
@@ -403,7 +403,8 @@ EXPORT_SYMBOL_GPL(rt286_mic_detect);
 static int is_mclk_mode(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
 
        if (rt286->clk_id == RT286_SCLK_S_MCLK)
                return 1;
@@ -417,6 +418,8 @@ static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
 static const struct snd_kcontrol_new rt286_snd_controls[] = {
        SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN,
                            RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv),
+       SOC_DOUBLE_R("ADC0 Capture Switch", RT286_ADCL_GAIN,
+                           RT286_ADCR_GAIN, 7, 1, 1),
        SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN,
                            RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv),
        SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN,
@@ -500,7 +503,7 @@ SOC_DAPM_ENUM("SPO source", rt286_spo_enum);
 static int rt286_spk_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -522,7 +525,7 @@ static int rt286_spk_event(struct snd_soc_dapm_widget *w,
 static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
                                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -538,36 +541,10 @@ static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
-static int rt286_adc_event(struct snd_soc_dapm_widget *w,
-                            struct snd_kcontrol *kcontrol, int event)
-{
-       struct snd_soc_codec *codec = w->codec;
-       unsigned int nid;
-
-       nid = (w->reg >> 20) & 0xff;
-
-       switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(codec,
-                       VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
-                       0x7080, 0x7000);
-               break;
-       case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(codec,
-                       VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0),
-                       0x7080, 0x7080);
-               break;
-       default:
-               return 0;
-       }
-
-       return 0;
-}
-
 static int rt286_vref_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -585,7 +562,7 @@ static int rt286_vref_event(struct snd_soc_dapm_widget *w,
 static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -604,7 +581,7 @@ static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
 static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -667,12 +644,10 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0),
 
        /* ADC Mux */
-       SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
-               &rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD |
-               SND_SOC_DAPM_POST_PMU),
-       SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
-               &rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD |
-               SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_MUX("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1,
+               &rt286_adc0_mux),
+       SND_SOC_DAPM_MUX("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1,
+               &rt286_adc1_mux),
 
        /* Audio Interface */
        SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
@@ -861,10 +836,8 @@ static int rt286_hw_params(struct snd_pcm_substream *substream,
                RT286_I2S_CTRL1, 0x0018, d_len_code << 3);
        dev_dbg(codec->dev, "format val = 0x%x\n", val);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val);
-       else
-               snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val);
+       snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val);
+       snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val);
 
        return 0;
 }
index 6d7b7ca7d530f034d2e972ba8070c03280e22bd0..c61852742ee30889c3fa482135acd1960324602f 100644 (file)
@@ -287,70 +287,78 @@ static const struct snd_kcontrol_new rt5631_snd_controls[] = {
 static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_GLOBAL_CLK_CTRL);
+       reg = snd_soc_read(codec, RT5631_GLOBAL_CLK_CTRL);
        return reg & RT5631_SYSCLK_SOUR_SEL_PLL;
 }
 
 static int check_dmic_used(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
        return rt5631->dmic_used_flag;
 }
 
 static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL);
+       reg = snd_soc_read(codec, RT5631_OUTMIXER_L_CTRL);
        return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L);
 }
 
 static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL);
+       reg = snd_soc_read(codec, RT5631_OUTMIXER_R_CTRL);
        return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R);
 }
 
 static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+       reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
        return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L);
 }
 
 static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL);
+       reg = snd_soc_read(codec, RT5631_SPK_MIXER_CTRL);
        return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R);
 }
 
 static int check_adcl_select(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+       reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
        return !(reg & RT5631_M_MIC1_TO_RECMIXER_L);
 }
 
 static int check_adcr_select(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
 
-       reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER);
+       reg = snd_soc_read(codec, RT5631_ADC_REC_MIXER);
        return !(reg & RT5631_M_MIC2_TO_RECMIXER_R);
 }
 
@@ -556,7 +564,7 @@ static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable)
 static int hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -590,7 +598,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int set_dmic_params(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec);
 
        switch (rt5631->rx_rate) {
index c3f2decd643c9ba7eb57eec8a644091bc440376d..178e55d4d48146b9bfee3a211bd297f67a822790 100644 (file)
@@ -458,7 +458,7 @@ static const struct snd_kcontrol_new rt5640_specific_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -475,9 +475,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5640_GLB_CLK);
+       val = snd_soc_read(codec, RT5640_GLB_CLK);
        val &= RT5640_SCLK_SRC_MASK;
        if (val == RT5640_SCLK_SRC_PLL1)
                return 1;
@@ -963,7 +964,7 @@ static void rt5640_pmu_depop(struct snd_soc_codec *codec)
 static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -987,7 +988,7 @@ static int rt5640_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1003,7 +1004,7 @@ static int rt5640_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2124,6 +2125,7 @@ MODULE_DEVICE_TABLE(of, rt5640_of_match);
 static struct acpi_device_id rt5640_acpi_match[] = {
        { "INT33CA", 0 },
        { "10EC5640", 0 },
+       { "10EC5642", 0 },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match);
index 27141e2df878a65204fc31cc9486fb099319bd26..3e16a889a8063f77e413aced7381574a9431ddad 100644 (file)
@@ -31,6 +31,7 @@
 #include "rt5645.h"
 
 #define RT5645_DEVICE_ID 0x6308
+#define RT5650_DEVICE_ID 0x6419
 
 #define RT5645_PR_RANGE_BASE (0xff + 1)
 #define RT5645_PR_SPACING 0x100
@@ -59,6 +60,10 @@ static const struct reg_default init_list[] = {
 };
 #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
+static const struct reg_default rt5650_init_list[] = {
+       {0xf6,  0x0100},
+};
+
 static const struct reg_default rt5645_reg[] = {
        { 0x00, 0x0000 },
        { 0x01, 0xc8c8 },
@@ -86,6 +91,7 @@ static const struct reg_default rt5645_reg[] = {
        { 0x2a, 0x5656 },
        { 0x2b, 0x5454 },
        { 0x2c, 0xaaa0 },
+       { 0x2d, 0x0000 },
        { 0x2f, 0x1002 },
        { 0x31, 0x5000 },
        { 0x32, 0x0000 },
@@ -193,6 +199,8 @@ static const struct reg_default rt5645_reg[] = {
        { 0xdb, 0x0003 },
        { 0xdc, 0x0049 },
        { 0xdd, 0x001b },
+       { 0xdf, 0x0008 },
+       { 0xe0, 0x4000 },
        { 0xe6, 0x8000 },
        { 0xe7, 0x0200 },
        { 0xec, 0xb300 },
@@ -242,6 +250,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg)
        case RT5645_IRQ_CTRL3:
        case RT5645_INT_IRQ_ST:
        case RT5645_IL_CMD:
+       case RT5650_4BTN_IL_CMD1:
        case RT5645_VENDOR_ID:
        case RT5645_VENDOR_ID1:
        case RT5645_VENDOR_ID2:
@@ -287,6 +296,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
        case RT5645_STO_DAC_MIXER:
        case RT5645_MONO_DAC_MIXER:
        case RT5645_DIG_MIXER:
+       case RT5650_A_DAC_SOUR:
        case RT5645_DIG_INF1_DATA:
        case RT5645_PDM_OUT_CTRL:
        case RT5645_REC_L1_MIXER:
@@ -378,6 +388,8 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg)
        case RT5645_IL_CMD:
        case RT5645_IL_CMD2:
        case RT5645_IL_CMD3:
+       case RT5650_4BTN_IL_CMD1:
+       case RT5650_4BTN_IL_CMD2:
        case RT5645_DRC1_HL_CTRL1:
        case RT5645_DRC2_HL_CTRL1:
        case RT5645_ADC_MONO_HP_CTRL1:
@@ -527,7 +539,7 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -544,9 +556,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5645_GLB_CLK);
+       val = snd_soc_read(codec, RT5645_GLB_CLK);
        val &= RT5645_SCLK_SRC_MASK;
        if (val == RT5645_SCLK_SRC_PLL1)
                return 1;
@@ -557,6 +570,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg, shift, val;
 
        switch (source->shift) {
@@ -588,7 +602,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
                return 0;
        }
 
-       val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+       val = (snd_soc_read(codec, reg) >> shift) & 0xf;
        switch (val) {
        case 1:
        case 2:
@@ -1007,6 +1021,44 @@ static SOC_ENUM_SINGLE_DECL(
 static const struct snd_kcontrol_new rt5645_if1_adc_in_mux =
        SOC_DAPM_ENUM("IF1 ADC IN source", rt5645_if1_adc_in_enum);
 
+/* MX-2d [3] [2] */
+static const char * const rt5650_a_dac1_src[] = {
+       "DAC1", "Stereo DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac1_l_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC1_L_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_l_mux =
+       SOC_DAPM_ENUM("A DAC1 L source", rt5650_a_dac1_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac1_r_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC1_R_IN_SFT, rt5650_a_dac1_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac1_r_mux =
+       SOC_DAPM_ENUM("A DAC1 R source", rt5650_a_dac1_r_enum);
+
+/* MX-2d [1] [0] */
+static const char * const rt5650_a_dac2_src[] = {
+       "Stereo DAC Mixer", "Mono DAC Mixer"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac2_l_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC2_L_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_l_mux =
+       SOC_DAPM_ENUM("A DAC2 L source", rt5650_a_dac2_l_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+       rt5650_a_dac2_r_enum, RT5650_A_DAC_SOUR,
+       RT5650_A_DAC2_R_IN_SFT, rt5650_a_dac2_src);
+
+static const struct snd_kcontrol_new rt5650_a_dac2_r_mux =
+       SOC_DAPM_ENUM("A DAC2 R source", rt5650_a_dac2_r_enum);
+
 /* MX-2F [13:12] */
 static const char * const rt5645_if2_adc_in_src[] = {
        "IF_ADC1", "IF_ADC2", "VAD_ADC"
@@ -1144,18 +1196,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
 static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                hp_amp_power(codec, 1);
                /* headphone unmute sequence */
-               snd_soc_update_bits(codec, RT5645_DEPOP_M3, RT5645_CP_FQ1_MASK |
-                       RT5645_CP_FQ2_MASK | RT5645_CP_FQ3_MASK,
-                       (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
-                       (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-                       (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+               if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+                       snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+               } else {
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+                               RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+                               RT5645_CP_FQ3_MASK,
+                               (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ1_SFT) |
+                               (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+                               (RT5645_CP_FQ_192_KHZ << RT5645_CP_FQ3_SFT));
+               }
                regmap_write(rt5645->regmap,
                        RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
                snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1175,12 +1232,16 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 
        case SND_SOC_DAPM_PRE_PMD:
                /* headphone mute sequence */
-               snd_soc_update_bits(codec, RT5645_DEPOP_M3,
-                       RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
-                       RT5645_CP_FQ3_MASK,
-                       (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
-                       (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
-                       (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+               if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+                       snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737);
+               } else {
+                       snd_soc_update_bits(codec, RT5645_DEPOP_M3,
+                               RT5645_CP_FQ1_MASK | RT5645_CP_FQ2_MASK |
+                               RT5645_CP_FQ3_MASK,
+                               (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ1_SFT) |
+                               (RT5645_CP_FQ_12_KHZ << RT5645_CP_FQ2_SFT) |
+                               (RT5645_CP_FQ_96_KHZ << RT5645_CP_FQ3_SFT));
+               }
                regmap_write(rt5645->regmap,
                        RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00);
                snd_soc_update_bits(codec, RT5645_DEPOP_M1,
@@ -1205,7 +1266,7 @@ static int rt5645_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1232,7 +1293,7 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
 static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1262,7 +1323,7 @@ static int rt5645_lout_event(struct snd_soc_dapm_widget *w,
 static int rt5645_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1574,6 +1635,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("SPOR"),
 };
 
+static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = {
+       SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac1_l_mux),
+       SND_SOC_DAPM_MUX("A DAC1 R Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac1_r_mux),
+       SND_SOC_DAPM_MUX("A DAC2 L Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac2_l_mux),
+       SND_SOC_DAPM_MUX("A DAC2 R Mux", SND_SOC_NOPM,
+               0, 0, &rt5650_a_dac2_r_mux),
+};
+
 static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
        { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1779,13 +1851,9 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "DAC MIXR", "DAC R2 Switch", "DAC R2 Volume" },
        { "DAC MIXR", "DAC L2 Switch", "DAC L2 Volume" },
 
-       { "DAC L1", NULL, "Stereo DAC MIXL" },
        { "DAC L1", NULL, "PLL1", is_sys_clk_from_pll },
-       { "DAC R1", NULL, "Stereo DAC MIXR" },
        { "DAC R1", NULL, "PLL1", is_sys_clk_from_pll },
-       { "DAC L2", NULL, "Mono DAC MIXL" },
        { "DAC L2", NULL, "PLL1", is_sys_clk_from_pll },
-       { "DAC R2", NULL, "Mono DAC MIXR" },
        { "DAC R2", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "SPK MIXL", "BST1 Switch", "BST1" },
@@ -1874,6 +1942,30 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
        { "SPOR", NULL, "SPK amp" },
 };
 
+static const struct snd_soc_dapm_route rt5650_specific_dapm_routes[] = {
+       { "A DAC1 L Mux", "DAC1",  "DAC1 MIXL"},
+       { "A DAC1 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+       { "A DAC1 R Mux", "DAC1",  "DAC1 MIXR"},
+       { "A DAC1 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+
+       { "A DAC2 L Mux", "Stereo DAC Mixer", "Stereo DAC MIXL"},
+       { "A DAC2 L Mux", "Mono DAC Mixer", "Mono DAC MIXL"},
+       { "A DAC2 R Mux", "Stereo DAC Mixer", "Stereo DAC MIXR"},
+       { "A DAC2 R Mux", "Mono DAC Mixer", "Mono DAC MIXR"},
+
+       { "DAC L1", NULL, "A DAC1 L Mux" },
+       { "DAC R1", NULL, "A DAC1 R Mux" },
+       { "DAC L2", NULL, "A DAC2 L Mux" },
+       { "DAC R2", NULL, "A DAC2 R Mux" },
+};
+
+static const struct snd_soc_dapm_route rt5645_specific_dapm_routes[] = {
+       { "DAC L1", NULL, "Stereo DAC MIXL" },
+       { "DAC R1", NULL, "Stereo DAC MIXR" },
+       { "DAC L2", NULL, "Mono DAC MIXL" },
+       { "DAC R2", NULL, "Mono DAC MIXR" },
+};
+
 static int rt5645_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
@@ -2293,6 +2385,22 @@ static int rt5645_probe(struct snd_soc_codec *codec)
 
        rt5645->codec = codec;
 
+       switch (rt5645->codec_type) {
+       case CODEC_TYPE_RT5645:
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5645_specific_dapm_routes,
+                       ARRAY_SIZE(rt5645_specific_dapm_routes));
+               break;
+       case CODEC_TYPE_RT5650:
+               snd_soc_dapm_new_controls(&codec->dapm,
+                       rt5650_specific_dapm_widgets,
+                       ARRAY_SIZE(rt5650_specific_dapm_widgets));
+               snd_soc_dapm_add_routes(&codec->dapm,
+                       rt5650_specific_dapm_routes,
+                       ARRAY_SIZE(rt5650_specific_dapm_routes));
+               break;
+       }
+
        rt5645_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
        snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
@@ -2424,6 +2532,7 @@ static const struct regmap_config rt5645_regmap = {
 
 static const struct i2c_device_id rt5645_i2c_id[] = {
        { "rt5645", 0 },
+       { "rt5650", 0 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id);
@@ -2456,9 +2565,18 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
        }
 
        regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val);
-       if (val != RT5645_DEVICE_ID) {
+
+       switch (val) {
+       case RT5645_DEVICE_ID:
+               rt5645->codec_type = CODEC_TYPE_RT5645;
+               break;
+       case RT5650_DEVICE_ID:
+               rt5645->codec_type = CODEC_TYPE_RT5650;
+               break;
+       default:
                dev_err(&i2c->dev,
-                       "Device with ID register %x is not rt5645\n", val);
+                       "Device with ID register %x is not rt5645 or rt5650\n",
+                       val);
                return -ENODEV;
        }
 
@@ -2469,6 +2587,14 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
        if (ret != 0)
                dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret);
 
+       if (rt5645->codec_type == CODEC_TYPE_RT5650) {
+               ret = regmap_register_patch(rt5645->regmap, rt5650_init_list,
+                                   ARRAY_SIZE(rt5650_init_list));
+               if (ret != 0)
+                       dev_warn(&i2c->dev, "Apply rt5650 patch failed: %d\n",
+                                          ret);
+       }
+
        if (rt5645->pdata.in2_diff)
                regmap_update_bits(rt5645->regmap, RT5645_IN2_CTRL,
                                        RT5645_IN_DF2, RT5645_IN_DF2);
index a815e36a2bdbcf27f2dc7e091e23d1ea28aaae75..74542310d3f0887cad49ee99877420d055ec7ba7 100644 (file)
@@ -47,6 +47,7 @@
 #define RT5645_STO_DAC_MIXER                   0x2a
 #define RT5645_MONO_DAC_MIXER                  0x2b
 #define RT5645_DIG_MIXER                       0x2c
+#define RT5650_A_DAC_SOUR                      0x2d
 #define RT5645_DIG_INF1_DATA                   0x2f
 /* Mixer - PDM */
 #define RT5645_PDM_OUT_CTRL                    0x31
 #define RT5645_IL_CMD                          0xdb
 #define RT5645_IL_CMD2                         0xdc
 #define RT5645_IL_CMD3                         0xdd
+#define RT5650_4BTN_IL_CMD1                    0xdf
+#define RT5650_4BTN_IL_CMD2                    0xe0
 #define RT5645_DRC1_HL_CTRL1                   0xe7
 #define RT5645_DRC2_HL_CTRL1                   0xe9
 #define RT5645_MUTI_DRC_CTRL1                  0xea
 #define RT5645_DAC_L2_DAC_R_VOL_MASK           (0x1 << 4)
 #define RT5645_DAC_L2_DAC_R_VOL_SFT            4
 
+/* Analog DAC1/2 Input Source Control (0x2d) */
+#define RT5650_A_DAC1_L_IN_SFT                 3
+#define RT5650_A_DAC1_R_IN_SFT                 2
+#define RT5650_A_DAC2_L_IN_SFT                 1
+#define RT5650_A_DAC2_R_IN_SFT                 0
+
 /* Digital Interface Data Control (0x2f) */
 #define RT5645_IF1_ADC2_IN_SEL                 (0x1 << 15)
 #define RT5645_IF1_ADC2_IN_SFT                 15
@@ -2175,6 +2184,11 @@ enum {
        RT5645_DMIC_DATA_GPIO11,
 };
 
+enum {
+       CODEC_TYPE_RT5645,
+       CODEC_TYPE_RT5650,
+};
+
 struct rt5645_priv {
        struct snd_soc_codec *codec;
        struct rt5645_platform_data pdata;
@@ -2184,6 +2198,7 @@ struct rt5645_priv {
        struct snd_soc_jack *mic_jack;
        struct delayed_work jack_detect_work;
 
+       int codec_type;
        int sysclk;
        int sysclk_src;
        int lrck[RT5645_AIFS];
index bb0a3ab5416cb2fe9fbc4e79c40e31340b374935..9f4c7be6d798691c70b953c65751904b68c66db1 100644 (file)
@@ -376,7 +376,7 @@ static const struct snd_kcontrol_new rt5651_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -394,9 +394,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sysclk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5651_GLB_CLK);
+       val = snd_soc_read(codec, RT5651_GLB_CLK);
        val &= RT5651_SCLK_SRC_MASK;
        if (val == RT5651_SCLK_SRC_PLL1)
                return 1;
@@ -731,7 +732,7 @@ static const struct snd_kcontrol_new rt5651_pdm_r_mux =
 static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -769,7 +770,7 @@ static int rt5651_amp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -813,7 +814,8 @@ static int rt5651_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -833,7 +835,7 @@ static int rt5651_hp_post_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -856,7 +858,7 @@ static int rt5651_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -879,7 +881,7 @@ static int rt5651_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5651_bst3_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index 8a0833de1665bcd39594d27bbc323e4ea3d35ba0..7b3d6b5992f1bc03d70988e1a7dc04c206c9361b 100644 (file)
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
+#include <linux/pm_runtime.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/spi/spi.h>
+#include <linux/dmi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -498,7 +500,7 @@ static const struct snd_kcontrol_new rt5670_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
        int idx = -EINVAL;
 
@@ -515,9 +517,10 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int val;
 
-       val = snd_soc_read(source->codec, RT5670_GLB_CLK);
+       val = snd_soc_read(codec, RT5670_GLB_CLK);
        val &= RT5670_SCLK_SRC_MASK;
        if (val == RT5670_SCLK_SRC_PLL1)
                return 1;
@@ -528,6 +531,7 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
 static int is_using_asrc(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg, shift, val;
 
        switch (source->shift) {
@@ -563,7 +567,7 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
                return 0;
        }
 
-       val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+       val = (snd_soc_read(codec, reg) >> shift) & 0xf;
        switch (val) {
        case 1:
        case 2:
@@ -588,6 +592,89 @@ static int can_use_asrc(struct snd_soc_dapm_widget *source,
        return 0;
 }
 
+
+/**
+ * rt5670_sel_asrc_clk_src - select ASRC clock source for a set of filters
+ * @codec: SoC audio codec device.
+ * @filter_mask: mask of filters.
+ * @clk_src: clock source
+ *
+ * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5670 can
+ * only support standard 32fs or 64fs i2s format, ASRC should be enabled to
+ * support special i2s clock format such as Intel's 100fs(100 * sampling rate).
+ * ASRC function will track i2s clock and generate a corresponding system clock
+ * for codec. This function provides an API to select the clock source for a
+ * set of filters specified by the mask. And the codec driver will turn on ASRC
+ * for these filters if ASRC is selected as their clock source.
+ */
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+                           unsigned int filter_mask, unsigned int clk_src)
+{
+       unsigned int asrc2_mask = 0, asrc2_value = 0;
+       unsigned int asrc3_mask = 0, asrc3_value = 0;
+
+       if (clk_src > RT5670_CLK_SEL_SYS3)
+               return -EINVAL;
+
+       if (filter_mask & RT5670_DA_STEREO_FILTER) {
+               asrc2_mask |= RT5670_DA_STO_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_DA_STO_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DA_STO_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_DA_MONO_L_FILTER) {
+               asrc2_mask |= RT5670_DA_MONOL_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_DA_MONOL_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DA_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_DA_MONO_R_FILTER) {
+               asrc2_mask |= RT5670_DA_MONOR_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_DA_MONOR_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DA_MONOR_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_AD_STEREO_FILTER) {
+               asrc2_mask |= RT5670_AD_STO1_CLK_SEL_MASK;
+               asrc2_value = (asrc2_value & ~RT5670_AD_STO1_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_AD_STO1_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_AD_MONO_L_FILTER) {
+               asrc3_mask |= RT5670_AD_MONOL_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_AD_MONOL_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_AD_MONOL_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_AD_MONO_R_FILTER)  {
+               asrc3_mask |= RT5670_AD_MONOR_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_AD_MONOR_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_AD_MONOR_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_UP_RATE_FILTER) {
+               asrc3_mask |= RT5670_UP_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_UP_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_UP_CLK_SEL_SFT);
+       }
+
+       if (filter_mask & RT5670_DOWN_RATE_FILTER) {
+               asrc3_mask |= RT5670_DOWN_CLK_SEL_MASK;
+               asrc3_value = (asrc3_value & ~RT5670_DOWN_CLK_SEL_MASK)
+                               | (clk_src <<  RT5670_DOWN_CLK_SEL_SFT);
+       }
+
+       if (asrc2_mask)
+               snd_soc_update_bits(codec, RT5670_ASRC_2,
+                                   asrc2_mask, asrc2_value);
+
+       if (asrc3_mask)
+               snd_soc_update_bits(codec, RT5670_ASRC_3,
+                                   asrc3_mask, asrc3_value);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rt5670_sel_asrc_clk_src);
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@ -1146,7 +1233,7 @@ static const struct snd_kcontrol_new rt5670_vad_adc_mux =
 static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1182,7 +1269,7 @@ static int rt5670_hp_power_event(struct snd_soc_dapm_widget *w,
 static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1232,7 +1319,7 @@ static int rt5670_hp_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1255,7 +1342,7 @@ static int rt5670_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5670_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -2188,6 +2275,13 @@ static int rt5670_set_dai_sysclk(struct snd_soc_dai *dai,
        if (freq == rt5670->sysclk && clk_id == rt5670->sysclk_src)
                return 0;
 
+       if (rt5670->pdata.jd_mode) {
+               if (clk_id == RT5670_SCLK_S_PLL1)
+                       snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1");
+               else
+                       snd_soc_dapm_disable_pin(&codec->dapm, "PLL1");
+               snd_soc_dapm_sync(&codec->dapm);
+       }
        switch (clk_id) {
        case RT5670_SCLK_S_MCLK:
                reg_val |= RT5670_SCLK_SRC_MCLK;
@@ -2549,6 +2643,17 @@ static struct acpi_device_id rt5670_acpi_match[] = {
 MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
 #endif
 
+static const struct dmi_system_id dmi_platform_intel_braswell[] = {
+       {
+               .ident = "Intel Braswell",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"),
+               },
+       },
+       {}
+};
+
 static int rt5670_i2c_probe(struct i2c_client *i2c,
                    const struct i2c_device_id *id)
 {
@@ -2568,6 +2673,12 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
        if (pdata)
                rt5670->pdata = *pdata;
 
+       if (dmi_check_system(dmi_platform_intel_braswell)) {
+               rt5670->pdata.dmic_en = true;
+               rt5670->pdata.dmic1_data_pin = RT5670_DMIC_DATA_IN2P;
+               rt5670->pdata.jd_mode = 1;
+       }
+
        rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
        if (IS_ERR(rt5670->regmap)) {
                ret = PTR_ERR(rt5670->regmap);
@@ -2609,6 +2720,10 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
        }
 
        if (rt5670->pdata.jd_mode) {
+               regmap_update_bits(rt5670->regmap, RT5670_GLB_CLK,
+                                  RT5670_SCLK_SRC_MASK, RT5670_SCLK_SRC_RCCLK);
+               rt5670->sysclk = 0;
+               rt5670->sysclk_src = RT5670_SCLK_S_RCCLK;
                regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG1,
                                   RT5670_PWR_MB, RT5670_PWR_MB);
                regmap_update_bits(rt5670->regmap, RT5670_PWR_ANLG2,
@@ -2716,18 +2831,26 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
 
        }
 
+       pm_runtime_enable(&i2c->dev);
+       pm_request_idle(&i2c->dev);
+
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5670,
                        rt5670_dai, ARRAY_SIZE(rt5670_dai));
        if (ret < 0)
                goto err;
 
+       pm_runtime_put(&i2c->dev);
+
        return 0;
 err:
+       pm_runtime_disable(&i2c->dev);
+
        return ret;
 }
 
 static int rt5670_i2c_remove(struct i2c_client *i2c)
 {
+       pm_runtime_disable(&i2c->dev);
        snd_soc_unregister_codec(&i2c->dev);
 
        return 0;
index d11b9c207e26799ba6cbb85cd3979ace7c76ea4d..21f8e18c13c48d606deb315b6abc82838029e14d 100644 (file)
 #define RT5670_DMIC_2_M_NOR                    (0x0 << 8)
 #define RT5670_DMIC_2_M_ASYN                   (0x1 << 8)
 
+/* ASRC clock source selection (0x84, 0x85) */
+#define RT5670_CLK_SEL_SYS                     (0x0)
+#define RT5670_CLK_SEL_I2S1_ASRC               (0x1)
+#define RT5670_CLK_SEL_I2S2_ASRC               (0x2)
+#define RT5670_CLK_SEL_I2S3_ASRC               (0x3)
+#define RT5670_CLK_SEL_SYS2                    (0x5)
+#define RT5670_CLK_SEL_SYS3                    (0x6)
+
 /* ASRC Control 2 (0x84) */
-#define RT5670_MDA_L_M_MASK                    (0x1 << 15)
-#define RT5670_MDA_L_M_SFT                     15
-#define RT5670_MDA_L_M_NOR                     (0x0 << 15)
-#define RT5670_MDA_L_M_ASYN                    (0x1 << 15)
-#define RT5670_MDA_R_M_MASK                    (0x1 << 14)
-#define RT5670_MDA_R_M_SFT                     14
-#define RT5670_MDA_R_M_NOR                     (0x0 << 14)
-#define RT5670_MDA_R_M_ASYN                    (0x1 << 14)
-#define RT5670_MAD_L_M_MASK                    (0x1 << 13)
-#define RT5670_MAD_L_M_SFT                     13
-#define RT5670_MAD_L_M_NOR                     (0x0 << 13)
-#define RT5670_MAD_L_M_ASYN                    (0x1 << 13)
-#define RT5670_MAD_R_M_MASK                    (0x1 << 12)
-#define RT5670_MAD_R_M_SFT                     12
-#define RT5670_MAD_R_M_NOR                     (0x0 << 12)
-#define RT5670_MAD_R_M_ASYN                    (0x1 << 12)
-#define RT5670_ADC_M_MASK                      (0x1 << 11)
-#define RT5670_ADC_M_SFT                       11
-#define RT5670_ADC_M_NOR                       (0x0 << 11)
-#define RT5670_ADC_M_ASYN                      (0x1 << 11)
-#define RT5670_STO_DAC_M_MASK                  (0x1 << 5)
-#define RT5670_STO_DAC_M_SFT                   5
-#define RT5670_STO_DAC_M_NOR                   (0x0 << 5)
-#define RT5670_STO_DAC_M_ASYN                  (0x1 << 5)
-#define RT5670_I2S1_R_D_MASK                   (0x1 << 4)
-#define RT5670_I2S1_R_D_SFT                    4
-#define RT5670_I2S1_R_D_DIS                    (0x0 << 4)
-#define RT5670_I2S1_R_D_EN                     (0x1 << 4)
-#define RT5670_I2S2_R_D_MASK                   (0x1 << 3)
-#define RT5670_I2S2_R_D_SFT                    3
-#define RT5670_I2S2_R_D_DIS                    (0x0 << 3)
-#define RT5670_I2S2_R_D_EN                     (0x1 << 3)
-#define RT5670_PRE_SCLK_MASK                   (0x3)
-#define RT5670_PRE_SCLK_SFT                    0
-#define RT5670_PRE_SCLK_512                    (0x0)
-#define RT5670_PRE_SCLK_1024                   (0x1)
-#define RT5670_PRE_SCLK_2048                   (0x2)
+#define RT5670_DA_STO_CLK_SEL_MASK             (0xf << 12)
+#define RT5670_DA_STO_CLK_SEL_SFT              12
+#define RT5670_DA_MONOL_CLK_SEL_MASK           (0xf << 8)
+#define RT5670_DA_MONOL_CLK_SEL_SFT            8
+#define RT5670_DA_MONOR_CLK_SEL_MASK           (0xf << 4)
+#define RT5670_DA_MONOR_CLK_SEL_SFT            4
+#define RT5670_AD_STO1_CLK_SEL_MASK            (0xf << 0)
+#define RT5670_AD_STO1_CLK_SEL_SFT             0
 
 /* ASRC Control 3 (0x85) */
-#define RT5670_I2S1_RATE_MASK                  (0xf << 12)
-#define RT5670_I2S1_RATE_SFT                   12
-#define RT5670_I2S2_RATE_MASK                  (0xf << 8)
-#define RT5670_I2S2_RATE_SFT                   8
+#define RT5670_UP_CLK_SEL_MASK                 (0xf << 12)
+#define RT5670_UP_CLK_SEL_SFT                  12
+#define RT5670_DOWN_CLK_SEL_MASK               (0xf << 8)
+#define RT5670_DOWN_CLK_SEL_SFT                        8
+#define RT5670_AD_MONOL_CLK_SEL_MASK           (0xf << 4)
+#define RT5670_AD_MONOL_CLK_SEL_SFT            4
+#define RT5670_AD_MONOR_CLK_SEL_MASK           (0xf << 0)
+#define RT5670_AD_MONOR_CLK_SEL_SFT            0
 
 /* ASRC Control 4 (0x89) */
 #define RT5670_I2S1_PD_MASK                    (0x7 << 12)
@@ -1983,6 +1966,21 @@ enum {
        RT5670_DMIC_DATA_GPIO5,
 };
 
+/* filter mask */
+enum {
+       RT5670_DA_STEREO_FILTER = 0x1,
+       RT5670_DA_MONO_L_FILTER = (0x1 << 1),
+       RT5670_DA_MONO_R_FILTER = (0x1 << 2),
+       RT5670_AD_STEREO_FILTER = (0x1 << 3),
+       RT5670_AD_MONO_L_FILTER = (0x1 << 4),
+       RT5670_AD_MONO_R_FILTER = (0x1 << 5),
+       RT5670_UP_RATE_FILTER   = (0x1 << 6),
+       RT5670_DOWN_RATE_FILTER = (0x1 << 7),
+};
+
+int rt5670_sel_asrc_clk_src(struct snd_soc_codec *codec,
+                           unsigned int filter_mask, unsigned int clk_src);
+
 struct rt5670_priv {
        struct snd_soc_codec *codec;
        struct rt5670_platform_data pdata;
index 81fe1464d2686661047aad6f2b9334f5d6a65c22..5d0bb8748dd1df5cd6a262d7e3a925fe4b4b5efd 100644 (file)
@@ -702,6 +702,9 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
        static bool activity;
        int ret;
 
+       if (!IS_ENABLED(CONFIG_SND_SOC_RT5677_SPI))
+               return -ENXIO;
+
        if (on && !activity) {
                activity = true;
 
@@ -784,8 +787,8 @@ static unsigned int bst_tlv[] = {
 static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
 
        ucontrol->value.integer.value[0] = rt5677->dsp_vad_en;
 
@@ -795,8 +798,9 @@ static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
 static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol)
 {
-       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+       struct rt5677_priv *rt5677 = snd_soc_component_get_drvdata(component);
+       struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
 
        rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
 
@@ -895,7 +899,7 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
 static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        int idx = rl6231_calc_dmic_clk(rt5677->sysclk);
 
@@ -910,7 +914,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        unsigned int val;
 
        regmap_read(rt5677->regmap, RT5677_GLB_CLK1, &val);
@@ -921,6 +926,101 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
                return 0;
 }
 
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg, shift, val;
+
+       if (source->reg == RT5677_ASRC_1) {
+               switch (source->shift) {
+               case 12:
+                       reg = RT5677_ASRC_4;
+                       shift = 0;
+                       break;
+               case 13:
+                       reg = RT5677_ASRC_4;
+                       shift = 4;
+                       break;
+               case 14:
+                       reg = RT5677_ASRC_4;
+                       shift = 8;
+                       break;
+               case 15:
+                       reg = RT5677_ASRC_4;
+                       shift = 12;
+                       break;
+               default:
+                       return 0;
+               }
+       } else {
+               switch (source->shift) {
+               case 0:
+                       reg = RT5677_ASRC_6;
+                       shift = 8;
+                       break;
+               case 1:
+                       reg = RT5677_ASRC_6;
+                       shift = 12;
+                       break;
+               case 2:
+                       reg = RT5677_ASRC_5;
+                       shift = 0;
+                       break;
+               case 3:
+                       reg = RT5677_ASRC_5;
+                       shift = 4;
+                       break;
+               case 4:
+                       reg = RT5677_ASRC_5;
+                       shift = 8;
+                       break;
+               case 5:
+                       reg = RT5677_ASRC_5;
+                       shift = 12;
+                       break;
+               case 12:
+                       reg = RT5677_ASRC_3;
+                       shift = 0;
+                       break;
+               case 13:
+                       reg = RT5677_ASRC_3;
+                       shift = 4;
+                       break;
+               case 14:
+                       reg = RT5677_ASRC_3;
+                       shift = 12;
+                       break;
+               default:
+                       return 0;
+               }
+       }
+
+       regmap_read(rt5677->regmap, reg, &val);
+       val = (val >> shift) & 0xf;
+
+       switch (val) {
+       case 1 ... 6:
+               return 1;
+       default:
+               return 0;
+       }
+
+}
+
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+                        struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+       if (rt5677->sysclk > rt5677->lrck[RT5677_AIF1] * 384)
+               return 1;
+
+       return 0;
+}
+
 /* Digital Mixer */
 static const struct snd_kcontrol_new rt5677_sto1_adc_l_mix[] = {
        SOC_DAPM_SINGLE("ADC1 Switch", RT5677_STO1_ADC_MIXER,
@@ -2030,7 +2130,7 @@ static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
 static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2054,7 +2154,7 @@ static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2078,14 +2178,18 @@ static int rt5677_bst2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_PRE_PMU:
                regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x2);
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
                regmap_update_bits(rt5677->regmap, RT5677_PLL1_CTRL2, 0x2, 0x0);
                break;
+
        default:
                return 0;
        }
@@ -2096,14 +2200,18 @@ static int rt5677_set_pll1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
-       case SND_SOC_DAPM_POST_PMU:
+       case SND_SOC_DAPM_PRE_PMU:
                regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x2);
+               break;
+
+       case SND_SOC_DAPM_POST_PMU:
                regmap_update_bits(rt5677->regmap, RT5677_PLL2_CTRL2, 0x2, 0x0);
                break;
+
        default:
                return 0;
        }
@@ -2114,7 +2222,7 @@ static int rt5677_set_pll2_event(struct snd_soc_dapm_widget *w,
 static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2141,7 +2249,7 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        unsigned int value;
 
@@ -2164,7 +2272,7 @@ static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
        unsigned int value;
 
@@ -2187,7 +2295,7 @@ static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
 static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -2211,9 +2319,50 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
 
 static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
        SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
-               0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU),
+               0, rt5677_set_pll1_event, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMU),
        SND_SOC_DAPM_SUPPLY("PLL2", RT5677_PWR_ANLG2, RT5677_PWR_PLL2_BIT,
-               0, rt5677_set_pll2_event, SND_SOC_DAPM_POST_PMU),
+               0, rt5677_set_pll2_event, SND_SOC_DAPM_PRE_PMU |
+               SND_SOC_DAPM_POST_PMU),
+
+       /* ASRC */
+       SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5677_ASRC_1, 0, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5677_ASRC_1, 1, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5677_ASRC_1, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("I2S4 ASRC", 1, RT5677_ASRC_1, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5677_ASRC_2, 14, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO2 L ASRC", 1, RT5677_ASRC_2, 13, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO2 R ASRC", 1, RT5677_ASRC_2, 12, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO3 L ASRC", 1, RT5677_ASRC_1, 15, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO3 R ASRC", 1, RT5677_ASRC_1, 14, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO4 L ASRC", 1, RT5677_ASRC_1, 13, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DAC MONO4 R ASRC", 1, RT5677_ASRC_1, 12, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5677_ASRC_2, 11, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5677_ASRC_2, 10, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO3 ASRC", 1, RT5677_ASRC_2, 9, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC STO4 ASRC", 1, RT5677_ASRC_2, 8, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5677_ASRC_2, 7, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5677_ASRC_2, 6, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5677_ASRC_2, 5, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5677_ASRC_2, 4, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO3 ASRC", 1, RT5677_ASRC_2, 3, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC STO4 ASRC", 1, RT5677_ASRC_2, 2, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5677_ASRC_2, 1, 0, NULL,
+               0),
+       SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5677_ASRC_2, 0, 0, NULL,
+               0),
 
        /* Input Side */
        /* micbias */
@@ -2645,10 +2794,18 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
        /* DAC Mixer */
        SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2,
                RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("dac mono left filter", RT5677_PWR_DIG2,
+       SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2,
                RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("dac mono right filter", RT5677_PWR_DIG2,
+       SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2,
                RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0),
+       SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2,
+               RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0),
 
        SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
                rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)),
@@ -2721,6 +2878,31 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
 };
 
 static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
+       { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
+       { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
+       { "Stereo3 DMIC Mux", NULL, "DMIC STO3 ASRC", can_use_asrc },
+       { "Stereo4 DMIC Mux", NULL, "DMIC STO4 ASRC", can_use_asrc },
+       { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
+       { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
+       { "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+       { "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
+       { "I2S3", NULL, "I2S3 ASRC", can_use_asrc},
+       { "I2S4", NULL, "I2S4 ASRC", can_use_asrc},
+
+       { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+       { "dac mono2 left filter", NULL, "DAC MONO2 L ASRC", is_using_asrc },
+       { "dac mono2 right filter", NULL, "DAC MONO2 R ASRC", is_using_asrc },
+       { "dac mono3 left filter", NULL, "DAC MONO3 L ASRC", is_using_asrc },
+       { "dac mono3 right filter", NULL, "DAC MONO3 R ASRC", is_using_asrc },
+       { "dac mono4 left filter", NULL, "DAC MONO4 L ASRC", is_using_asrc },
+       { "dac mono4 right filter", NULL, "DAC MONO4 R ASRC", is_using_asrc },
+       { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+       { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
+       { "adc stereo3 filter", NULL, "ADC STO3 ASRC", is_using_asrc },
+       { "adc stereo4 filter", NULL, "ADC STO4 ASRC", is_using_asrc },
+       { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+       { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+
        { "DMIC1", NULL, "DMIC L1" },
        { "DMIC1", NULL, "DMIC R1" },
        { "DMIC2", NULL, "DMIC L2" },
@@ -2851,8 +3033,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo1 ADC MIXL", NULL, "Sto1 ADC MIXL" },
        { "Stereo1 ADC MIXL", NULL, "adc stereo1 filter" },
-       { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo1 ADC MIXR", NULL, "Sto1 ADC MIXR" },
        { "Stereo1 ADC MIXR", NULL, "adc stereo1 filter" },
        { "adc stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -2873,8 +3053,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo2 ADC MIXL", NULL, "Stereo2 ADC LR Mux" },
        { "Stereo2 ADC MIXL", NULL, "adc stereo2 filter" },
-       { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo2 ADC MIXR", NULL, "Sto2 ADC MIXR" },
        { "Stereo2 ADC MIXR", NULL, "adc stereo2 filter" },
        { "adc stereo2 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -2889,8 +3067,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo3 ADC MIXL", NULL, "Sto3 ADC MIXL" },
        { "Stereo3 ADC MIXL", NULL, "adc stereo3 filter" },
-       { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo3 ADC MIXR", NULL, "Sto3 ADC MIXR" },
        { "Stereo3 ADC MIXR", NULL, "adc stereo3 filter" },
        { "adc stereo3 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -2905,8 +3081,6 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "Stereo4 ADC MIXL", NULL, "Sto4 ADC MIXL" },
        { "Stereo4 ADC MIXL", NULL, "adc stereo4 filter" },
-       { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
-
        { "Stereo4 ADC MIXR", NULL, "Sto4 ADC MIXR" },
        { "Stereo4 ADC MIXR", NULL, "adc stereo4 filter" },
        { "adc stereo4 filter", NULL, "PLL1", is_sys_clk_from_pll },
@@ -3455,10 +3629,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
 
        { "DAC1 MIXL", "Stereo ADC Switch", "ADDA1 Mux" },
        { "DAC1 MIXL", "DAC1 Switch", "DAC1 Mux" },
-       { "DAC1 MIXL", NULL, "dac stereo1 filter" },
        { "DAC1 MIXR", "Stereo ADC Switch", "ADDA1 Mux" },
        { "DAC1 MIXR", "DAC1 Switch", "DAC1 Mux" },
-       { "DAC1 MIXR", NULL, "dac stereo1 filter" },
 
        { "DAC1 FS", NULL, "DAC1 MIXL" },
        { "DAC1 FS", NULL, "DAC1 MIXR" },
@@ -3525,35 +3697,46 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "Stereo DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
        { "Stereo DAC MIXR", "DAC1 L Switch", "DAC1 MIXL" },
        { "Stereo DAC MIXR", NULL, "dac stereo1 filter" },
+       { "dac stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "Mono DAC MIXL", "ST L Switch", "Sidetone Mux" },
        { "Mono DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" },
        { "Mono DAC MIXL", "DAC2 L Switch", "DAC2 L Mux" },
        { "Mono DAC MIXL", "DAC2 R Switch", "DAC2 R Mux" },
-       { "Mono DAC MIXL", NULL, "dac mono left filter" },
+       { "Mono DAC MIXL", NULL, "dac mono2 left filter" },
+       { "dac mono2 left filter", NULL, "PLL1", is_sys_clk_from_pll },
        { "Mono DAC MIXR", "ST R Switch", "Sidetone Mux" },
        { "Mono DAC MIXR", "DAC1 R Switch", "DAC1 MIXR" },
        { "Mono DAC MIXR", "DAC2 R Switch", "DAC2 R Mux" },
        { "Mono DAC MIXR", "DAC2 L Switch", "DAC2 L Mux" },
-       { "Mono DAC MIXR", NULL, "dac mono right filter" },
+       { "Mono DAC MIXR", NULL, "dac mono2 right filter" },
+       { "dac mono2 right filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "DD1 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
        { "DD1 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
        { "DD1 MIXL", "DAC3 L Switch", "DAC3 L Mux" },
        { "DD1 MIXL", "DAC3 R Switch", "DAC3 R Mux" },
+       { "DD1 MIXL", NULL, "dac mono3 left filter" },
+       { "dac mono3 left filter", NULL, "PLL1", is_sys_clk_from_pll },
        { "DD1 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
        { "DD1 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
        { "DD1 MIXR", "DAC3 L Switch", "DAC3 L Mux" },
        { "DD1 MIXR", "DAC3 R Switch", "DAC3 R Mux" },
+       { "DD1 MIXR", NULL, "dac mono3 right filter" },
+       { "dac mono3 right filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "DD2 MIXL", "Sto DAC Mix L Switch", "Stereo DAC MIXL" },
        { "DD2 MIXL", "Mono DAC Mix L Switch", "Mono DAC MIXL" },
        { "DD2 MIXL", "DAC4 L Switch", "DAC4 L Mux" },
        { "DD2 MIXL", "DAC4 R Switch", "DAC4 R Mux" },
+       { "DD2 MIXL", NULL, "dac mono4 left filter" },
+       { "dac mono4 left filter", NULL, "PLL1", is_sys_clk_from_pll },
        { "DD2 MIXR", "Sto DAC Mix R Switch", "Stereo DAC MIXR" },
        { "DD2 MIXR", "Mono DAC Mix R Switch", "Mono DAC MIXR" },
        { "DD2 MIXR", "DAC4 L Switch", "DAC4 L Mux" },
        { "DD2 MIXR", "DAC4 R Switch", "DAC4 R Mux" },
+       { "DD2 MIXR", NULL, "dac mono4 right filter" },
+       { "dac mono4 right filter", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "Stereo DAC MIX", NULL, "Stereo DAC MIXL" },
        { "Stereo DAC MIX", NULL, "Stereo DAC MIXR" },
@@ -3575,11 +3758,8 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
        { "DAC3 SRC Mux", "DD MIX2L", "DD2 MIXL" },
 
        { "DAC 1", NULL, "DAC12 SRC Mux" },
-       { "DAC 1", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC 2", NULL, "DAC12 SRC Mux" },
-       { "DAC 2", NULL, "PLL1", is_sys_clk_from_pll },
        { "DAC 3", NULL, "DAC3 SRC Mux" },
-       { "DAC 3", NULL, "PLL1", is_sys_clk_from_pll },
 
        { "PDM1 L Mux", "STO1 DAC MIX", "Stereo DAC MIXL" },
        { "PDM1 L Mux", "MONO DAC MIX", "Mono DAC MIXL" },
@@ -3926,7 +4106,8 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
                        unsigned int rx_mask, int slots, int slot_width)
 {
        struct snd_soc_codec *codec = dai->codec;
-       unsigned int val = 0;
+       struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+       unsigned int val = 0, slot_width_25 = 0;
 
        if (rx_mask || tx_mask)
                val |= (1 << 12);
@@ -3950,6 +4131,8 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
        case 20:
                val |= (1 << 8);
                break;
+       case 25:
+               slot_width_25 = 0x8080;
        case 24:
                val |= (2 << 8);
                break;
@@ -3963,10 +4146,16 @@ static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
 
        switch (dai->id) {
        case RT5677_AIF1:
-               snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val);
+               regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, 0x1f00,
+                       val);
+               regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x8000,
+                       slot_width_25);
                break;
        case RT5677_AIF2:
-               snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val);
+               regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, 0x1f00,
+                       val);
+               regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x80,
+                       slot_width_25);
                break;
        default:
                break;
@@ -4751,6 +4940,11 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
                                        RT5677_GPIO5_DIR_OUT);
        }
 
+       if (rt5677->pdata.micbias1_vdd_3v3)
+               regmap_update_bits(rt5677->regmap, RT5677_MICBIAS,
+                       RT5677_MICBIAS1_CTRL_VDD_MASK,
+                       RT5677_MICBIAS1_CTRL_VDD_3_3V);
+
        rt5677_init_gpio(i2c);
        rt5677_init_irq(i2c);
 
index 29cf7ce610f4707feeaba22425daedbe50491ba4..e182e6569bbd138713ec0047de606136254d81c4 100644 (file)
@@ -155,18 +155,19 @@ struct sgtl5000_priv {
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* change mic bias resistor */
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+               snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
                        SGTL5000_BIAS_R_MASK,
                        sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
+               snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
                                SGTL5000_BIAS_R_MASK, 0);
                break;
        }
@@ -181,11 +182,12 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
 static int power_vag_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        const u32 mask = SGTL5000_DAC_POWERUP | SGTL5000_ADC_POWERUP;
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+               snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                        SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
                break;
 
@@ -195,9 +197,9 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
                 * operational to prevent inadvertently starving the
                 * other one of them.
                 */
-               if ((snd_soc_read(w->codec, SGTL5000_CHIP_ANA_POWER) &
+               if ((snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER) &
                                mask) != mask) {
-                       snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER,
+                       snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                                SGTL5000_VAG_POWERUP, 0);
                        msleep(400);
                }
@@ -483,21 +485,21 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        /* setting i2s data format */
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_DSP_A:
-               i2sctl |= SGTL5000_I2S_MODE_PCM;
+               i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT;
                break;
        case SND_SOC_DAIFMT_DSP_B:
-               i2sctl |= SGTL5000_I2S_MODE_PCM;
+               i2sctl |= SGTL5000_I2S_MODE_PCM << SGTL5000_I2S_MODE_SHIFT;
                i2sctl |= SGTL5000_I2S_LRALIGN;
                break;
        case SND_SOC_DAIFMT_I2S:
-               i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
+               i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               i2sctl |= SGTL5000_I2S_MODE_RJ;
+               i2sctl |= SGTL5000_I2S_MODE_RJ << SGTL5000_I2S_MODE_SHIFT;
                i2sctl |= SGTL5000_I2S_LRPOL;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
+               i2sctl |= SGTL5000_I2S_MODE_I2S_LJ << SGTL5000_I2S_MODE_SHIFT;
                i2sctl |= SGTL5000_I2S_LRALIGN;
                break;
        default:
@@ -1462,6 +1464,9 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
        if (ret)
                return ret;
 
+       /* Need 8 clocks before I2C accesses */
+       udelay(1);
+
        /* read chip information */
        ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, &reg);
        if (ret)
index 1f451a1946eb259c4734b68a2e2f273279c35dec..47b257e4180965f38be5c393cab204945f444b7f 100644 (file)
@@ -233,16 +233,18 @@ static int sn95031_set_vaud_bias(struct snd_soc_codec *codec,
 static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
                /* power up the rail */
-               snd_soc_write(w->codec, SN95031_VHSP, 0x3D);
-               snd_soc_write(w->codec, SN95031_VHSN, 0x3F);
+               snd_soc_write(codec, SN95031_VHSP, 0x3D);
+               snd_soc_write(codec, SN95031_VHSN, 0x3F);
                msleep(1);
        } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
                pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-               snd_soc_write(w->codec, SN95031_VHSP, 0xC4);
-               snd_soc_write(w->codec, SN95031_VHSN, 0x04);
+               snd_soc_write(codec, SN95031_VHSP, 0xC4);
+               snd_soc_write(codec, SN95031_VHSN, 0x04);
        }
        return 0;
 }
@@ -250,14 +252,16 @@ static int sn95031_vhs_event(struct snd_soc_dapm_widget *w,
 static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        if (SND_SOC_DAPM_EVENT_ON(event)) {
                pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n");
                /* power up the rail */
-               snd_soc_write(w->codec, SN95031_VIHF, 0x27);
+               snd_soc_write(codec, SN95031_VIHF, 0x27);
                msleep(1);
        } else if (SND_SOC_DAPM_EVENT_OFF(event)) {
                pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n");
-               snd_soc_write(w->codec, SN95031_VIHF, 0x24);
+               snd_soc_write(codec, SN95031_VIHF, 0x24);
        }
        return 0;
 }
@@ -265,6 +269,7 @@ static int sn95031_vihf_event(struct snd_soc_dapm_widget *w,
 static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -273,15 +278,16 @@ static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w,
                data_dir = BIT(7);
        }
        /* program DMIC LDO, clock and set clock */
-       snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(7), data_dir);
+       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+       snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(0), clk_dir);
+       snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(7), data_dir);
        return 0;
 }
 
 static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int ldo = 0, clk_dir = 0, data_dir = 0;
 
        if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -290,22 +296,23 @@ static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w,
                data_dir = BIT(1);
        }
        /* program DMIC LDO, clock and set clock */
-       snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
-       snd_soc_update_bits(w->codec, SN95031_DMICBUF45, BIT(1), data_dir);
+       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo);
+       snd_soc_update_bits(codec, SN95031_DMICBUF0123, BIT(2), clk_dir);
+       snd_soc_update_bits(codec, SN95031_DMICBUF45, BIT(1), data_dir);
        return 0;
 }
 
 static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *k, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int ldo = 0;
 
        if (SND_SOC_DAPM_EVENT_ON(event))
                ldo = BIT(7)|BIT(6);
 
        /* program DMIC LDO */
-       snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
+       snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo);
        return 0;
 }
 
index 7e18200dd6a9f5b29469dedf6bbdc26cd9bc8032..3a1343fa109b482860811baea1566d354e574399 100644 (file)
 #include <linux/delay.h>
 #include <linux/pm.h>
 #include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <sound/core.h>
@@ -102,6 +105,35 @@ static const struct reg_default sta32x_regs[] = {
        { 0x2c, 0x0c },
 };
 
+static const struct regmap_range sta32x_write_regs_range[] = {
+       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
+       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_read_regs_range[] = {
+       regmap_reg_range(STA32X_CONFA,  STA32X_AUTO2),
+       regmap_reg_range(STA32X_C1CFG,  STA32X_FDRC2),
+};
+
+static const struct regmap_range sta32x_volatile_regs_range[] = {
+       regmap_reg_range(STA32X_CFADDR2, STA32X_CFUD),
+};
+
+static const struct regmap_access_table sta32x_write_regs = {
+       .yes_ranges =   sta32x_write_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta32x_write_regs_range),
+};
+
+static const struct regmap_access_table sta32x_read_regs = {
+       .yes_ranges =   sta32x_read_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta32x_read_regs_range),
+};
+
+static const struct regmap_access_table sta32x_volatile_regs = {
+       .yes_ranges =   sta32x_volatile_regs_range,
+       .n_yes_ranges = ARRAY_SIZE(sta32x_volatile_regs_range),
+};
+
 /* regulator power supply names */
 static const char *sta32x_supply_names[] = {
        "Vdda", /* analog supply, 3.3VV */
@@ -122,6 +154,8 @@ struct sta32x_priv {
        u32 coef_shadow[STA32X_COEF_COUNT];
        struct delayed_work watchdog_work;
        int shutdown;
+       struct gpio_desc *gpiod_nreset;
+       struct mutex coeff_lock;
 };
 
 static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1);
@@ -155,37 +189,32 @@ static const char *sta32x_limiter_release_rate[] = {
        "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299",
        "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137",
        "0.0134", "0.0117", "0.0110", "0.0104" };
-
-static const unsigned int sta32x_limiter_ac_attack_tlv[] = {
-       TLV_DB_RANGE_HEAD(2),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_attack_tlv,
        0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0),
        8, 16, TLV_DB_SCALE_ITEM(300, 100, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_ac_release_tlv[] = {
-       TLV_DB_RANGE_HEAD(5),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_ac_release_tlv,
        0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
        1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0),
        2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0),
        3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0),
        8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_drc_attack_tlv[] = {
-       TLV_DB_RANGE_HEAD(3),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_attack_tlv,
        0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0),
        8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0),
        14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0),
-};
+);
 
-static const unsigned int sta32x_limiter_drc_release_tlv[] = {
-       TLV_DB_RANGE_HEAD(5),
+static DECLARE_TLV_DB_RANGE(sta32x_limiter_drc_release_tlv,
        0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0),
        1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0),
        3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0),
        5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0),
        13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0),
-};
+);
 
 static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum,
                            STA32X_CONFD, STA32X_CONFD_DRC_SHIFT,
@@ -244,29 +273,42 @@ static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol,
                                  struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+       struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
        int numcoef = kcontrol->private_value >> 16;
        int index = kcontrol->private_value & 0xffff;
-       unsigned int cfud;
-       int i;
+       unsigned int cfud, val;
+       int i, ret = 0;
+
+       mutex_lock(&sta32x->coeff_lock);
 
        /* preserve reserved bits in STA32X_CFUD */
-       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
-       /* chip documentation does not say if the bits are self clearing,
-        * so do it explicitly */
-       snd_soc_write(codec, STA32X_CFUD, cfud);
+       regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+       cfud &= 0xf0;
+       /*
+        * chip documentation does not say if the bits are self clearing,
+        * so do it explicitly
+        */
+       regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
 
-       snd_soc_write(codec, STA32X_CFADDR2, index);
-       if (numcoef == 1)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x04);
-       else if (numcoef == 5)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x08);
-       else
-               return -EINVAL;
-       for (i = 0; i < 3 * numcoef; i++)
-               ucontrol->value.bytes.data[i] =
-                       snd_soc_read(codec, STA32X_B1CF1 + i);
+       regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
+       if (numcoef == 1) {
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x04);
+       } else if (numcoef == 5) {
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x08);
+       } else {
+               ret = -EINVAL;
+               goto exit_unlock;
+       }
 
-       return 0;
+       for (i = 0; i < 3 * numcoef; i++) {
+               regmap_read(sta32x->regmap, STA32X_B1CF1 + i, &val);
+               ucontrol->value.bytes.data[i] = val;
+       }
+
+exit_unlock:
+       mutex_unlock(&sta32x->coeff_lock);
+
+       return ret;
 }
 
 static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
@@ -280,24 +322,27 @@ static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol,
        int i;
 
        /* preserve reserved bits in STA32X_CFUD */
-       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
-       /* chip documentation does not say if the bits are self clearing,
-        * so do it explicitly */
-       snd_soc_write(codec, STA32X_CFUD, cfud);
+       regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+       cfud &= 0xf0;
+       /*
+        * chip documentation does not say if the bits are self clearing,
+        * so do it explicitly
+        */
+       regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
 
-       snd_soc_write(codec, STA32X_CFADDR2, index);
+       regmap_write(sta32x->regmap, STA32X_CFADDR2, index);
        for (i = 0; i < numcoef && (index + i < STA32X_COEF_COUNT); i++)
                sta32x->coef_shadow[index + i] =
                          (ucontrol->value.bytes.data[3 * i] << 16)
                        | (ucontrol->value.bytes.data[3 * i + 1] << 8)
                        | (ucontrol->value.bytes.data[3 * i + 2]);
        for (i = 0; i < 3 * numcoef; i++)
-               snd_soc_write(codec, STA32X_B1CF1 + i,
-                             ucontrol->value.bytes.data[i]);
+               regmap_write(sta32x->regmap, STA32X_B1CF1 + i,
+                            ucontrol->value.bytes.data[i]);
        if (numcoef == 1)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
        else if (numcoef == 5)
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x02);
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x02);
        else
                return -EINVAL;
 
@@ -311,20 +356,23 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec)
        int i;
 
        /* preserve reserved bits in STA32X_CFUD */
-       cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0;
+       regmap_read(sta32x->regmap, STA32X_CFUD, &cfud);
+       cfud &= 0xf0;
 
        for (i = 0; i < STA32X_COEF_COUNT; i++) {
-               snd_soc_write(codec, STA32X_CFADDR2, i);
-               snd_soc_write(codec, STA32X_B1CF1,
-                             (sta32x->coef_shadow[i] >> 16) & 0xff);
-               snd_soc_write(codec, STA32X_B1CF2,
-                             (sta32x->coef_shadow[i] >> 8) & 0xff);
-               snd_soc_write(codec, STA32X_B1CF3,
-                             (sta32x->coef_shadow[i]) & 0xff);
-               /* chip documentation does not say if the bits are
-                * self-clearing, so do it explicitly */
-               snd_soc_write(codec, STA32X_CFUD, cfud);
-               snd_soc_write(codec, STA32X_CFUD, cfud | 0x01);
+               regmap_write(sta32x->regmap, STA32X_CFADDR2, i);
+               regmap_write(sta32x->regmap, STA32X_B1CF1,
+                            (sta32x->coef_shadow[i] >> 16) & 0xff);
+               regmap_write(sta32x->regmap, STA32X_B1CF2,
+                            (sta32x->coef_shadow[i] >> 8) & 0xff);
+               regmap_write(sta32x->regmap, STA32X_B1CF3,
+                            (sta32x->coef_shadow[i]) & 0xff);
+               /*
+                * chip documentation does not say if the bits are
+                * self-clearing, so do it explicitly
+                */
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud);
+               regmap_write(sta32x->regmap, STA32X_CFUD, cfud | 0x01);
        }
        return 0;
 }
@@ -336,11 +384,11 @@ static int sta32x_cache_sync(struct snd_soc_codec *codec)
        int rc;
 
        /* mute during register sync */
-       mute = snd_soc_read(codec, STA32X_MMUTE);
-       snd_soc_write(codec, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
+       regmap_read(sta32x->regmap, STA32X_MMUTE, &mute);
+       regmap_write(sta32x->regmap, STA32X_MMUTE, mute | STA32X_MMUTE_MMUTE);
        sta32x_sync_coef_shadow(codec);
        rc = regcache_sync(sta32x->regmap);
-       snd_soc_write(codec, STA32X_MMUTE, mute);
+       regmap_write(sta32x->regmap, STA32X_MMUTE, mute);
        return rc;
 }
 
@@ -508,17 +556,12 @@ static struct {
 };
 
 /* MCLK to fs clock ratios */
-static struct {
-       int ratio;
-       int mcs;
-} mclk_ratios[3][7] = {
-       { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 },
-         { 128, 4 }, { 576, 5 }, { 0, 0 } },
-       { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
-       { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } },
+static int mcs_ratio_table[3][7] = {
+       { 768, 512, 384, 256, 128, 576, 0 },
+       { 384, 256, 192, 128,  64,   0 },
+       { 384, 256, 192, 128,  64,   0 },
 };
 
-
 /**
  * sta32x_set_dai_sysclk - configure MCLK
  * @codec_dai: the codec DAI
@@ -543,46 +586,10 @@ static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       int i, j, ir, fs;
-       unsigned int rates = 0;
-       unsigned int rate_min = -1;
-       unsigned int rate_max = 0;
 
-       pr_debug("mclk=%u\n", freq);
+       dev_dbg(codec->dev, "mclk=%u\n", freq);
        sta32x->mclk = freq;
 
-       if (sta32x->mclk) {
-               for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
-                       ir = interpolation_ratios[i].ir;
-                       fs = interpolation_ratios[i].fs;
-                       for (j = 0; mclk_ratios[ir][j].ratio; j++) {
-                               if (mclk_ratios[ir][j].ratio * fs == freq) {
-                                       rates |= snd_pcm_rate_to_rate_bit(fs);
-                                       if (fs < rate_min)
-                                               rate_min = fs;
-                                       if (fs > rate_max)
-                                               rate_max = fs;
-                                       break;
-                               }
-                       }
-               }
-               /* FIXME: soc should support a rate list */
-               rates &= ~SNDRV_PCM_RATE_KNOT;
-
-               if (!rates) {
-                       dev_err(codec->dev, "could not find a valid sample rate\n");
-                       return -EINVAL;
-               }
-       } else {
-               /* enable all possible rates */
-               rates = STA32X_RATES;
-               rate_min = 32000;
-               rate_max = 192000;
-       }
-
-       codec_dai->driver->playback.rates = rates;
-       codec_dai->driver->playback.rate_min = rate_min;
-       codec_dai->driver->playback.rate_max = rate_max;
        return 0;
 }
 
@@ -599,10 +606,7 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_codec *codec = codec_dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       u8 confb = snd_soc_read(codec, STA32X_CONFB);
-
-       pr_debug("\n");
-       confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM);
+       u8 confb = 0;
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBS_CFS:
@@ -632,8 +636,8 @@ static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       snd_soc_write(codec, STA32X_CONFB, confb);
-       return 0;
+       return regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+                                 STA32X_CONFB_C1IM | STA32X_CONFB_C2IM, confb);
 }
 
 /**
@@ -651,39 +655,55 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
-       unsigned int rate;
-       int i, mcs = -1, ir = -1;
-       u8 confa, confb;
+       int i, mcs = -EINVAL, ir = -EINVAL;
+       unsigned int confa, confb;
+       unsigned int rate, ratio;
+       int ret;
+
+       if (!sta32x->mclk) {
+               dev_err(codec->dev,
+                       "sta32x->mclk is unset. Unable to determine ratio\n");
+               return -EIO;
+       }
 
        rate = params_rate(params);
-       pr_debug("rate: %u\n", rate);
-       for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
+       ratio = sta32x->mclk / rate;
+       dev_dbg(codec->dev, "rate: %u, ratio: %u\n", rate, ratio);
+
+       for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) {
                if (interpolation_ratios[i].fs == rate) {
                        ir = interpolation_ratios[i].ir;
                        break;
                }
-       if (ir < 0)
+       }
+
+       if (ir < 0) {
+               dev_err(codec->dev, "Unsupported samplerate: %u\n", rate);
                return -EINVAL;
-       for (i = 0; mclk_ratios[ir][i].ratio; i++)
-               if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
-                       mcs = mclk_ratios[ir][i].mcs;
+       }
+
+       for (i = 0; i < 6; i++) {
+               if (mcs_ratio_table[ir][i] == ratio) {
+                       mcs = i;
                        break;
                }
-       if (mcs < 0)
+       }
+
+       if (mcs < 0) {
+               dev_err(codec->dev, "Unresolvable ratio: %u\n", ratio);
                return -EINVAL;
+       }
 
-       confa = snd_soc_read(codec, STA32X_CONFA);
-       confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK);
-       confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT);
+       confa = (ir << STA32X_CONFA_IR_SHIFT) |
+               (mcs << STA32X_CONFA_MCS_SHIFT);
+       confb = 0;
 
-       confb = snd_soc_read(codec, STA32X_CONFB);
-       confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB);
        switch (params_width(params)) {
        case 24:
-               pr_debug("24bit\n");
+               dev_dbg(codec->dev, "24bit\n");
                /* fall through */
        case 32:
-               pr_debug("24bit or 32bit\n");
+               dev_dbg(codec->dev, "24bit or 32bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x0;
@@ -698,7 +718,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
                break;
        case 20:
-               pr_debug("20bit\n");
+               dev_dbg(codec->dev, "20bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x4;
@@ -713,7 +733,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
                break;
        case 18:
-               pr_debug("18bit\n");
+               dev_dbg(codec->dev, "18bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x8;
@@ -728,7 +748,7 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
 
                break;
        case 16:
-               pr_debug("16bit\n");
+               dev_dbg(codec->dev, "16bit\n");
                switch (sta32x->format) {
                case SND_SOC_DAIFMT_I2S:
                        confb |= 0x0;
@@ -746,8 +766,30 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       snd_soc_write(codec, STA32X_CONFA, confa);
-       snd_soc_write(codec, STA32X_CONFB, confb);
+       ret = regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+                                STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK,
+                                confa);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_update_bits(sta32x->regmap, STA32X_CONFB,
+                                STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB,
+                                confb);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int sta32x_startup_sequence(struct sta32x_priv *sta32x)
+{
+       if (sta32x->gpiod_nreset) {
+               gpiod_set_value(sta32x->gpiod_nreset, 0);
+               mdelay(1);
+               gpiod_set_value(sta32x->gpiod_nreset, 1);
+               mdelay(1);
+       }
+
        return 0;
 }
 
@@ -766,14 +808,14 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
        int ret;
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
 
-       pr_debug("level = %d\n", level);
+       dev_dbg(codec->dev, "level = %d\n", level);
        switch (level) {
        case SND_SOC_BIAS_ON:
                break;
 
        case SND_SOC_BIAS_PREPARE:
                /* Full power on */
-               snd_soc_update_bits(codec, STA32X_CONFF,
+               regmap_update_bits(sta32x->regmap, STA32X_CONFF,
                                    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
                                    STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
                break;
@@ -788,25 +830,28 @@ static int sta32x_set_bias_level(struct snd_soc_codec *codec,
                                return ret;
                        }
 
+                       sta32x_startup_sequence(sta32x);
                        sta32x_cache_sync(codec);
                        sta32x_watchdog_start(sta32x);
                }
 
-               /* Power up to mute */
-               /* FIXME */
-               snd_soc_update_bits(codec, STA32X_CONFF,
-                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD);
+               /* Power down */
+               regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                                  STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
+                                  0);
 
                break;
 
        case SND_SOC_BIAS_OFF:
                /* The chip runs through the power down sequence for us. */
-               snd_soc_update_bits(codec, STA32X_CONFF,
-                                   STA32X_CONFF_PWDN | STA32X_CONFF_EAPD,
-                                   STA32X_CONFF_PWDN);
+               regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                                  STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, 0);
                msleep(300);
                sta32x_watchdog_stop(sta32x);
+
+               if (sta32x->gpiod_nreset)
+                       gpiod_set_value(sta32x->gpiod_nreset, 0);
+
                regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies),
                                       sta32x->supplies);
                break;
@@ -822,7 +867,7 @@ static const struct snd_soc_dai_ops sta32x_dai_ops = {
 };
 
 static struct snd_soc_dai_driver sta32x_dai = {
-       .name = "STA32X",
+       .name = "sta32x-hifi",
        .playback = {
                .stream_name = "Playback",
                .channels_min = 2,
@@ -836,11 +881,8 @@ static struct snd_soc_dai_driver sta32x_dai = {
 static int sta32x_probe(struct snd_soc_codec *codec)
 {
        struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
+       struct sta32x_platform_data *pdata = sta32x->pdata;
        int i, ret = 0, thermal = 0;
-
-       sta32x->codec = codec;
-       sta32x->pdata = dev_get_platdata(codec->dev);
-
        ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies),
                                    sta32x->supplies);
        if (ret != 0) {
@@ -848,50 +890,73 @@ static int sta32x_probe(struct snd_soc_codec *codec)
                return ret;
        }
 
-       /* Chip documentation explicitly requires that the reset values
-        * of reserved register bits are left untouched.
-        * Write the register default value to cache for reserved registers,
-        * so the write to the these registers are suppressed by the cache
-        * restore code when it skips writes of default registers.
-        */
-       regcache_cache_only(sta32x->regmap, true);
-       snd_soc_write(codec, STA32X_CONFC, 0xc2);
-       snd_soc_write(codec, STA32X_CONFE, 0xc2);
-       snd_soc_write(codec, STA32X_CONFF, 0x5c);
-       snd_soc_write(codec, STA32X_MMUTE, 0x10);
-       snd_soc_write(codec, STA32X_AUTO1, 0x60);
-       snd_soc_write(codec, STA32X_AUTO3, 0x00);
-       snd_soc_write(codec, STA32X_C3CFG, 0x40);
-       regcache_cache_only(sta32x->regmap, false);
-
-       /* set thermal warning adjustment and recovery */
-       if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_ADJUSTMENT_ENABLE))
+       ret = sta32x_startup_sequence(sta32x);
+       if (ret < 0) {
+               dev_err(codec->dev, "Failed to startup device\n");
+               return ret;
+       }
+
+       /* CONFA */
+       if (!pdata->thermal_warning_recovery)
                thermal |= STA32X_CONFA_TWAB;
-       if (!(sta32x->pdata->thermal_conf & STA32X_THERMAL_RECOVERY_ENABLE))
+       if (!pdata->thermal_warning_adjustment)
                thermal |= STA32X_CONFA_TWRB;
-       snd_soc_update_bits(codec, STA32X_CONFA,
-                           STA32X_CONFA_TWAB | STA32X_CONFA_TWRB,
-                           thermal);
+       if (!pdata->fault_detect_recovery)
+               thermal |= STA32X_CONFA_FDRB;
+       regmap_update_bits(sta32x->regmap, STA32X_CONFA,
+                          STA32X_CONFA_TWAB | STA32X_CONFA_TWRB |
+                          STA32X_CONFA_FDRB,
+                          thermal);
+
+       /* CONFC */
+       regmap_update_bits(sta32x->regmap, STA32X_CONFC,
+                          STA32X_CONFC_CSZ_MASK,
+                          pdata->drop_compensation_ns
+                               << STA32X_CONFC_CSZ_SHIFT);
+
+       /* CONFE */
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_MPCV,
+                          pdata->max_power_use_mpcc ?
+                               STA32X_CONFE_MPCV : 0);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_MPC,
+                          pdata->max_power_correction ?
+                               STA32X_CONFE_MPC : 0);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_AME,
+                          pdata->am_reduction_mode ?
+                               STA32X_CONFE_AME : 0);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFE,
+                          STA32X_CONFE_PWMS,
+                          pdata->odd_pwm_speed_mode ?
+                               STA32X_CONFE_PWMS : 0);
+
+       /*  CONFF */
+       regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                          STA32X_CONFF_IDE,
+                          pdata->invalid_input_detect_mute ?
+                               STA32X_CONFF_IDE : 0);
 
        /* select output configuration  */
-       snd_soc_update_bits(codec, STA32X_CONFF,
-                           STA32X_CONFF_OCFG_MASK,
-                           sta32x->pdata->output_conf
-                           << STA32X_CONFF_OCFG_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_CONFF,
+                          STA32X_CONFF_OCFG_MASK,
+                          pdata->output_conf
+                               << STA32X_CONFF_OCFG_SHIFT);
 
        /* channel to output mapping */
-       snd_soc_update_bits(codec, STA32X_C1CFG,
-                           STA32X_CxCFG_OM_MASK,
-                           sta32x->pdata->ch1_output_mapping
-                           << STA32X_CxCFG_OM_SHIFT);
-       snd_soc_update_bits(codec, STA32X_C2CFG,
-                           STA32X_CxCFG_OM_MASK,
-                           sta32x->pdata->ch2_output_mapping
-                           << STA32X_CxCFG_OM_SHIFT);
-       snd_soc_update_bits(codec, STA32X_C3CFG,
-                           STA32X_CxCFG_OM_MASK,
-                           sta32x->pdata->ch3_output_mapping
-                           << STA32X_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_C1CFG,
+                          STA32X_CxCFG_OM_MASK,
+                          pdata->ch1_output_mapping
+                               << STA32X_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_C2CFG,
+                          STA32X_CxCFG_OM_MASK,
+                          pdata->ch2_output_mapping
+                               << STA32X_CxCFG_OM_SHIFT);
+       regmap_update_bits(sta32x->regmap, STA32X_C3CFG,
+                          STA32X_CxCFG_OM_MASK,
+                          pdata->ch3_output_mapping
+                               << STA32X_CxCFG_OM_SHIFT);
 
        /* initialize coefficient shadow RAM with reset values */
        for (i = 4; i <= 49; i += 5)
@@ -924,16 +989,6 @@ static int sta32x_remove(struct snd_soc_codec *codec)
        return 0;
 }
 
-static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
-{
-       switch (reg) {
-       case STA32X_CONFA ... STA32X_L2ATRT:
-       case STA32X_MPCC1 ... STA32X_FDRC2:
-               return 0;
-       }
-       return 1;
-}
-
 static const struct snd_soc_codec_driver sta32x_codec = {
        .probe =                sta32x_probe,
        .remove =               sta32x_remove,
@@ -954,12 +1009,75 @@ static const struct regmap_config sta32x_regmap = {
        .reg_defaults =         sta32x_regs,
        .num_reg_defaults =     ARRAY_SIZE(sta32x_regs),
        .cache_type =           REGCACHE_RBTREE,
-       .volatile_reg =         sta32x_reg_is_volatile,
+       .wr_table =             &sta32x_write_regs,
+       .rd_table =             &sta32x_read_regs,
+       .volatile_table =       &sta32x_volatile_regs,
 };
 
+#ifdef CONFIG_OF
+static const struct of_device_id st32x_dt_ids[] = {
+       { .compatible = "st,sta32x", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, st32x_dt_ids);
+
+static int sta32x_probe_dt(struct device *dev, struct sta32x_priv *sta32x)
+{
+       struct device_node *np = dev->of_node;
+       struct sta32x_platform_data *pdata;
+       u16 tmp;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       of_property_read_u8(np, "st,output-conf",
+                           &pdata->output_conf);
+       of_property_read_u8(np, "st,ch1-output-mapping",
+                           &pdata->ch1_output_mapping);
+       of_property_read_u8(np, "st,ch2-output-mapping",
+                           &pdata->ch2_output_mapping);
+       of_property_read_u8(np, "st,ch3-output-mapping",
+                           &pdata->ch3_output_mapping);
+
+       if (of_get_property(np, "st,thermal-warning-recovery", NULL))
+               pdata->thermal_warning_recovery = 1;
+       if (of_get_property(np, "st,thermal-warning-adjustment", NULL))
+               pdata->thermal_warning_adjustment = 1;
+       if (of_get_property(np, "st,needs_esd_watchdog", NULL))
+               pdata->needs_esd_watchdog = 1;
+
+       tmp = 140;
+       of_property_read_u16(np, "st,drop-compensation-ns", &tmp);
+       pdata->drop_compensation_ns = clamp_t(u16, tmp, 0, 300) / 20;
+
+       /* CONFE */
+       if (of_get_property(np, "st,max-power-use-mpcc", NULL))
+               pdata->max_power_use_mpcc = 1;
+
+       if (of_get_property(np, "st,max-power-correction", NULL))
+               pdata->max_power_correction = 1;
+
+       if (of_get_property(np, "st,am-reduction-mode", NULL))
+               pdata->am_reduction_mode = 1;
+
+       if (of_get_property(np, "st,odd-pwm-speed-mode", NULL))
+               pdata->odd_pwm_speed_mode = 1;
+
+       /* CONFF */
+       if (of_get_property(np, "st,invalid-input-detect-mute", NULL))
+               pdata->invalid_input_detect_mute = 1;
+
+       sta32x->pdata = pdata;
+
+       return 0;
+}
+#endif
+
 static int sta32x_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
+       struct device *dev = &i2c->dev;
        struct sta32x_priv *sta32x;
        int ret, i;
 
@@ -968,6 +1086,29 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
        if (!sta32x)
                return -ENOMEM;
 
+       mutex_init(&sta32x->coeff_lock);
+       sta32x->pdata = dev_get_platdata(dev);
+
+#ifdef CONFIG_OF
+       if (dev->of_node) {
+               ret = sta32x_probe_dt(dev, sta32x);
+               if (ret < 0)
+                       return ret;
+       }
+#endif
+
+       /* GPIOs */
+       sta32x->gpiod_nreset = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(sta32x->gpiod_nreset)) {
+               ret = PTR_ERR(sta32x->gpiod_nreset);
+               if (ret != -ENOENT && ret != -ENOSYS)
+                       return ret;
+
+               sta32x->gpiod_nreset = NULL;
+       } else {
+               gpiod_direction_output(sta32x->gpiod_nreset, 0);
+       }
+
        /* regulators */
        for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++)
                sta32x->supplies[i].supply = sta32x_supply_names[i];
@@ -982,15 +1123,15 @@ static int sta32x_i2c_probe(struct i2c_client *i2c,
        sta32x->regmap = devm_regmap_init_i2c(i2c, &sta32x_regmap);
        if (IS_ERR(sta32x->regmap)) {
                ret = PTR_ERR(sta32x->regmap);
-               dev_err(&i2c->dev, "Failed to init regmap: %d\n", ret);
+               dev_err(dev, "Failed to init regmap: %d\n", ret);
                return ret;
        }
 
        i2c_set_clientdata(i2c, sta32x);
 
-       ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
-       if (ret != 0)
-               dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+       ret = snd_soc_register_codec(dev, &sta32x_codec, &sta32x_dai, 1);
+       if (ret < 0)
+               dev_err(dev, "Failed to register codec (%d)\n", ret);
 
        return ret;
 }
@@ -1013,6 +1154,7 @@ static struct i2c_driver sta32x_i2c_driver = {
        .driver = {
                .name = "sta32x",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(st32x_dt_ids),
        },
        .probe =    sta32x_i2c_probe,
        .remove =   sta32x_i2c_remove,
index d8e32a6262ee087ec13e73d24e57b936eefaa42b..d3191c983d712b5c02fb8a94733b75c21cb6b447 100644 (file)
 #define STA32X_CONFF_OCFG_MASK 0x03
 #define STA32X_CONFF_OCFG_SHIFT        0
 #define STA32X_CONFF_IDE       0x04
-#define STA32X_CONFF_IDE_SHIFT 3
+#define STA32X_CONFF_IDE_SHIFT 2
 #define STA32X_CONFF_BCLE      0x08
 #define STA32X_CONFF_ECLE      0x20
 #define STA32X_CONFF_PWDN      0x40
index dc3223d6eca1884a0faa44f9510e1ecb946ceae2..c86dd9aae1576670925b0ae1ce4b7959e5f199e4 100644 (file)
@@ -349,7 +349,8 @@ static int aic31xx_wait_bits(struct aic31xx_priv *aic31xx, unsigned int reg,
 static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
                                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
        unsigned int reg = AIC31XX_DACFLAG1;
        unsigned int mask;
 
@@ -377,7 +378,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
                reg = AIC31XX_ADCFLAG;
                break;
        default:
-               dev_err(w->codec->dev, "Unknown widget '%s' calling %s\n",
+               dev_err(codec->dev, "Unknown widget '%s' calling %s\n",
                        w->name, __func__);
                return -EINVAL;
        }
@@ -388,7 +389,7 @@ static int aic31xx_dapm_power_event(struct snd_soc_dapm_widget *w,
        case SND_SOC_DAPM_POST_PMD:
                return aic31xx_wait_bits(aic31xx, reg, mask, 0, 5000, 100);
        default:
-               dev_dbg(w->codec->dev,
+               dev_dbg(codec->dev,
                        "Unhandled dapm widget event %d from %s\n",
                        event, w->name);
        }
@@ -433,7 +434,7 @@ static const struct snd_kcontrol_new aic31xx_dapm_spr_switch =
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index b7ebce054b4ebe673ceeb23fa73118a1c9c74998..51c4713ac6e39059efbb6d296be7ee3527435649 100644 (file)
@@ -87,6 +87,7 @@ struct aic3x_priv {
 #define AIC3X_MODEL_3X 0
 #define AIC3X_MODEL_33 1
 #define AIC3X_MODEL_3007 2
+#define AIC3X_MODEL_3104 3
        u16 model;
 
        /* Selects the micbias voltage */
@@ -197,7 +198,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
 static int mic_bias_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -316,52 +317,37 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
         * only for swapped L-to-R and R-to-L routes. See below stereo controls
         * for direct L-to-L and R-to-R routes.
         */
-       SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
-                      LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left Line Mixer PGAR Bypass Volume",
                       PGAR_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left Line Mixer DACR1 Playback Volume",
                       DACR1_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
-                      LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right Line Mixer PGAL Bypass Volume",
                       PGAL_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right Line Mixer DACL1 Playback Volume",
                       DACL1_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
-                      LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HP Mixer PGAR Bypass Volume",
                       PGAR_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HP Mixer DACR1 Playback Volume",
                       DACR1_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
-                      LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HP Mixer PGAL Bypass Volume",
                       PGAL_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HP Mixer DACL1 Playback Volume",
                       DACL1_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
-                      LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HPCOM Mixer PGAR Bypass Volume",
                       PGAR_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Left HPCOM Mixer DACR1 Playback Volume",
                       DACR1_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
 
-       SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
-                      LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HPCOM Mixer PGAL Bypass Volume",
                       PGAL_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
        SOC_SINGLE_TLV("Right HPCOM Mixer DACL1 Playback Volume",
                       DACL1_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
 
        /* Stereo output controls for direct L-to-L and R-to-R routes */
-       SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
-                        LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
-                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("Line PGA Bypass Volume",
                         PGAL_2_LLOPM_VOL, PGAR_2_RLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -369,9 +355,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                         DACL1_2_LLOPM_VOL, DACR1_2_RLOPM_VOL,
                         0, 118, 1, output_stage_tlv),
 
-       SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
-                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
-                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("HP PGA Bypass Volume",
                         PGAL_2_HPLOUT_VOL, PGAR_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -379,9 +362,6 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
                         DACL1_2_HPLOUT_VOL, DACR1_2_HPROUT_VOL,
                         0, 118, 1, output_stage_tlv),
 
-       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
-                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
-                        0, 118, 1, output_stage_tlv),
        SOC_DOUBLE_R_TLV("HPCOM PGA Bypass Volume",
                         PGAL_2_HPLCOM_VOL, PGAR_2_HPRCOM_VOL,
                         0, 118, 1, output_stage_tlv),
@@ -424,6 +404,45 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
        SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum),
 };
 
+/* For other than tlv320aic3104 */
+static const struct snd_kcontrol_new aic3x_extra_snd_controls[] = {
+       /*
+        * Output controls that map to output mixer switches. Note these are
+        * only for swapped L-to-R and R-to-L routes. See below stereo controls
+        * for direct L-to-L and R-to-R routes.
+        */
+       SOC_SINGLE_TLV("Left Line Mixer Line2R Bypass Volume",
+                      LINE2R_2_LLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right Line Mixer Line2L Bypass Volume",
+                      LINE2L_2_RLOPM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HP Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLOUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HP Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPROUT_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Left HPCOM Mixer Line2R Bypass Volume",
+                      LINE2R_2_HPLCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       SOC_SINGLE_TLV("Right HPCOM Mixer Line2L Bypass Volume",
+                      LINE2L_2_HPRCOM_VOL, 0, 118, 1, output_stage_tlv),
+
+       /* Stereo output controls for direct L-to-L and R-to-R routes */
+       SOC_DOUBLE_R_TLV("Line Line2 Bypass Volume",
+                        LINE2L_2_LLOPM_VOL, LINE2R_2_RLOPM_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("HP Line2 Bypass Volume",
+                        LINE2L_2_HPLOUT_VOL, LINE2R_2_HPROUT_VOL,
+                        0, 118, 1, output_stage_tlv),
+
+       SOC_DOUBLE_R_TLV("HPCOM Line2 Bypass Volume",
+                        LINE2L_2_HPLCOM_VOL, LINE2R_2_HPRCOM_VOL,
+                        0, 118, 1, output_stage_tlv),
+};
+
 static const struct snd_kcontrol_new aic3x_mono_controls[] = {
        SOC_DOUBLE_R_TLV("Mono Line2 Bypass Volume",
                         LINE2L_2_MONOLOPM_VOL, LINE2R_2_MONOLOPM_VOL,
@@ -464,22 +483,24 @@ SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum);
 
 /* Left Line Mixer */
 static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_LLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_LLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_LLOPM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_LLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_LLOPM_VOL, 7, 1, 0),
 };
 
 /* Right Line Mixer */
 static const struct snd_kcontrol_new aic3x_right_line_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_RLOPM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_RLOPM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_RLOPM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_RLOPM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_RLOPM_VOL, 7, 1, 0),
 };
 
 /* Mono Mixer */
@@ -494,42 +515,46 @@ static const struct snd_kcontrol_new aic3x_mono_mixer_controls[] = {
 
 /* Left HP Mixer */
 static const struct snd_kcontrol_new aic3x_left_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLOUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLOUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLOUT_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLOUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLOUT_VOL, 7, 1, 0),
 };
 
 /* Right HP Mixer */
 static const struct snd_kcontrol_new aic3x_right_hp_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPROUT_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPROUT_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPROUT_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPROUT_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPROUT_VOL, 7, 1, 0),
 };
 
 /* Left HPCOM Mixer */
 static const struct snd_kcontrol_new aic3x_left_hpcom_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPLCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPLCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPLCOM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPLCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPLCOM_VOL, 7, 1, 0),
 };
 
 /* Right HPCOM Mixer */
 static const struct snd_kcontrol_new aic3x_right_hpcom_mixer_controls[] = {
-       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAL Bypass Switch", PGAL_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACL1 Switch", DACL1_2_HPRCOM_VOL, 7, 1, 0),
-       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("PGAR Bypass Switch", PGAR_2_HPRCOM_VOL, 7, 1, 0),
        SOC_DAPM_SINGLE("DACR1 Switch", DACR1_2_HPRCOM_VOL, 7, 1, 0),
+       /* Not on tlv320aic3104 */
+       SOC_DAPM_SINGLE("Line2L Bypass Switch", LINE2L_2_HPRCOM_VOL, 7, 1, 0),
+       SOC_DAPM_SINGLE("Line2R Bypass Switch", LINE2R_2_HPRCOM_VOL, 7, 1, 0),
 };
 
 /* Left PGA Mixer */
@@ -550,6 +575,22 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
        SOC_DAPM_SINGLE_AIC3X("Mic3R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
 };
 
+/* Left PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_left_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_LADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_LADC_CTRL, 4, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_LADC_CTRL, 0, 1, 1),
+};
+
+/* Right PGA Mixer for tlv320aic3104 */
+static const struct snd_kcontrol_new aic3104_right_pga_mixer_controls[] = {
+       SOC_DAPM_SINGLE_AIC3X("Line1R Switch", LINE1R_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Line1L Switch", LINE1L_2_RADC_CTRL, 3, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2L Switch", MIC3LR_2_RADC_CTRL, 4, 1, 1),
+       SOC_DAPM_SINGLE_AIC3X("Mic2R Switch", MIC3LR_2_RADC_CTRL, 0, 1, 1),
+};
+
 /* Left Line1 Mux */
 static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
 SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum);
@@ -593,26 +634,56 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
 
        /* Inputs to Left ADC */
        SND_SOC_DAPM_ADC("Left ADC", "Left Capture", LINE1L_2_LADC_CTRL, 2, 0),
-       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_left_pga_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line1l_mux_controls),
        SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_left_line1r_mux_controls),
-       SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
-                        &aic3x_left_line2_mux_controls),
 
        /* Inputs to Right ADC */
        SND_SOC_DAPM_ADC("Right ADC", "Right Capture",
                         LINE1R_2_RADC_CTRL, 2, 0),
-       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
-                          &aic3x_right_pga_mixer_controls[0],
-                          ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line1l_mux_controls),
        SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line1r_mux_controls),
+
+       /* Mic Bias */
+       SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
+                        mic_bias_event,
+                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+       SND_SOC_DAPM_OUTPUT("LLOUT"),
+       SND_SOC_DAPM_OUTPUT("RLOUT"),
+       SND_SOC_DAPM_OUTPUT("HPLOUT"),
+       SND_SOC_DAPM_OUTPUT("HPROUT"),
+       SND_SOC_DAPM_OUTPUT("HPLCOM"),
+       SND_SOC_DAPM_OUTPUT("HPRCOM"),
+
+       SND_SOC_DAPM_INPUT("LINE1L"),
+       SND_SOC_DAPM_INPUT("LINE1R"),
+
+       /*
+        * Virtual output pin to detection block inside codec. This can be
+        * used to keep codec bias on if gpio or detection features are needed.
+        * Force pin on or construct a path with an input jack and mic bias
+        * widgets.
+        */
+       SND_SOC_DAPM_OUTPUT("Detection"),
+};
+
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3x_extra_dapm_widgets[] = {
+       /* Inputs to Left ADC */
+       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_pga_mixer_controls)),
+       SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0,
+                        &aic3x_left_line2_mux_controls),
+
+       /* Inputs to Right ADC */
+       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_pga_mixer_controls)),
        SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0,
                         &aic3x_right_line2_mux_controls),
 
@@ -637,11 +708,6 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
        SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32",
                         AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
 
-       /* Mic Bias */
-       SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0,
-                        mic_bias_event,
-                        SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
-
        /* Output mixers */
        SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
                           &aic3x_left_line_mixer_controls[0],
@@ -662,27 +728,46 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
                           &aic3x_right_hpcom_mixer_controls[0],
                           ARRAY_SIZE(aic3x_right_hpcom_mixer_controls)),
 
-       SND_SOC_DAPM_OUTPUT("LLOUT"),
-       SND_SOC_DAPM_OUTPUT("RLOUT"),
-       SND_SOC_DAPM_OUTPUT("HPLOUT"),
-       SND_SOC_DAPM_OUTPUT("HPROUT"),
-       SND_SOC_DAPM_OUTPUT("HPLCOM"),
-       SND_SOC_DAPM_OUTPUT("HPRCOM"),
-
        SND_SOC_DAPM_INPUT("MIC3L"),
        SND_SOC_DAPM_INPUT("MIC3R"),
-       SND_SOC_DAPM_INPUT("LINE1L"),
-       SND_SOC_DAPM_INPUT("LINE1R"),
        SND_SOC_DAPM_INPUT("LINE2L"),
        SND_SOC_DAPM_INPUT("LINE2R"),
+};
 
-       /*
-        * Virtual output pin to detection block inside codec. This can be
-        * used to keep codec bias on if gpio or detection features are needed.
-        * Force pin on or construct a path with an input jack and mic bias
-        * widgets.
-        */
-       SND_SOC_DAPM_OUTPUT("Detection"),
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_widget aic3104_extra_dapm_widgets[] = {
+       /* Inputs to Left ADC */
+       SND_SOC_DAPM_MIXER("Left PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3104_left_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3104_left_pga_mixer_controls)),
+
+       /* Inputs to Right ADC */
+       SND_SOC_DAPM_MIXER("Right PGA Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3104_right_pga_mixer_controls[0],
+                          ARRAY_SIZE(aic3104_right_pga_mixer_controls)),
+
+       /* Output mixers */
+       SND_SOC_DAPM_MIXER("Left Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_line_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Right Line Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_line_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_line_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Left HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hp_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Right HP Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hp_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hp_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Left HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_left_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_left_hpcom_mixer_controls) - 2),
+       SND_SOC_DAPM_MIXER("Right HPCOM Mixer", SND_SOC_NOPM, 0, 0,
+                          &aic3x_right_hpcom_mixer_controls[0],
+                          ARRAY_SIZE(aic3x_right_hpcom_mixer_controls) - 2),
+
+       SND_SOC_DAPM_INPUT("MIC2L"),
+       SND_SOC_DAPM_INPUT("MIC2R"),
 };
 
 static const struct snd_soc_dapm_widget aic3x_dapm_mono_widgets[] = {
@@ -712,17 +797,10 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Left Line1R Mux", "single-ended", "LINE1R"},
        {"Left Line1R Mux", "differential", "LINE1R"},
 
-       {"Left Line2L Mux", "single-ended", "LINE2L"},
-       {"Left Line2L Mux", "differential", "LINE2L"},
-
        {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"},
        {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"},
-       {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
-       {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
-       {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Left ADC", NULL, "Left PGA Mixer"},
-       {"Left ADC", NULL, "GPIO1 dmic modclk"},
 
        /* Right Input */
        {"Right Line1R Mux", "single-ended", "LINE1R"},
@@ -730,25 +808,10 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right Line1L Mux", "single-ended", "LINE1L"},
        {"Right Line1L Mux", "differential", "LINE1L"},
 
-       {"Right Line2R Mux", "single-ended", "LINE2R"},
-       {"Right Line2R Mux", "differential", "LINE2R"},
-
        {"Right PGA Mixer", "Line1L Switch", "Right Line1L Mux"},
        {"Right PGA Mixer", "Line1R Switch", "Right Line1R Mux"},
-       {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
-       {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
-       {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
 
        {"Right ADC", NULL, "Right PGA Mixer"},
-       {"Right ADC", NULL, "GPIO1 dmic modclk"},
-
-       /*
-        * Logical path between digital mic enable and GPIO1 modulator clock
-        * output function
-        */
-       {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
-       {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
-       {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
 
        /* Left DAC Output */
        {"Left DAC Mux", "DAC_L1", "Left DAC"},
@@ -761,10 +824,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"Right DAC Mux", "DAC_R3", "Right DAC"},
 
        /* Left Line Output */
-       {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Left Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Left Line Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Left Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Left Line Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -773,10 +834,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"LLOUT", NULL, "Left Line Out"},
 
        /* Right Line Output */
-       {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Right Line Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Right Line Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Right Line Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Right Line Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -785,10 +844,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"RLOUT", NULL, "Right Line Out"},
 
        /* Left HP Output */
-       {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Left HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Left HP Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Left HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Left HP Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -797,10 +854,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPLOUT", NULL, "Left HP Out"},
 
        /* Right HP Output */
-       {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Right HP Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Right HP Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Right HP Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Right HP Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -809,10 +864,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPROUT", NULL, "Right HP Out"},
 
        /* Left HPCOM Output */
-       {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Left HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Left HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Left HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Left HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -823,10 +876,8 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPLCOM", NULL, "Left HP Com"},
 
        /* Right HPCOM Output */
-       {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
        {"Right HPCOM Mixer", "PGAL Bypass Switch", "Left PGA Mixer"},
        {"Right HPCOM Mixer", "DACL1 Switch", "Left DAC Mux"},
-       {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
        {"Right HPCOM Mixer", "PGAR Bypass Switch", "Right PGA Mixer"},
        {"Right HPCOM Mixer", "DACR1 Switch", "Right DAC Mux"},
 
@@ -839,6 +890,72 @@ static const struct snd_soc_dapm_route intercon[] = {
        {"HPRCOM", NULL, "Right HP Com"},
 };
 
+/* For other than tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra[] = {
+       /* Left Input */
+       {"Left Line2L Mux", "single-ended", "LINE2L"},
+       {"Left Line2L Mux", "differential", "LINE2L"},
+
+       {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"},
+       {"Left PGA Mixer", "Mic3L Switch", "MIC3L"},
+       {"Left PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+       {"Left ADC", NULL, "GPIO1 dmic modclk"},
+
+       /* Right Input */
+       {"Right Line2R Mux", "single-ended", "LINE2R"},
+       {"Right Line2R Mux", "differential", "LINE2R"},
+
+       {"Right PGA Mixer", "Line2R Switch", "Right Line2R Mux"},
+       {"Right PGA Mixer", "Mic3L Switch", "MIC3L"},
+       {"Right PGA Mixer", "Mic3R Switch", "MIC3R"},
+
+       {"Right ADC", NULL, "GPIO1 dmic modclk"},
+
+       /*
+        * Logical path between digital mic enable and GPIO1 modulator clock
+        * output function
+        */
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 128"},
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 64"},
+       {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
+
+       /* Left Line Output */
+       {"Left Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Right Line Output */
+       {"Right Line Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right Line Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Left HP Output */
+       {"Left HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Right HP Output */
+       {"Right HP Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HP Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Left HPCOM Output */
+       {"Left HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Left HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+
+       /* Right HPCOM Output */
+       {"Right HPCOM Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
+       {"Right HPCOM Mixer", "Line2R Bypass Switch", "Right Line2R Mux"},
+};
+
+/* For tlv320aic3104 */
+static const struct snd_soc_dapm_route intercon_extra_3104[] = {
+       /* Left Input */
+       {"Left PGA Mixer", "Mic2L Switch", "MIC2L"},
+       {"Left PGA Mixer", "Mic2R Switch", "MIC2R"},
+
+       /* Right Input */
+       {"Right PGA Mixer", "Mic2L Switch", "MIC2L"},
+       {"Right PGA Mixer", "Mic2R Switch", "MIC2R"},
+};
+
 static const struct snd_soc_dapm_route intercon_mono[] = {
        /* Mono Output */
        {"Mono Mixer", "Line2L Bypass Switch", "Left Line2L Mux"},
@@ -867,17 +984,31 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec)
        switch (aic3x->model) {
        case AIC3X_MODEL_3X:
        case AIC3X_MODEL_33:
+               snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+                                         ARRAY_SIZE(aic3x_extra_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_extra,
+                                       ARRAY_SIZE(intercon_extra));
                snd_soc_dapm_new_controls(dapm, aic3x_dapm_mono_widgets,
                        ARRAY_SIZE(aic3x_dapm_mono_widgets));
                snd_soc_dapm_add_routes(dapm, intercon_mono,
                                        ARRAY_SIZE(intercon_mono));
                break;
        case AIC3X_MODEL_3007:
+               snd_soc_dapm_new_controls(dapm, aic3x_extra_dapm_widgets,
+                                         ARRAY_SIZE(aic3x_extra_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_extra,
+                                       ARRAY_SIZE(intercon_extra));
                snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
                        ARRAY_SIZE(aic3007_dapm_widgets));
                snd_soc_dapm_add_routes(dapm, intercon_3007,
                                        ARRAY_SIZE(intercon_3007));
                break;
+       case AIC3X_MODEL_3104:
+               snd_soc_dapm_new_controls(dapm, aic3104_extra_dapm_widgets,
+                               ARRAY_SIZE(aic3104_extra_dapm_widgets));
+               snd_soc_dapm_add_routes(dapm, intercon_extra_3104,
+                               ARRAY_SIZE(intercon_extra_3104));
+               break;
        }
 
        return 0;
@@ -1046,7 +1177,7 @@ static int aic3x_prepare(struct snd_pcm_substream *substream,
                delay += aic3x->tdm_delay;
 
        /* Configure data delay */
-       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay);
+       snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
 
        return 0;
 }
@@ -1438,23 +1569,33 @@ static int aic3x_probe(struct snd_soc_codec *codec)
        aic3x_init(codec);
 
        if (aic3x->setup) {
-               /* setup GPIO functions */
-               snd_soc_write(codec, AIC3X_GPIO1_REG,
-                             (aic3x->setup->gpio_func[0] & 0xf) << 4);
-               snd_soc_write(codec, AIC3X_GPIO2_REG,
-                             (aic3x->setup->gpio_func[1] & 0xf) << 4);
+               if (aic3x->model != AIC3X_MODEL_3104) {
+                       /* setup GPIO functions */
+                       snd_soc_write(codec, AIC3X_GPIO1_REG,
+                                     (aic3x->setup->gpio_func[0] & 0xf) << 4);
+                       snd_soc_write(codec, AIC3X_GPIO2_REG,
+                                     (aic3x->setup->gpio_func[1] & 0xf) << 4);
+               } else {
+                       dev_warn(codec->dev, "GPIO functionality is not supported on tlv320aic3104\n");
+               }
        }
 
        switch (aic3x->model) {
        case AIC3X_MODEL_3X:
        case AIC3X_MODEL_33:
+               snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+                               ARRAY_SIZE(aic3x_extra_snd_controls));
                snd_soc_add_codec_controls(codec, aic3x_mono_controls,
                                ARRAY_SIZE(aic3x_mono_controls));
                break;
        case AIC3X_MODEL_3007:
+               snd_soc_add_codec_controls(codec, aic3x_extra_snd_controls,
+                               ARRAY_SIZE(aic3x_extra_snd_controls));
                snd_soc_add_codec_controls(codec,
                                &aic3x_classd_amp_gain_ctrl, 1);
                break;
+       case AIC3X_MODEL_3104:
+               break;
        }
 
        /* set mic bias voltage */
@@ -1522,6 +1663,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
        { "tlv320aic33", AIC3X_MODEL_33 },
        { "tlv320aic3007", AIC3X_MODEL_3007 },
        { "tlv320aic3106", AIC3X_MODEL_3X },
+       { "tlv320aic3104", AIC3X_MODEL_3104 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@@ -1673,6 +1815,7 @@ static const struct of_device_id tlv320aic3x_of_match[] = {
        { .compatible = "ti,tlv320aic33" },
        { .compatible = "ti,tlv320aic3007" },
        { .compatible = "ti,tlv320aic3106" },
+       { .compatible = "ti,tlv320aic3104" },
        {},
 };
 MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match);
index 0fe2ced5b09fc72324fd2e9ac89c1ec3cf0d06cb..4e3e607dec13085df4cbc4a3d198ae5cacf78c32 100644 (file)
@@ -423,17 +423,18 @@ exit:
 static int dac33_playback_event(struct snd_soc_dapm_widget *w,
                struct snd_kcontrol *kcontrol, int event)
 {
-       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                if (likely(dac33->substream)) {
-                       dac33_calculate_times(dac33->substream, w->codec);
-                       dac33_prepare_chip(dac33->substream, w->codec);
+                       dac33_calculate_times(dac33->substream, codec);
+                       dac33_prepare_chip(dac33->substream, codec);
                }
                break;
        case SND_SOC_DAPM_POST_PMD:
-               dac33_disable_digital(w->codec);
+               dac33_disable_digital(codec);
                break;
        }
        return 0;
index 1d1205702d2324bcef0b41d9682a49549bc4f6e0..9fd80ac1897f5b369bc14a0420c0b834da748343 100644 (file)
@@ -20,6 +20,8 @@
 #include <sound/jack.h>
 #include <sound/soc.h>
 
+#include "ts3a227e.h"
+
 struct ts3a227e {
        struct regmap *regmap;
        struct snd_soc_jack *jack;
@@ -79,6 +81,10 @@ static const int ts3a227e_buttons[] = {
 /* TS3A227E_REG_SETTING_2 0x05 */
 #define KP_ENABLE 0x04
 
+/* TS3A227E_REG_SETTING_3 0x06 */
+#define MICBIAS_SETTING_SFT (3)
+#define MICBIAS_SETTING_MASK (0x7 << MICBIAS_SETTING_SFT)
+
 /* TS3A227E_REG_ACCESSORY_STATUS  0x0b */
 #define TYPE_3_POLE 0x01
 #define TYPE_4_POLE_OMTP 0x02
@@ -221,9 +227,9 @@ int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
        struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component);
 
        snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
-       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+       snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
 
        ts3a227e->jack = jack;
        ts3a227e_jack_report(ts3a227e);
@@ -248,12 +254,28 @@ static const struct regmap_config ts3a227e_regmap_config = {
        .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
 };
 
+static int ts3a227e_parse_dt(struct ts3a227e *ts3a227e, struct device_node *np)
+{
+       u32 micbias;
+       int err;
+
+       err = of_property_read_u32(np, "ti,micbias", &micbias);
+       if (!err) {
+               regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_SETTING_3,
+                       MICBIAS_SETTING_MASK,
+                       (micbias & 0x07) << MICBIAS_SETTING_SFT);
+       }
+
+       return 0;
+}
+
 static int ts3a227e_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
        struct ts3a227e *ts3a227e;
        struct device *dev = &i2c->dev;
        int ret;
+       unsigned int acc_reg;
 
        ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL);
        if (ts3a227e == NULL)
@@ -265,6 +287,14 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
        if (IS_ERR(ts3a227e->regmap))
                return PTR_ERR(ts3a227e->regmap);
 
+       if (dev->of_node) {
+               ret = ts3a227e_parse_dt(ts3a227e, dev->of_node);
+               if (ret) {
+                       dev_err(dev, "Failed to parse device tree: %d\n", ret);
+                       return ret;
+               }
+       }
+
        ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
                                        IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                        "TS3A227E", ts3a227e);
@@ -283,6 +313,11 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c,
                           INTB_DISABLE | ADC_COMPLETE_INT_DISABLE,
                           ADC_COMPLETE_INT_DISABLE);
 
+       /* Read jack status because chip might not trigger interrupt at boot. */
+       regmap_read(ts3a227e->regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
+       ts3a227e_new_jack_state(ts3a227e, acc_reg);
+       ts3a227e_jack_report(ts3a227e);
+
        return 0;
 }
 
index 44af3188afb9c6e50e9e097e4c97c0ffb15f4023..d04693e9cf9f8c9b362b212b04058e7fe6ee2278 100644 (file)
@@ -567,12 +567,13 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control =
 static int pin_name##pga_event(struct snd_soc_dapm_widget *w,          \
                               struct snd_kcontrol *kcontrol, int event) \
 {                                                                      \
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);   \
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); \
                                                                        \
        switch (event) {                                                \
        case SND_SOC_DAPM_POST_PMU:                                     \
                twl4030->pin_name##_enabled = 1;                        \
-               twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \
+               twl4030_write(codec, reg, twl4030_read(codec, reg));    \
                break;                                                  \
        case SND_SOC_DAPM_POST_PMD:                                     \
                twl4030->pin_name##_enabled = 0;                        \
@@ -621,12 +622,14 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp)
 static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
                               struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 1);
+               handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               handsfree_ramp(w->codec, TWL4030_REG_HFL_CTL, 0);
+               handsfree_ramp(codec, TWL4030_REG_HFL_CTL, 0);
                break;
        }
        return 0;
@@ -635,12 +638,14 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w,
 static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
                               struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
-               handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 1);
+               handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               handsfree_ramp(w->codec, TWL4030_REG_HFR_CTL, 0);
+               handsfree_ramp(codec, TWL4030_REG_HFR_CTL, 0);
                break;
        }
        return 0;
@@ -649,19 +654,23 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w,
 static int vibramux_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
-       twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
+       twl4030_write(codec, TWL4030_REG_VIBRA_SET, 0xff);
        return 0;
 }
 
 static int apll_event(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
-               twl4030_apll_enable(w->codec, 1);
+               twl4030_apll_enable(codec, 1);
                break;
        case SND_SOC_DAPM_POST_PMD:
-               twl4030_apll_enable(w->codec, 0);
+               twl4030_apll_enable(codec, 0);
                break;
        }
        return 0;
@@ -670,23 +679,24 @@ static int apll_event(struct snd_soc_dapm_widget *w,
 static int aif_event(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u8 audio_if;
 
-       audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF);
+       audio_if = twl4030_read(codec, TWL4030_REG_AUDIO_IF);
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                /* Enable AIF */
                /* enable the PLL before we use it to clock the DAI */
-               twl4030_apll_enable(w->codec, 1);
+               twl4030_apll_enable(codec, 1);
 
-               twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
+               twl4030_write(codec, TWL4030_REG_AUDIO_IF,
                              audio_if | TWL4030_AIF_EN);
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* disable the DAI before we stop it's source PLL */
-               twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
+               twl4030_write(codec, TWL4030_REG_AUDIO_IF,
                              audio_if &  ~TWL4030_AIF_EN);
-               twl4030_apll_enable(w->codec, 0);
+               twl4030_apll_enable(codec, 0);
                break;
        }
        return 0;
@@ -758,20 +768,21 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
 static int headsetlpga_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* Do the ramp-up only once */
                if (!twl4030->hsr_enabled)
-                       headset_ramp(w->codec, 1);
+                       headset_ramp(codec, 1);
 
                twl4030->hsl_enabled = 1;
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* Do the ramp-down only if both headsetL/R is disabled */
                if (!twl4030->hsr_enabled)
-                       headset_ramp(w->codec, 0);
+                       headset_ramp(codec, 0);
 
                twl4030->hsl_enabled = 0;
                break;
@@ -782,20 +793,21 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
 static int headsetrpga_event(struct snd_soc_dapm_widget *w,
                             struct snd_kcontrol *kcontrol, int event)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* Do the ramp-up only once */
                if (!twl4030->hsl_enabled)
-                       headset_ramp(w->codec, 1);
+                       headset_ramp(codec, 1);
 
                twl4030->hsr_enabled = 1;
                break;
        case SND_SOC_DAPM_POST_PMD:
                /* Do the ramp-down only if both headsetL/R is disabled */
                if (!twl4030->hsl_enabled)
-                       headset_ramp(w->codec, 0);
+                       headset_ramp(codec, 0);
 
                twl4030->hsr_enabled = 0;
                break;
@@ -806,7 +818,8 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w,
 static int digimic_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
        struct twl4030_codec_data *pdata = twl4030->pdata;
 
        if (pdata && pdata->digimic_delay)
index 90f47f988b3fe3b1e28321df538c1ba2f7d9bb4f..aeec27b6f1af76aca729aacd35e872b01eb05362 100644 (file)
@@ -234,7 +234,7 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf)
 static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u8 hslctl, hsrctl;
 
        /*
@@ -261,7 +261,7 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
 static int twl6040_ep_drv_event(struct snd_soc_dapm_widget *w,
                        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
index 34ef65c52a7d9425e84a6c9ba475f5cfdb664ea9..8d9de49a50524bb4e88ebd62cb580e17239b07d6 100644 (file)
@@ -683,7 +683,7 @@ static const struct snd_kcontrol_new wm2000_controls[] = {
 static int wm2000_anc_power_event(struct snd_soc_dapm_widget *w,
                                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm2000_priv *wm2000 = dev_get_drvdata(codec->dev);
        int ret;
 
index b80970dc2d2f14c9edbbe2e333f65843f0e33b88..ea09db585aa1fd266f391aadbde5fa78c71318db 100644 (file)
@@ -775,7 +775,8 @@ static int wm5100_out_ev(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol,
                         int event)
 {
-       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
 
        switch (w->reg) {
        case WM5100_CHANNEL_ENABLES_1:
@@ -839,7 +840,7 @@ static int wm5100_post_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol,
                          int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec);
        int ret;
 
index f439ae052128c145c3f65d09f42d1531bdfe89a0..6d0fe0ac95a3f6121d87c52cfa4f17f6ec844651 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <linux/mfd/arizona/core.h>
 #include <linux/mfd/arizona/registers.h>
+#include <asm/unaligned.h>
 
 #include "arizona.h"
 #include "wm5102.h"
@@ -580,7 +581,7 @@ static const struct reg_default wm5102_sysclk_revb_patch[] = {
 static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
@@ -617,11 +618,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
-       uint16_t data;
 
        mutex_lock(&arizona->dac_comp_lock);
-       data = cpu_to_be16(arizona->dac_comp_coeff);
-       memcpy(ucontrol->value.bytes.data, &data, sizeof(data));
+       put_unaligned_be16(arizona->dac_comp_coeff,
+                          ucontrol->value.bytes.data);
        mutex_unlock(&arizona->dac_comp_lock);
 
        return 0;
@@ -1272,19 +1272,24 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
                   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
index 4456b38a3ef59543591260505e177144f66fcd54..fbaeddb3e9033a3044b4995265dce2849b348160 100644 (file)
@@ -134,7 +134,7 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
 static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
@@ -905,22 +905,28 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
                   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3R", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
index 574579b988726a41b7b8d7b4e8615359b1aa4e12..c81a9eab3e3e5113121a9e2c90f1971a410d41fe 100644 (file)
@@ -259,7 +259,7 @@ static void wm8350_pga_work(struct work_struct *work)
 static int pga_event(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
        struct wm8350_output *out;
 
index 8ee446987aa9e4999f9b0a4098adee220b7d0f66..b0d84e552fca758786100c5eca18b746013a1d61 100644 (file)
@@ -324,6 +324,7 @@ SOC_SINGLE("RIN34 Mute Switch", WM8400_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_event (struct snd_soc_dapm_widget *w,
        struct snd_kcontrol * kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        u32 reg_shift = mc->shift;
@@ -332,7 +333,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
 
        switch (reg_shift) {
        case WM8400_SPEAKER_MIXER | (WM8400_LDSPK << 8) :
-               reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER1);
+               reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER1);
                if (reg & WM8400_LDLO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -340,7 +341,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_SPEAKER_MIXER | (WM8400_RDSPK << 8):
-               reg = snd_soc_read(w->codec, WM8400_OUTPUT_MIXER2);
+               reg = snd_soc_read(codec, WM8400_OUTPUT_MIXER2);
                if (reg & WM8400_RDRO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -348,7 +349,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_OUTPUT_MIXER1 | (WM8400_LDLO << 8):
-               reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
                if (reg & WM8400_LDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -356,7 +357,7 @@ static int outmixer_event (struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8400_OUTPUT_MIXER2 | (WM8400_RDRO << 8):
-               reg = snd_soc_read(w->codec, WM8400_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8400_SPEAKER_MIXER);
                if (reg & WM8400_RDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer RDSPK Set\n");
index b9211b42f6e919f0603eabda95ca332eea71dfb6..098c143f44d653d99c33f36e02edde9eca6600d8 100644 (file)
@@ -217,7 +217,8 @@ SND_SOC_DAPM_INPUT("LLINEIN"),
 static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
                            struct snd_soc_dapm_widget *sink)
 {
-       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
 
        return wm8731->sysclk_type == WM8731_SYSCLK_XTAL;
 }
@@ -717,6 +718,8 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
        if (wm8731 == NULL)
                return -ENOMEM;
 
+       mutex_init(&wm8731->lock);
+
        wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
        if (IS_ERR(wm8731->regmap)) {
                ret = PTR_ERR(wm8731->regmap);
index f6847fdd6dddd1e7833acf1eaa2f89244e229c12..eb0a1644ba1142d05cc8ac561945a507f776e066 100644 (file)
@@ -323,7 +323,7 @@ static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("ROUT2"),
        SND_SOC_DAPM_OUTPUT("MONO1"),
        SND_SOC_DAPM_OUTPUT("OUT3"),
-       SND_SOC_DAPM_OUTPUT("VREF"),
+       SND_SOC_DAPM_VMID("VREF"),
 
        SND_SOC_DAPM_INPUT("LINPUT1"),
        SND_SOC_DAPM_INPUT("LINPUT2"),
index 180e7a09872618469e59f7b9b845c2553c460262..53e977da2f86d325c0366efae3e3ba121e49fedd 100644 (file)
@@ -308,9 +308,7 @@ static const struct snd_soc_dapm_route wm8770_intercon[] = {
 static int vout12supply_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -327,9 +325,7 @@ static int vout12supply_event(struct snd_soc_dapm_widget *w,
 static int vout34supply_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
index 1315f76425031686629b8af397b0996969c570c7..b2b0e68f707e32037fe8dc623aed5be1b2cda73c 100644 (file)
@@ -648,7 +648,7 @@ static struct snd_soc_dai_driver wm8804_dai = {
        .symmetric_rates = 1
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
        .probe = wm8804_probe,
        .remove = wm8804_remove,
        .set_bias_level = wm8804_set_bias_level,
@@ -664,7 +664,7 @@ static const struct of_device_id wm8804_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, wm8804_of_match);
 
-static struct regmap_config wm8804_regmap_config = {
+static const struct regmap_config wm8804_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 
index 3a0d4b7d692fcc2bd77eb017374d6139a3bb5df3..2eb986c19b886a48e9d367623adf353a94796689 100644 (file)
@@ -224,7 +224,7 @@ static void wm8900_reset(struct snd_soc_codec *codec)
 static int wm8900_hp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1);
 
        switch (event) {
index cc6b0ef98a345e9b8832bb4c09d1312451d7d070..dde462c082be0eb6124e0f881b9a1ed936e34c77 100644 (file)
@@ -260,7 +260,7 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w,
 static int wm8903_dcs_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index a80bc528431a986a62d81ba6babaa6996d6aeb12..d3b3f57668ccae412f0a75d61f91f9f34f1f0fb0 100644 (file)
@@ -673,7 +673,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int sysclk_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -711,7 +711,7 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
        int reg, val;
        int dcs_mask;
@@ -1076,10 +1076,13 @@ static const struct snd_soc_dapm_route adc_intercon[] = {
        { "Right Capture PGA", NULL, "Right Capture Mux" },
        { "Right Capture PGA", NULL, "Right Capture Inverting Mux" },
 
-       { "AIFOUTL", "Left",  "ADCL" },
-       { "AIFOUTL", "Right", "ADCR" },
-       { "AIFOUTR", "Left",  "ADCL" },
-       { "AIFOUTR", "Right", "ADCR" },
+       { "AIFOUTL Mux", "Left", "ADCL" },
+       { "AIFOUTL Mux", "Right", "ADCR" },
+       { "AIFOUTR Mux", "Left", "ADCL" },
+       { "AIFOUTR Mux", "Right", "ADCR" },
+
+       { "AIFOUTL", NULL, "AIFOUTL Mux" },
+       { "AIFOUTR", NULL, "AIFOUTR Mux" },
 
        { "ADCL", NULL, "CLK_DSP" },
        { "ADCL", NULL, "Left Capture PGA" },
@@ -1089,12 +1092,16 @@ static const struct snd_soc_dapm_route adc_intercon[] = {
 };
 
 static const struct snd_soc_dapm_route dac_intercon[] = {
-       { "DACL", "Right", "AIFINR" },
-       { "DACL", "Left",  "AIFINL" },
+       { "DACL Mux", "Left", "AIFINL" },
+       { "DACL Mux", "Right", "AIFINR" },
+
+       { "DACR Mux", "Left", "AIFINL" },
+       { "DACR Mux", "Right", "AIFINR" },
+
+       { "DACL", NULL, "DACL Mux" },
        { "DACL", NULL, "CLK_DSP" },
 
-       { "DACR", "Right", "AIFINR" },
-       { "DACR", "Left",  "AIFINL" },
+       { "DACR", NULL, "DACR Mux" },
        { "DACR", NULL, "CLK_DSP" },
 
        { "Charge pump", NULL, "SYSCLK" },
index 1173f7fef5a76dcb9f1954c2c23568e7f5c99123..1ab2d462afadfb24a7205638a779bb0152eb702a 100644 (file)
@@ -333,7 +333,7 @@ static int wm8955_configure_clocking(struct snd_soc_codec *codec)
 static int wm8955_sysclk(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int ret = 0;
 
        /* Always disable the clocks - if we're doing reconfiguration this
index 3cbc82b3329288e8d16f33acaa4782dac147a542..c799cca5abeb704645687b863ccedfc6749e9ac2 100644 (file)
@@ -418,7 +418,7 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start)
 int wm8958_aif_ev(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int i;
 
        switch (event) {
index 031a1ae71d943f2782d08f911d24c79d38d078ab..a96eb497a3796e9b67b539eae255a316af52864b 100644 (file)
@@ -556,7 +556,7 @@ static struct {
        { 22050, 2 },
        { 24000, 2 },
        { 16000, 3 },
-       { 11250, 4 },
+       { 11025, 4 },
        { 12000, 4 },
        {  8000, 5 },
 };
index eeffd05384b40e5e15c11f22cbf2cbe7d46a33f7..95e2c1bfc809ff1a0d9c20b6f280c0afed491239 100644 (file)
@@ -194,7 +194,7 @@ static bool wm8961_readable(struct device *dev, unsigned int reg)
 static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0);
        u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1);
        u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
@@ -286,7 +286,7 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w,
 static int wm8961_spk_event(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2);
        u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1);
 
index d32d554f5b34e5c3c3a0d0786aa0fe501dc1368e..118b0034ba235d238bfc5c137db7681126bba45b 100644 (file)
@@ -1866,7 +1866,7 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int timeout;
        int reg;
        int expected = (WM8962_DCS_STARTUP_DONE_HP1L |
@@ -1960,7 +1960,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int out_pga_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int reg;
 
        switch (w->shift) {
@@ -1993,7 +1993,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
 static int dsp2_event(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
index e418199155a8824d0a5cb6fb2cb02b22ffd1c3b8..baff2cc222a67e0c0d713ed42b11443f6a326742 100644 (file)
@@ -244,7 +244,7 @@ SOC_DOUBLE_R_TLV("Output 2 Playback Volume", WM8988_LOUT2V, WM8988_ROUT2V,
 static int wm8988_lrc_control(struct snd_soc_dapm_widget *w,
                              struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2);
 
        /* Use the DAC to gate LRC if active, otherwise use ADC */
index 8a584229310a72daba726678b8e2342b3e431d23..c93bffcb3cfba2e3953b53b571e046a9553ff5a0 100644 (file)
@@ -374,13 +374,14 @@ SOC_SINGLE("RIN34 Mute Switch", WM8990_RIGHT_LINE_INPUT_3_4_VOLUME,
 static int outmixer_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u32 reg_shift = kcontrol->private_value & 0xfff;
        int ret = 0;
        u16 reg;
 
        switch (reg_shift) {
        case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) :
-               reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1);
+               reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER1);
                if (reg & WM8990_LDLO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -388,7 +389,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2);
+               reg = snd_soc_read(codec, WM8990_OUTPUT_MIXER2);
                if (reg & WM8990_RDRO) {
                        printk(KERN_WARNING
                        "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -396,7 +397,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
                if (reg & WM8990_LDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -404,7 +405,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                }
                break;
        case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8990_SPEAKER_MIXER);
                if (reg & WM8990_RDSPK) {
                        printk(KERN_WARNING
                        "Cannot set as Speaker Mixer RDSPK Set\n");
index b0ac2c3e31b9b09a84552eeda9765dec043d023f..49df0dc607e67f41252cd6c56eb38cc0abdf06dc 100644 (file)
@@ -382,13 +382,14 @@ static const struct snd_kcontrol_new wm8991_snd_controls[] = {
 static int outmixer_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u32 reg_shift = kcontrol->private_value & 0xfff;
        int ret = 0;
        u16 reg;
 
        switch (reg_shift) {
        case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1);
+               reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER1);
                if (reg & WM8991_LDLO) {
                        printk(KERN_WARNING
                               "Cannot set as Output Mixer 1 LDLO Set\n");
@@ -397,7 +398,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                break;
 
        case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2);
+               reg = snd_soc_read(codec, WM8991_OUTPUT_MIXER2);
                if (reg & WM8991_RDRO) {
                        printk(KERN_WARNING
                               "Cannot set as Output Mixer 2 RDRO Set\n");
@@ -406,7 +407,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                break;
 
        case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
                if (reg & WM8991_LDSPK) {
                        printk(KERN_WARNING
                               "Cannot set as Speaker Mixer LDSPK Set\n");
@@ -415,7 +416,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w,
                break;
 
        case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8):
-               reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER);
+               reg = snd_soc_read(codec, WM8991_SPEAKER_MIXER);
                if (reg & WM8991_RDSPK) {
                        printk(KERN_WARNING
                               "Cannot set as Speaker Mixer RDSPK Set\n");
index 53c6fe35949675fab58000a661390adefd802f89..2e70a270eb2894f36ccb5cacd3fd618dee45256c 100644 (file)
@@ -810,7 +810,7 @@ SOC_SINGLE_TLV("EQ5 Volume", WM8993_EQ6, 0, 24, 0, eq_tlv),
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
index 1b97de2e4e67126f918097abc24e8932d40995ec..4fbc7689339a8903f724fa9aefcb6feb31dad54f 100644 (file)
@@ -249,7 +249,8 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
-       int reg = snd_soc_read(source->codec, WM8994_CLOCKING_1);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+       int reg = snd_soc_read(codec, WM8994_CLOCKING_1);
        const char *clk;
 
        /* Check what we're currently using for CLK_SYS */
@@ -806,7 +807,7 @@ static void active_dereference(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -981,7 +982,7 @@ static void vmid_dereference(struct snd_soc_codec *codec)
 static int vmid_event(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -1037,7 +1038,7 @@ static bool wm8994_check_class_w_digital(struct snd_soc_codec *codec)
 static int aif1clk_ev(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
        struct wm8994 *control = wm8994->wm8994;
        int mask = WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA;
@@ -1135,7 +1136,7 @@ static int aif1clk_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_ev(struct snd_soc_dapm_widget *w,
                      struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int i;
        int dac;
        int adc;
@@ -1220,7 +1221,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w,
 static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1238,7 +1239,7 @@ static int aif1clk_late_ev(struct snd_soc_dapm_widget *w,
 static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1256,7 +1257,7 @@ static int aif2clk_late_ev(struct snd_soc_dapm_widget *w,
 static int late_enable_ev(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1289,7 +1290,7 @@ static int late_enable_ev(struct snd_soc_dapm_widget *w,
 static int late_disable_ev(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -1331,7 +1332,7 @@ static int micbias_ev(struct snd_soc_dapm_widget *w,
 static int dac_ev(struct snd_soc_dapm_widget *w,
                  struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int mask = 1 << w->shift;
 
        snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5,
@@ -1372,7 +1373,7 @@ SOC_DAPM_SINGLE("DAC1 Switch", WM8994_SPEAKER_MIXER, 0, 1, 0),
 static int post_ev(struct snd_soc_dapm_widget *w,
            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        dev_dbg(codec->dev, "SRC status: %x\n",
                snd_soc_read(codec,
                             WM8994_RATE_STATUS));
index c280f0a3a424303ebba6def4972d4e644fc479f8..66103c2b012e522062a9d29d5f92a099223c6015 100644 (file)
@@ -44,7 +44,7 @@ static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = {
        "MICVDD"
 };
 
-static struct reg_default wm8995_reg_defaults[] = {
+static const struct reg_default wm8995_reg_defaults[] = {
        { 0, 0x8995 },
        { 5, 0x0100 },
        { 16, 0x000b },
@@ -534,10 +534,11 @@ static void wm8995_update_class_w(struct snd_soc_codec *codec)
 static int check_clk_sys(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
        unsigned int reg;
        const char *clk;
 
-       reg = snd_soc_read(source->codec, WM8995_CLOCKING_1);
+       reg = snd_soc_read(codec, WM8995_CLOCKING_1);
        /* Check what we're currently using for CLK_SYS */
        if (reg & WM8995_SYSCLK_SRC)
                clk = "AIF2CLK";
@@ -560,9 +561,7 @@ static int wm8995_put_class_w(struct snd_kcontrol *kcontrol,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -611,10 +610,9 @@ static void dc_servo_cmd(struct snd_soc_codec *codec,
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int reg;
 
-       codec = w->codec;
        reg = snd_soc_read(codec, WM8995_ANALOGUE_HP_1);
 
        switch (event) {
@@ -761,9 +759,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec;
-
-       codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
@@ -2190,7 +2186,7 @@ static struct snd_soc_dai_driver wm8995_dai[] = {
        }
 };
 
-static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
+static const struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
        .probe = wm8995_probe,
        .remove = wm8995_remove,
        .set_bias_level = wm8995_set_bias_level,
@@ -2204,7 +2200,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
        .num_dapm_routes = ARRAY_SIZE(wm8995_intercon),
 };
 
-static struct regmap_config wm8995_regmap = {
+static const struct regmap_config wm8995_regmap = {
        .reg_bits = 16,
        .val_bits = 16,
 
index b1dcc11c1b23bd0134940d2f9571d14b9e1dac92..dc92d5e4e9426e8157104361d4a71f675769f00d 100644 (file)
@@ -599,7 +599,7 @@ static void wm8996_bg_disable(struct snd_soc_codec *codec)
 static int bg_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        int ret = 0;
 
        switch (event) {
@@ -634,7 +634,8 @@ static int cp_event(struct snd_soc_dapm_widget *w,
 static int rmv_short_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 
        /* Record which outputs we enabled */
        switch (event) {
@@ -758,7 +759,8 @@ static void wm8996_seq_notifier(struct snd_soc_dapm_context *dapm,
 static int dcs_start(struct snd_soc_dapm_widget *w,
                     struct snd_kcontrol *kcontrol, int event)
 {
-       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(w->codec);
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
index 7e8bfe27566bd10be11b0dfdc736bf346c02489a..a4d11770630cdd9bd169836c5e14e0f8dfc5633b 100644 (file)
@@ -84,7 +84,7 @@ static const struct reg_default wm8997_sysclk_reva_patch[] = {
 static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w,
                            struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
        struct regmap *regmap = arizona->regmap;
        const struct reg_default *patch = NULL;
@@ -610,13 +610,16 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
 
 SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM,
                   ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM,
                   ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
-                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+                  SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
+                  SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU),
 SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1,
                   ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev,
                   SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
index b1d946facd57f1796815f5f157848f0569d547b5..13a3f335ea5b6cb4bfeecd8ed0eb9ce13a1bb7ce 100644 (file)
@@ -734,7 +734,7 @@ static int configure_clock(struct snd_soc_codec *codec)
 static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
 
        /* This should be done on init() for bypass paths */
index 6ffe8dc4f3fad5ba5a08544bda7e062fecef3f79..60d243c904f529597399c408c8426c2ca879ccd6 100644 (file)
@@ -254,7 +254,7 @@ SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
 static int hp_ev(struct snd_soc_dapm_widget *w,
                 struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0);
 
        switch (event) {
index 3eddb18fefd156eaf1acd3b050b106b3d32ff3b5..5cc457ef8894f7c69ae7c4981ab7e2d6d08d135b 100644 (file)
@@ -344,23 +344,27 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec)
        struct snd_ac97 *ac97;
        int ret = 0;
 
-       ac97 = snd_soc_new_ac97_codec(codec);
+       ac97 = snd_soc_alloc_ac97_codec(codec);
        if (IS_ERR(ac97)) {
                ret = PTR_ERR(ac97);
                dev_err(codec->dev, "Failed to register AC97 codec\n");
                return ret;
        }
 
-       snd_soc_codec_set_drvdata(codec, ac97);
-
        ret = wm9705_reset(codec);
        if (ret)
-               goto reset_err;
+               goto err_put_device;
+
+       ret = device_add(&ac97->dev);
+       if (ret)
+               goto err_put_device;
+
+       snd_soc_codec_set_drvdata(codec, ac97);
 
        return 0;
 
-reset_err:
-       snd_soc_free_ac97_codec(ac97);
+err_put_device:
+       put_device(&ac97->dev);
        return ret;
 }
 
index e04643d2bb2412e334112cbb6ef15c8942cbf558..9517571e820d9576b9505be863a73f3c02116cb8 100644 (file)
@@ -666,7 +666,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
        struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
 
-       wm9712->ac97 = snd_soc_new_ac97_codec(codec);
+       wm9712->ac97 = snd_soc_alloc_ac97_codec(codec);
        if (IS_ERR(wm9712->ac97)) {
                ret = PTR_ERR(wm9712->ac97);
                dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
@@ -675,15 +675,19 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 
        ret = wm9712_reset(codec, 0);
        if (ret < 0)
-               goto reset_err;
+               goto err_put_device;
+
+       ret = device_add(&wm9712->ac97->dev);
+       if (ret)
+               goto err_put_device;
 
        /* set alc mux to none */
        ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
 
        return 0;
 
-reset_err:
-       snd_soc_free_ac97_codec(wm9712->ac97);
+err_put_device:
+       put_device(&wm9712->ac97->dev);
        return ret;
 }
 
index 71b9d5b0734d22c54284172184fede22fc4e5c48..68222917b396666b975cc2aa96e13d983bf52fc2 100644 (file)
@@ -217,7 +217,7 @@ SOC_SINGLE("3D Depth", AC97_REC_GAIN_MIC, 0, 15, 1),
 static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
                                 struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 status, rate;
 
        if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD))
@@ -1225,7 +1225,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
        struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
        int ret = 0, reg;
 
-       wm9713->ac97 = snd_soc_new_ac97_codec(codec);
+       wm9713->ac97 = snd_soc_alloc_ac97_codec(codec);
        if (IS_ERR(wm9713->ac97))
                return PTR_ERR(wm9713->ac97);
 
@@ -1234,7 +1234,11 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
        wm9713_reset(codec, 0);
        ret = wm9713_reset(codec, 1);
        if (ret < 0)
-               goto reset_err;
+               goto err_put_device;
+
+       ret = device_add(&wm9713->ac97->dev);
+       if (ret)
+               goto err_put_device;
 
        /* unmute the adc - move to kcontrol */
        reg = ac97_read(codec, AC97_CD) & 0x7fff;
@@ -1242,8 +1246,8 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
 
        return 0;
 
-reset_err:
-       snd_soc_free_ac97_codec(wm9713->ac97);
+err_put_device:
+       put_device(&wm9713->ac97->dev);
        return ret;
 }
 
index 720d6e852986c3e7c6b0b1128876b7c4c4fa4ffb..ff67b334065badc1011807648ac671a4d07765bf 100644 (file)
@@ -1373,7 +1373,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol,
                   int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
        struct wm_adsp_alg_region *alg_region;
@@ -1605,7 +1605,7 @@ err:
 int wm_adsp2_early_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
 
@@ -1626,7 +1626,7 @@ EXPORT_SYMBOL_GPL(wm_adsp2_early_event);
 int wm_adsp2_event(struct snd_soc_dapm_widget *w,
                   struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec);
        struct wm_adsp *dsp = &dsps[w->shift];
        struct wm_adsp_alg_region *alg_region;
index 374537d5e179c6615ec98e1787536659c4a83ff0..8366e19657a73708fc4d65f5c3a13a449618ca92 100644 (file)
@@ -500,7 +500,7 @@ SOC_SINGLE_TLV("LINEOUT2 Volume", WM8993_LINE_OUTPUTS_VOLUME, 0, 1, 1,
 static int hp_supply_event(struct snd_soc_dapm_widget *w,
                           struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
@@ -542,7 +542,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
 static int hp_event(struct snd_soc_dapm_widget *w,
                    struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        unsigned int reg = snd_soc_read(codec, WM8993_ANALOGUE_HP_0);
 
        switch (event) {
@@ -594,7 +594,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
 static int earpiece_event(struct snd_soc_dapm_widget *w,
                          struct snd_kcontrol *control, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        u16 reg = snd_soc_read(codec, WM8993_ANTIPOP1) & ~WM8993_HPOUT2_IN_ENA;
 
        switch (event) {
@@ -619,7 +619,7 @@ static int earpiece_event(struct snd_soc_dapm_widget *w,
 static int lineout_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *control, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        bool *flag;
 
@@ -649,7 +649,7 @@ static int lineout_event(struct snd_soc_dapm_widget *w,
 static int micbias_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
-       struct snd_soc_codec *codec = w->codec;
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
 
        switch (w->shift) {
index 8e948c63f3d96ec6dab93a2891d41f6eee0912da..2b81ca418d2a67d93087e0acd0fc896cb2478210 100644 (file)
@@ -58,13 +58,12 @@ choice
        depends on MACH_DAVINCI_DM365_EVM
 
 config SND_DM365_AIC3X_CODEC
-       bool "Audio Codec - AIC3101"
+       tristate "Audio Codec - AIC3101"
        help
          Say Y if you want to add support for AIC3101 audio codec
 
 config SND_DM365_VOICE_CODEC
        tristate "Voice Codec - CQ93VC"
-       depends on SND_DAVINCI_SOC
        select MFD_DAVINCI_VOICECODEC
        select SND_DAVINCI_SOC_VCIF
        select SND_SOC_CQ0093VC
index 158cb3d1db70c91fce6853e38a99c89dc63d6a95..b6bb5947a8a8435f5219d4d8efb541e842e531f4 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/timer.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/edma.h>
 #include <linux/i2c.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
 #include <asm/dma.h>
 #include <asm/mach-types.h>
 
-#include <linux/edma.h>
-
-#include "davinci-pcm.h"
-#include "davinci-i2s.h"
-
 struct snd_soc_card_drvdata_davinci {
        struct clk *mclk;
        unsigned sysclk;
index 30b94d4f9c5de369531713517adc2a9f1d3a46f7..de3b155a50116f4e533c8f22e0fc6b933e8040ae 100644 (file)
@@ -364,6 +364,20 @@ static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
        return IRQ_RETVAL(handled_mask);
 }
 
+static irqreturn_t davinci_mcasp_common_irq_handler(int irq, void *data)
+{
+       struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+       irqreturn_t ret = IRQ_NONE;
+
+       if (mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK])
+               ret = davinci_mcasp_tx_irq_handler(irq, data);
+
+       if (mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE])
+               ret |= davinci_mcasp_rx_irq_handler(irq, data);
+
+       return ret;
+}
+
 static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                                         unsigned int fmt)
 {
@@ -1313,16 +1327,19 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of(
 
        pdata->tx_dma_channel = dma_spec.args[0];
 
-       ret = of_property_match_string(np, "dma-names", "rx");
-       if (ret < 0)
-               goto nodata;
+       /* RX is not valid in DIT mode */
+       if (pdata->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               ret = of_property_match_string(np, "dma-names", "rx");
+               if (ret < 0)
+                       goto nodata;
 
-       ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
-                                        &dma_spec);
-       if (ret < 0)
-               goto nodata;
+               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells", ret,
+                                                &dma_spec);
+               if (ret < 0)
+                       goto nodata;
 
-       pdata->rx_dma_channel = dma_spec.args[0];
+               pdata->rx_dma_channel = dma_spec.args[0];
+       }
 
        ret = of_property_read_u32(np, "tx-num-evt", &val);
        if (ret >= 0)
@@ -1441,6 +1458,23 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
 
        mcasp->dev = &pdev->dev;
 
+       irq = platform_get_irq_byname(pdev, "common");
+       if (irq >= 0) {
+               irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_common\n",
+                                         dev_name(&pdev->dev));
+               ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                               davinci_mcasp_common_irq_handler,
+                                               IRQF_ONESHOT | IRQF_SHARED,
+                                               irq_name, mcasp);
+               if (ret) {
+                       dev_err(&pdev->dev, "common IRQ request failed\n");
+                       goto err;
+               }
+
+               mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
+               mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
+       }
+
        irq = platform_get_irq_byname(pdev, "rx");
        if (irq >= 0) {
                irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n",
@@ -1501,19 +1535,34 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        else
                dma_data->filter_data = &dma_params->channel;
 
-       dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
-       dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
-       dma_params->asp_chan_q = pdata->asp_chan_q;
-       dma_params->ram_chan_q = pdata->ram_chan_q;
-       dma_params->sram_pool = pdata->sram_pool;
-       dma_params->sram_size = pdata->sram_size_capture;
-       if (dat)
-               dma_params->dma_addr = dat->start;
-       else
-               dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
-
-       /* Unconditional dmaengine stuff */
-       dma_data->addr = dma_params->dma_addr;
+       /* RX is not valid in DIT mode */
+       if (mcasp->op_mode != DAVINCI_MCASP_DIT_MODE) {
+               dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE];
+               dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];
+               dma_params->asp_chan_q = pdata->asp_chan_q;
+               dma_params->ram_chan_q = pdata->ram_chan_q;
+               dma_params->sram_pool = pdata->sram_pool;
+               dma_params->sram_size = pdata->sram_size_capture;
+               if (dat)
+                       dma_params->dma_addr = dat->start;
+               else
+                       dma_params->dma_addr = mem->start + pdata->rx_dma_offset;
+
+               /* Unconditional dmaengine stuff */
+               dma_data->addr = dma_params->dma_addr;
+
+               res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (res)
+                       dma_params->channel = res->start;
+               else
+                       dma_params->channel = pdata->rx_dma_channel;
+
+               /* dmaengine filter data for DT and non-DT boot */
+               if (pdev->dev.of_node)
+                       dma_data->filter_data = "rx";
+               else
+                       dma_data->filter_data = &dma_params->channel;
+       }
 
        if (mcasp->version < MCASP_VERSION_3) {
                mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE;
@@ -1523,18 +1572,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
                mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (res)
-               dma_params->channel = res->start;
-       else
-               dma_params->channel = pdata->rx_dma_channel;
-
-       /* dmaengine filter data for DT and non-DT boot */
-       if (pdev->dev.of_node)
-               dma_data->filter_data = "rx";
-       else
-               dma_data->filter_data = &dma_params->channel;
-
        dev_set_drvdata(&pdev->dev, mcasp);
 
        mcasp_reparent_fck(pdev);
index e334900cf0b8e2bd740acaf60360f50251dcf280..d50e08517dce57502d6548d7852d5792c9c56ad7 100644 (file)
@@ -1,6 +1,7 @@
 config SND_DESIGNWARE_I2S
        tristate "Synopsys I2S Device Driver"
        depends on CLKDEV_LOOKUP
+       select SND_SOC_GENERIC_DMAENGINE_PCM
        help
         Say Y or M if you want to add support for I2S driver for
         Synopsys desigwnware I2S device. The device supports upto
index b93168d4f6489ee667d94d89a7271e6b4eba8ad5..a3e97b46b64e3871ec9362b231d19f9334628229 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
 
 /* common register for all channel */
 #define IER            0x000
 #define I2S_COMP_VERSION       0x01F8
 #define I2S_COMP_TYPE          0x01FC
 
+/*
+ * Component parameter register fields - define the I2S block's
+ * configuration.
+ */
+#define        COMP1_TX_WORDSIZE_3(r)  (((r) & GENMASK(27, 25)) >> 25)
+#define        COMP1_TX_WORDSIZE_2(r)  (((r) & GENMASK(24, 22)) >> 22)
+#define        COMP1_TX_WORDSIZE_1(r)  (((r) & GENMASK(21, 19)) >> 19)
+#define        COMP1_TX_WORDSIZE_0(r)  (((r) & GENMASK(18, 16)) >> 16)
+#define        COMP1_TX_CHANNELS(r)    (((r) & GENMASK(10, 9)) >> 9)
+#define        COMP1_RX_CHANNELS(r)    (((r) & GENMASK(8, 7)) >> 7)
+#define        COMP1_RX_ENABLED(r)     (((r) & BIT(6)) >> 6)
+#define        COMP1_TX_ENABLED(r)     (((r) & BIT(5)) >> 5)
+#define        COMP1_MODE_EN(r)        (((r) & BIT(4)) >> 4)
+#define        COMP1_FIFO_DEPTH_GLOBAL(r)      (((r) & GENMASK(3, 2)) >> 2)
+#define        COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0)
+
+#define        COMP2_RX_WORDSIZE_3(r)  (((r) & GENMASK(12, 10)) >> 10)
+#define        COMP2_RX_WORDSIZE_2(r)  (((r) & GENMASK(9, 7)) >> 7)
+#define        COMP2_RX_WORDSIZE_1(r)  (((r) & GENMASK(5, 3)) >> 3)
+#define        COMP2_RX_WORDSIZE_0(r)  (((r) & GENMASK(2, 0)) >> 0)
+
+/* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */
+#define        COMP_MAX_WORDSIZE       (1 << 3)
+#define        COMP_MAX_DATA_WIDTH     (1 << 2)
+
 #define MAX_CHANNEL_NUM                8
 #define MIN_CHANNEL_NUM                2
 
+union dw_i2s_snd_dma_data {
+       struct i2s_dma_data pd;
+       struct snd_dmaengine_dai_dma_data dt;
+};
+
 struct dw_i2s_dev {
        void __iomem *i2s_base;
        struct clk *clk;
@@ -65,8 +96,8 @@ struct dw_i2s_dev {
        struct device *dev;
 
        /* data related to DMA transfers b/w i2s and DMAC */
-       struct i2s_dma_data play_dma_data;
-       struct i2s_dma_data capture_dma_data;
+       union dw_i2s_snd_dma_data play_dma_data;
+       union dw_i2s_snd_dma_data capture_dma_data;
        struct i2s_clk_config_data config;
        int (*i2s_clk_cfg)(struct i2s_clk_config_data *config);
 };
@@ -153,7 +184,7 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream,
                struct snd_soc_dai *cpu_dai)
 {
        struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
-       struct i2s_dma_data *dma_data = NULL;
+       union dw_i2s_snd_dma_data *dma_data = NULL;
 
        if (!(dev->capability & DWC_I2S_RECORD) &&
                        (substream->stream == SNDRV_PCM_STREAM_CAPTURE))
@@ -209,16 +240,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
 
        switch (config->chan_nr) {
        case EIGHT_CHANNEL_SUPPORT:
-               ch_reg = 3;
-               break;
        case SIX_CHANNEL_SUPPORT:
-               ch_reg = 2;
-               break;
        case FOUR_CHANNEL_SUPPORT:
-               ch_reg = 1;
-               break;
        case TWO_CHANNEL_SUPPORT:
-               ch_reg = 0;
                break;
        default:
                dev_err(dev->dev, "channel not supported\n");
@@ -227,31 +251,43 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
 
        i2s_disable_channels(dev, substream->stream);
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution);
-               i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
-               irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
-               i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
-               i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
-       } else {
-               i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution);
-               i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
-               irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
-               i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
-               i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+       for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) {
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       i2s_write_reg(dev->i2s_base, TCR(ch_reg),
+                                     xfer_resolution);
+                       i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02);
+                       irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+                       i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30);
+                       i2s_write_reg(dev->i2s_base, TER(ch_reg), 1);
+               } else {
+                       i2s_write_reg(dev->i2s_base, RCR(ch_reg),
+                                     xfer_resolution);
+                       i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07);
+                       irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg));
+                       i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03);
+                       i2s_write_reg(dev->i2s_base, RER(ch_reg), 1);
+               }
        }
 
        i2s_write_reg(dev->i2s_base, CCR, ccr);
 
        config->sample_rate = params_rate(params);
 
-       if (!dev->i2s_clk_cfg)
-               return -EINVAL;
+       if (dev->i2s_clk_cfg) {
+               ret = dev->i2s_clk_cfg(config);
+               if (ret < 0) {
+                       dev_err(dev->dev, "runtime audio clk config fail\n");
+                       return ret;
+               }
+       } else {
+               u32 bitclk = config->sample_rate * config->data_width * 2;
 
-       ret = dev->i2s_clk_cfg(config);
-       if (ret < 0) {
-               dev_err(dev->dev, "runtime audio clk config fail\n");
-               return ret;
+               ret = clk_set_rate(dev->clk, bitclk);
+               if (ret) {
+                       dev_err(dev->dev, "Can't set I2S clock rate: %d\n",
+                               ret);
+                       return ret;
+               }
        }
 
        return 0;
@@ -263,6 +299,19 @@ static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
        snd_soc_dai_set_dma_data(dai, substream, NULL);
 }
 
+static int dw_i2s_prepare(struct snd_pcm_substream *substream,
+                         struct snd_soc_dai *dai)
+{
+       struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               i2s_write_reg(dev->i2s_base, TXFFR, 1);
+       else
+               i2s_write_reg(dev->i2s_base, RXFFR, 1);
+
+       return 0;
+}
+
 static int dw_i2s_trigger(struct snd_pcm_substream *substream,
                int cmd, struct snd_soc_dai *dai)
 {
@@ -294,6 +343,7 @@ static struct snd_soc_dai_ops dw_i2s_dai_ops = {
        .startup        = dw_i2s_startup,
        .shutdown       = dw_i2s_shutdown,
        .hw_params      = dw_i2s_hw_params,
+       .prepare        = dw_i2s_prepare,
        .trigger        = dw_i2s_trigger,
 };
 
@@ -324,20 +374,162 @@ static int dw_i2s_resume(struct snd_soc_dai *dai)
 #define dw_i2s_resume  NULL
 #endif
 
+/*
+ * The following tables allow a direct lookup of various parameters
+ * defined in the I2S block's configuration in terms of sound system
+ * parameters.  Each table is sized to the number of entries possible
+ * according to the number of configuration bits describing an I2S
+ * block parameter.
+ */
+
+/* Maximum bit resolution of a channel - not uniformly spaced */
+static const u32 fifo_width[COMP_MAX_WORDSIZE] = {
+       12, 16, 20, 24, 32, 0, 0, 0
+};
+
+/* Width of (DMA) bus */
+static const u32 bus_widths[COMP_MAX_DATA_WIDTH] = {
+       DMA_SLAVE_BUSWIDTH_1_BYTE,
+       DMA_SLAVE_BUSWIDTH_2_BYTES,
+       DMA_SLAVE_BUSWIDTH_4_BYTES,
+       DMA_SLAVE_BUSWIDTH_UNDEFINED
+};
+
+/* PCM format to support channel resolution */
+static const u32 formats[COMP_MAX_WORDSIZE] = {
+       SNDRV_PCM_FMTBIT_S16_LE,
+       SNDRV_PCM_FMTBIT_S16_LE,
+       SNDRV_PCM_FMTBIT_S24_LE,
+       SNDRV_PCM_FMTBIT_S24_LE,
+       SNDRV_PCM_FMTBIT_S32_LE,
+       0,
+       0,
+       0
+};
+
+static int dw_configure_dai(struct dw_i2s_dev *dev,
+                                  struct snd_soc_dai_driver *dw_i2s_dai,
+                                  unsigned int rates)
+{
+       /*
+        * Read component parameter registers to extract
+        * the I2S block's configuration.
+        */
+       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+       u32 idx;
+
+       if (COMP1_TX_ENABLED(comp1)) {
+               dev_dbg(dev->dev, " designware: play supported\n");
+               idx = COMP1_TX_WORDSIZE_0(comp1);
+               if (WARN_ON(idx >= ARRAY_SIZE(formats)))
+                       return -EINVAL;
+               dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
+               dw_i2s_dai->playback.channels_max =
+                               1 << (COMP1_TX_CHANNELS(comp1) + 1);
+               dw_i2s_dai->playback.formats = formats[idx];
+               dw_i2s_dai->playback.rates = rates;
+       }
+
+       if (COMP1_RX_ENABLED(comp1)) {
+               dev_dbg(dev->dev, "designware: record supported\n");
+               idx = COMP2_RX_WORDSIZE_0(comp2);
+               if (WARN_ON(idx >= ARRAY_SIZE(formats)))
+                       return -EINVAL;
+               dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
+               dw_i2s_dai->capture.channels_max =
+                               1 << (COMP1_RX_CHANNELS(comp1) + 1);
+               dw_i2s_dai->capture.formats = formats[idx];
+               dw_i2s_dai->capture.rates = rates;
+       }
+
+       return 0;
+}
+
+static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev,
+                                  struct snd_soc_dai_driver *dw_i2s_dai,
+                                  struct resource *res,
+                                  const struct i2s_platform_data *pdata)
+{
+       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 idx = COMP1_APB_DATA_WIDTH(comp1);
+       int ret;
+
+       if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
+               return -EINVAL;
+
+       ret = dw_configure_dai(dev, dw_i2s_dai, pdata->snd_rates);
+       if (ret < 0)
+               return ret;
+
+       /* Set DMA slaves info */
+       dev->play_dma_data.pd.data = pdata->play_dma_data;
+       dev->capture_dma_data.pd.data = pdata->capture_dma_data;
+       dev->play_dma_data.pd.addr = res->start + I2S_TXDMA;
+       dev->capture_dma_data.pd.addr = res->start + I2S_RXDMA;
+       dev->play_dma_data.pd.max_burst = 16;
+       dev->capture_dma_data.pd.max_burst = 16;
+       dev->play_dma_data.pd.addr_width = bus_widths[idx];
+       dev->capture_dma_data.pd.addr_width = bus_widths[idx];
+       dev->play_dma_data.pd.filter = pdata->filter;
+       dev->capture_dma_data.pd.filter = pdata->filter;
+
+       return 0;
+}
+
+static int dw_configure_dai_by_dt(struct dw_i2s_dev *dev,
+                                  struct snd_soc_dai_driver *dw_i2s_dai,
+                                  struct resource *res)
+{
+       u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1);
+       u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2);
+       u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1));
+       u32 idx = COMP1_APB_DATA_WIDTH(comp1);
+       u32 idx2;
+       int ret;
+
+       if (WARN_ON(idx >= ARRAY_SIZE(bus_widths)))
+               return -EINVAL;
+
+       ret = dw_configure_dai(dev, dw_i2s_dai, SNDRV_PCM_RATE_8000_192000);
+       if (ret < 0)
+               return ret;
+
+       if (COMP1_TX_ENABLED(comp1)) {
+               idx2 = COMP1_TX_WORDSIZE_0(comp1);
+
+               dev->capability |= DWC_I2S_PLAY;
+               dev->play_dma_data.dt.addr = res->start + I2S_TXDMA;
+               dev->play_dma_data.dt.addr_width = bus_widths[idx];
+               dev->play_dma_data.dt.chan_name = "TX";
+               dev->play_dma_data.dt.fifo_size = fifo_depth *
+                       (fifo_width[idx2]) >> 8;
+               dev->play_dma_data.dt.maxburst = 16;
+       }
+       if (COMP1_RX_ENABLED(comp1)) {
+               idx2 = COMP2_RX_WORDSIZE_0(comp2);
+
+               dev->capability |= DWC_I2S_RECORD;
+               dev->capture_dma_data.dt.addr = res->start + I2S_RXDMA;
+               dev->capture_dma_data.dt.addr_width = bus_widths[idx];
+               dev->capture_dma_data.dt.chan_name = "RX";
+               dev->capture_dma_data.dt.fifo_size = fifo_depth *
+                       (fifo_width[idx2] >> 8);
+               dev->capture_dma_data.dt.maxburst = 16;
+       }
+
+       return 0;
+
+}
+
 static int dw_i2s_probe(struct platform_device *pdev)
 {
        const struct i2s_platform_data *pdata = pdev->dev.platform_data;
        struct dw_i2s_dev *dev;
        struct resource *res;
        int ret;
-       unsigned int cap;
        struct snd_soc_dai_driver *dw_i2s_dai;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "Invalid platform data\n");
-               return -EINVAL;
-       }
-
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev) {
                dev_warn(&pdev->dev, "kzalloc fail\n");
@@ -345,83 +537,67 @@ static int dw_i2s_probe(struct platform_device *pdev)
        }
 
        dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
-       if (!dw_i2s_dai) {
-               dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
+       if (!dw_i2s_dai)
                return -ENOMEM;
-       }
 
        dw_i2s_dai->ops = &dw_i2s_dai_ops;
        dw_i2s_dai->suspend = dw_i2s_suspend;
        dw_i2s_dai->resume = dw_i2s_resume;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no i2s resource defined\n");
-               return -ENODEV;
-       }
-
        dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dev->i2s_base)) {
-               dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+       if (IS_ERR(dev->i2s_base))
                return PTR_ERR(dev->i2s_base);
-       }
 
-       cap = pdata->cap;
-       dev->capability = cap;
-       dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+       dev->dev = &pdev->dev;
+       if (pdata) {
+               ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata);
+               if (ret < 0)
+                       return ret;
+
+               dev->capability = pdata->cap;
+               dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
+               if (!dev->i2s_clk_cfg) {
+                       dev_err(&pdev->dev, "no clock configure method\n");
+                       return -ENODEV;
+               }
 
-       /* Set DMA slaves info */
+               dev->clk = devm_clk_get(&pdev->dev, NULL);
+       } else {
+               ret = dw_configure_dai_by_dt(dev, dw_i2s_dai, res);
+               if (ret < 0)
+                       return ret;
 
-       dev->play_dma_data.data = pdata->play_dma_data;
-       dev->capture_dma_data.data = pdata->capture_dma_data;
-       dev->play_dma_data.addr = res->start + I2S_TXDMA;
-       dev->capture_dma_data.addr = res->start + I2S_RXDMA;
-       dev->play_dma_data.max_burst = 16;
-       dev->capture_dma_data.max_burst = 16;
-       dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-       dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
-       dev->play_dma_data.filter = pdata->filter;
-       dev->capture_dma_data.filter = pdata->filter;
-
-       dev->clk = clk_get(&pdev->dev, NULL);
+               dev->clk = devm_clk_get(&pdev->dev, "i2sclk");
+       }
        if (IS_ERR(dev->clk))
-               return  PTR_ERR(dev->clk);
+               return PTR_ERR(dev->clk);
 
-       ret = clk_enable(dev->clk);
+       ret = clk_prepare_enable(dev->clk);
        if (ret < 0)
-               goto err_clk_put;
-
-       if (cap & DWC_I2S_PLAY) {
-               dev_dbg(&pdev->dev, " designware: play supported\n");
-               dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
-               dw_i2s_dai->playback.channels_max = pdata->channel;
-               dw_i2s_dai->playback.formats = pdata->snd_fmts;
-               dw_i2s_dai->playback.rates = pdata->snd_rates;
-       }
-
-       if (cap & DWC_I2S_RECORD) {
-               dev_dbg(&pdev->dev, "designware: record supported\n");
-               dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM;
-               dw_i2s_dai->capture.channels_max = pdata->channel;
-               dw_i2s_dai->capture.formats = pdata->snd_fmts;
-               dw_i2s_dai->capture.rates = pdata->snd_rates;
-       }
+               return ret;
 
-       dev->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, dev);
-       ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
+       ret = devm_snd_soc_register_component(&pdev->dev, &dw_i2s_component,
                                         dw_i2s_dai, 1);
        if (ret != 0) {
                dev_err(&pdev->dev, "not able to register dai\n");
                goto err_clk_disable;
        }
 
+       if (!pdata) {
+               ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Could not register PCM: %d\n", ret);
+                       goto err_clk_disable;
+               }
+       }
+
        return 0;
 
 err_clk_disable:
-       clk_disable(dev->clk);
-err_clk_put:
-       clk_put(dev->clk);
+       clk_disable_unprepare(dev->clk);
        return ret;
 }
 
@@ -429,18 +605,26 @@ static int dw_i2s_remove(struct platform_device *pdev)
 {
        struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev);
 
-       snd_soc_unregister_component(&pdev->dev);
-
-       clk_put(dev->clk);
+       clk_disable_unprepare(dev->clk);
 
        return 0;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id dw_i2s_of_match[] = {
+       { .compatible = "snps,designware-i2s",   },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dw_i2s_of_match);
+#endif
+
 static struct platform_driver dw_i2s_driver = {
        .probe          = dw_i2s_probe,
        .remove         = dw_i2s_remove,
        .driver         = {
                .name   = "designware-i2s",
+               .of_match_table = of_match_ptr(dw_i2s_of_match),
        },
 };
 
index 9ce70fc67b0950b432a5be5d5e23d6cd4e631f43..e1aa3834b101e6cf19f4e1adac4b4e7cb1f074f0 100644 (file)
@@ -42,25 +42,6 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       /* fsl_ssi lacks the set_fmt ops. */
-       if (ret && ret != -ENOTSUPP) {
-               dev_err(cpu_dai->dev,
-                       "Failed to set the cpu dai format.\n");
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               dev_err(cpu_dai->dev,
-                       "Failed to set the codec format.\n");
-               return ret;
-       }
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                     CODEC_CLOCK, SND_SOC_CLOCK_OUT);
        if (ret) {
@@ -69,7 +50,7 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+       snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
 
        ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
                                SND_SOC_CLOCK_IN);
@@ -91,6 +72,8 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = {
        .name           = "tlv320aic23",
        .stream_name    = "TLV320AIC23",
        .codec_dai_name = "tlv320aic23-hifi",
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBM_CFM,
        .ops            = &eukrea_tlv320_snd_ops,
 };
 
index 026a80117540be10568d92d2d95f000295c7074c..c068494bae305caaf1015f92636e32e16e475a55 100644 (file)
@@ -818,7 +818,6 @@ static int fsl_asrc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        asrc_priv->pdev = pdev;
-       strncpy(asrc_priv->name, np->name, sizeof(asrc_priv->name) - 1);
 
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -837,12 +836,12 @@ static int fsl_asrc_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
        ret = devm_request_irq(&pdev->dev, irq, fsl_asrc_isr, 0,
-                              asrc_priv->name, asrc_priv);
+                              dev_name(&pdev->dev), asrc_priv);
        if (ret) {
                dev_err(&pdev->dev, "failed to claim irq %u: %d\n", irq, ret);
                return ret;
index a3f211f53c23bfdf08d34acc0e518e79ce50f0e3..4aed63c4b431b519f3bccaa8f138bfabd1dcb6bf 100644 (file)
@@ -433,7 +433,6 @@ struct fsl_asrc_pair {
  * @channel_avail: non-occupied channel numbers
  * @asrc_rate: default sample rate for ASoC Back-Ends
  * @asrc_width: default sample width for ASoC Back-Ends
- * @name: driver name
  */
 struct fsl_asrc {
        struct snd_dmaengine_dai_dma_data dma_params_rx;
@@ -452,8 +451,6 @@ struct fsl_asrc {
 
        int asrc_rate;
        int asrc_width;
-
-       char name[32];
 };
 
 extern struct snd_soc_platform_driver fsl_asrc_platform;
index 1c08ab13637c6c5d65fb823f60db7c65538d07f6..5c7597191e3ffc682d1f813cdd9a6da8afbde397 100644 (file)
@@ -774,7 +774,7 @@ static int fsl_esai_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
index 91a550f4a10dc7e0156efd8389fc3ba90bb15955..5e793bbb6b02be5f4a628f52755c09564c4a72fd 100644 (file)
 #define ESAI_xCCR_xFP_MASK     (((1 << ESAI_xCCR_xFP_WIDTH) - 1) << ESAI_xCCR_xFP_SHIFT)
 #define ESAI_xCCR_xFP(v)       ((((v) - 1) << ESAI_xCCR_xFP_SHIFT) & ESAI_xCCR_xFP_MASK)
 #define ESAI_xCCR_xDC_SHIFT     9
-#define ESAI_xCCR_xDC_WIDTH    4
+#define ESAI_xCCR_xDC_WIDTH    5
 #define ESAI_xCCR_xDC_MASK     (((1 << ESAI_xCCR_xDC_WIDTH) - 1) << ESAI_xCCR_xDC_SHIFT)
 #define ESAI_xCCR_xDC(v)       ((((v) - 1) << ESAI_xCCR_xDC_SHIFT) & ESAI_xCCR_xDC_MASK)
 #define ESAI_xCCR_xPSR_SHIFT   8
index 032d2d33619c20be9aa9d63c807a238af26417b6..ec79c3d5e65e28acb24b6be4190a1fe091252e7a 100644 (file)
@@ -612,7 +612,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
index af0429421fc8b4997874777acf58950908ec317f..75870c0ea2c9f613d9b4ebe3e10efd53430e5363 100644 (file)
@@ -90,7 +90,6 @@ struct spdif_mixer_control {
  * @sysclk: system clock for rx clock rate measurement
  * @dma_params_tx: DMA parameters for transmit channel
  * @dma_params_rx: DMA parameters for receive channel
- * @name: driver name
  */
 struct fsl_spdif_priv {
        struct spdif_mixer_control fsl_spdif_control;
@@ -109,12 +108,8 @@ struct fsl_spdif_priv {
        struct clk *sysclk;
        struct snd_dmaengine_dai_dma_data dma_params_tx;
        struct snd_dmaengine_dai_dma_data dma_params_rx;
-
-       /* The name space will be allocated dynamically */
-       char name[0];
 };
 
-
 /* DPLL locked and lock loss interrupt handler */
 static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
 {
@@ -1169,19 +1164,15 @@ static int fsl_spdif_probe(struct platform_device *pdev)
        if (!np)
                return -ENODEV;
 
-       spdif_priv = devm_kzalloc(&pdev->dev,
-                       sizeof(struct fsl_spdif_priv) + strlen(np->name) + 1,
-                       GFP_KERNEL);
+       spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL);
        if (!spdif_priv)
                return -ENOMEM;
 
-       strcpy(spdif_priv->name, np->name);
-
        spdif_priv->pdev = pdev;
 
        /* Initialize this copy of the CPU DAI driver structure */
        memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
-       spdif_priv->cpu_dai_drv.name = spdif_priv->name;
+       spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
 
        /* Get the addresses and IRQ */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1198,12 +1189,12 @@ static int fsl_spdif_probe(struct platform_device *pdev)
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
                return irq;
        }
 
        ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
-                       spdif_priv->name, spdif_priv);
+                              dev_name(&pdev->dev), spdif_priv);
        if (ret) {
                dev_err(&pdev->dev, "could not claim irq %u\n", irq);
                return ret;
index a65f17d57ffb44733b7858364678581308dea040..2595611e8a6ded3876345767bde2ce51e079c9ee 100644 (file)
@@ -160,7 +160,7 @@ struct fsl_ssi_soc_data {
  */
 struct fsl_ssi_private {
        struct regmap *regs;
-       unsigned int irq;
+       int irq;
        struct snd_soc_dai_driver cpu_dai_drv;
 
        unsigned int dai_fmt;
@@ -992,8 +992,8 @@ static int fsl_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
        regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN,
                        CCSR_SSI_SCR_SSIEN);
 
-       regmap_write(regs, CCSR_SSI_STMSK, tx_mask);
-       regmap_write(regs, CCSR_SSI_SRMSK, rx_mask);
+       regmap_write(regs, CCSR_SSI_STMSK, ~tx_mask);
+       regmap_write(regs, CCSR_SSI_SRMSK, ~rx_mask);
 
        regmap_update_bits(regs, CCSR_SSI_SCR, CCSR_SSI_SCR_SSIEN, val);
 
@@ -1363,8 +1363,8 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        ssi_private->irq = platform_get_irq(pdev, 0);
        if (!ssi_private->irq) {
-               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
-               return -ENXIO;
+               dev_err(&pdev->dev, "no irq for node %s\n", pdev->name);
+               return ssi_private->irq;
        }
 
        /* Are the RX and the TX clocks locked? */
index 2ac7755da8768dfe2b12a9d35a5aa5eda9e1d766..b9e42b503a37728b8a20a14a3979ada69ed82872 100644 (file)
@@ -86,33 +86,6 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np,
 }
 EXPORT_SYMBOL(fsl_asoc_get_dma_channel);
 
-/**
- * fsl_asoc_xlate_tdm_slot_mask - generate TDM slot TX/RX mask.
- *
- * @slots: Number of slots in use.
- * @tx_mask: bitmask representing active TX slots.
- * @rx_mask: bitmask representing active RX slots.
- *
- * This function used to generate the TDM slot TX/RX mask. And the TX/RX
- * mask will use a 0 bit for an active slot as default, and the default
- * active bits are at the LSB of the mask value.
- */
-int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
-                                   unsigned int *tx_mask,
-                                   unsigned int *rx_mask)
-{
-       if (!slots)
-               return -EINVAL;
-
-       if (tx_mask)
-               *tx_mask = ~((1 << slots) - 1);
-       if (rx_mask)
-               *rx_mask = ~((1 << slots) - 1);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(fsl_asoc_xlate_tdm_slot_mask);
-
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Freescale ASoC utility code");
 MODULE_LICENSE("GPL v2");
index df535db40313e61ae25d6e46ba68a149c5e62346..1687b66ef18eb5dee972d28fd1da334fa3fe6b6d 100644 (file)
@@ -22,7 +22,4 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name,
                             struct snd_soc_dai_link *dai,
                             unsigned int *dma_channel_id,
                             unsigned int *dma_id);
-int fsl_asoc_xlate_tdm_slot_mask(unsigned int slots,
-                                   unsigned int *tx_mask,
-                                   unsigned int *rx_mask);
 #endif /* _FSL_UTILS_H */
index 6bf5bce01a92124cbf8e84eeb67157fa8727a0f4..9e6493d4e7ff92e6a328dfa2d062349a314d88a0 100644 (file)
@@ -37,8 +37,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
 
-       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xfffffffc, 0xfffffffc,
-                                       4, 16);
+       ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 0x3, 4, 16);
        if (ret)
                return ret;
 
@@ -46,7 +45,7 @@ static int imx_mc13783_hifi_hw_params(struct snd_pcm_substream *substream,
        if (ret)
                return ret;
 
-       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x0, 0xfffffffc, 2, 16);
+       ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 16);
        if (ret)
                return ret;
 
index e94704f1b9ee52ed5dcea4006c6321ff30e26a6b..33da26a1245718f4b6e814bb22e04218ecc340fc 100644 (file)
@@ -60,6 +60,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
        data->card.dev = &pdev->dev;
        data->card.dai_link = &data->dai;
        data->card.num_links = 1;
+       data->card.owner = THIS_MODULE;
 
        ret = snd_soc_of_parse_card_name(&data->card, "model");
        if (ret)
index fa801e17c51e6222abbbce12e40e5cc9f50a56c2..461ce27b884f0f0b22dd6bb03216a1ee05f7e0fc 100644 (file)
@@ -74,8 +74,8 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        sccr |= SSI_STCCR_DC(slots - 1);
        writel(sccr, ssi->base + SSI_SRCCR);
 
-       writel(tx_mask, ssi->base + SSI_STMSK);
-       writel(rx_mask, ssi->base + SSI_SRMSK);
+       writel(~tx_mask, ssi->base + SSI_STMSK);
+       writel(~rx_mask, ssi->base + SSI_SRMSK);
 
        return 0;
 }
@@ -340,7 +340,6 @@ static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
        .set_fmt        = imx_ssi_set_dai_fmt,
        .set_clkdiv     = imx_ssi_set_dai_clkdiv,
        .set_sysclk     = imx_ssi_set_dai_sysclk,
-       .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask,
        .set_tdm_slot   = imx_ssi_set_dai_tdm_slot,
        .trigger        = imx_ssi_trigger,
 };
index 4caacb05a62324e404811e45768ec17eed0973ea..cd146d4fa8054fb0980abdda8a9fc506c1c4ef98 100644 (file)
@@ -257,6 +257,7 @@ static int imx_wm8962_probe(struct platform_device *pdev)
        if (ret)
                goto clk_fail;
        data->card.num_links = 1;
+       data->card.owner = THIS_MODULE;
        data->card.dai_link = &data->dai;
        data->card.dapm_widgets = imx_wm8962_dapm_widgets;
        data->card.num_dapm_widgets = ARRAY_SIZE(imx_wm8962_dapm_widgets);
index b1ced7b8d80c472be45f1d578c622db1f07275fa..198eeb3f3f7a05b570f7a1e280b7228ce7cb0706 100644 (file)
@@ -55,16 +55,6 @@ static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
-       u32 dai_format;
-
-       dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM;
-
-       /* set codec DAI configuration */
-       snd_soc_dai_set_fmt(codec_dai, dai_format);
-
-       /* set cpu DAI configuration */
-       snd_soc_dai_set_fmt(cpu_dai, dai_format);
 
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                     25000000, SND_SOC_CLOCK_OUT);
@@ -164,6 +154,8 @@ static struct snd_soc_dai_link mx27vis_aic32x4_dai = {
        .platform_name  = "imx-ssi.0",
        .codec_name     = "tlv320aic32x4.0-0018",
        .cpu_dai_name   = "imx-ssi.0",
+       .dai_fmt        = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBM_CFM,
        .ops            = &mx27vis_aic32x4_snd_ops,
 };
 
index 804749a6c61e3241763eace3f935f95b978a0d17..a958937ab405ce0d79e43942942c875ad69f66da 100644 (file)
@@ -87,7 +87,6 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
        snd_pcm_format_t format = params_format(params);
        unsigned int rate = params_rate(params);
        unsigned int channels = params_channels(params);
-       u32 dai_format;
 
        /* find the correct audio parameters */
        for (i = 0; i < ARRAY_SIZE(wm8350_audio); i++) {
@@ -104,22 +103,13 @@ static int wm1133_ev1_hw_params(struct snd_pcm_substream *substream,
        /* codec FLL input is 14.75 MHz from MCLK */
        snd_soc_dai_set_pll(codec_dai, 0, 0, 14750000, wm8350_audio[i].sysclk);
 
-       dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM;
-
-       /* set codec DAI configuration */
-       snd_soc_dai_set_fmt(codec_dai, dai_format);
-
-       /* set cpu DAI configuration */
-       snd_soc_dai_set_fmt(cpu_dai, dai_format);
-
        /* TODO: The SSI driver should figure this out for us */
        switch (channels) {
        case 2:
-               snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
+               snd_soc_dai_set_tdm_slot(cpu_dai, 0x3, 0x3, 2, 0);
                break;
        case 1:
-               snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffe, 0xffffffe, 1, 0);
+               snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 0);
                break;
        default:
                return -EINVAL;
@@ -244,6 +234,8 @@ static struct snd_soc_dai_link wm1133_ev1_dai = {
        .init = wm1133_ev1_init,
        .ops = &wm1133_ev1_ops,
        .symmetric_rates = 1,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
 };
 
 static struct snd_soc_card wm1133_ev1 = {
index fb9240fdc9b70095d364e3e90e14c16653ca4aff..f7c6734bd5daee1dafd76ba8b6feafa05b2a6c52 100644 (file)
@@ -39,6 +39,37 @@ struct simple_card_data {
 #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
 #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
 
+static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props =
+               &priv->dai_props[rtd - rtd->card->rtd];
+       int ret;
+
+       ret = clk_prepare_enable(dai_props->cpu_dai.clk);
+       if (ret)
+               return ret;
+       
+       ret = clk_prepare_enable(dai_props->codec_dai.clk);
+       if (ret)
+               clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+       return ret;
+}
+
+static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+       struct simple_dai_props *dai_props =
+               &priv->dai_props[rtd - rtd->card->rtd];
+
+       clk_disable_unprepare(dai_props->cpu_dai.clk);
+
+       clk_disable_unprepare(dai_props->codec_dai.clk);
+}
+
 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params *params)
 {
@@ -58,6 +89,8 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 }
 
 static struct snd_soc_ops asoc_simple_card_ops = {
+       .startup = asoc_simple_card_startup,
+       .shutdown = asoc_simple_card_shutdown,
        .hw_params = asoc_simple_card_hw_params,
 };
 
@@ -219,6 +252,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
                }
 
                dai->sysclk = clk_get_rate(clk);
+               dai->clk = clk;
        } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
                dai->sysclk = val;
        } else {
@@ -452,9 +486,8 @@ static int asoc_simple_card_parse_of(struct device_node *node,
 }
 
 /* Decrease the reference count of the device nodes */
-static int asoc_simple_card_unref(struct platform_device *pdev)
+static int asoc_simple_card_unref(struct snd_soc_card *card)
 {
-       struct snd_soc_card *card = platform_get_drvdata(pdev);
        struct snd_soc_dai_link *dai_link;
        int num_links;
 
@@ -556,7 +589,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
                return ret;
 
 err:
-       asoc_simple_card_unref(pdev);
+       asoc_simple_card_unref(&priv->snd_card);
        return ret;
 }
 
@@ -572,7 +605,7 @@ static int asoc_simple_card_remove(struct platform_device *pdev)
                snd_soc_jack_free_gpios(&simple_card_mic_jack, 1,
                                        &simple_card_mic_jack_gpio);
 
-       return asoc_simple_card_unref(pdev);
+       return asoc_simple_card_unref(card);
 }
 
 static const struct of_device_id asoc_simple_of_match[] = {
index e989ecf046c953a7ad79e7c464123909059a7f2a..c0813f546d1f319c6121d31f78e68f8e5ddda026 100644 (file)
@@ -46,7 +46,7 @@ config SND_SOC_INTEL_BAYTRAIL
 
 config SND_SOC_INTEL_HASWELL_MACH
        tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
-       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\
+       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \
                   I2C_DESIGNWARE_PLATFORM
        select SND_SOC_INTEL_HASWELL
        select SND_SOC_RT5640
@@ -76,7 +76,7 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
 
 config SND_SOC_INTEL_BROADWELL_MACH
        tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
-       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\
+       depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \
                   I2C_DESIGNWARE_PLATFORM
        select SND_SOC_INTEL_HASWELL
        select SND_COMPRESS_OFFLOAD
@@ -89,7 +89,7 @@ config SND_SOC_INTEL_BROADWELL_MACH
 
 config SND_SOC_INTEL_BYTCR_RT5640_MACH
        tristate "ASoC Audio DSP Support for MID BYT Platform"
-       depends on X86
+       depends on X86 && I2C
        select SND_SOC_RT5640
        select SND_SST_MFLD_PLATFORM
        select SND_SST_IPC_ACPI
@@ -101,7 +101,7 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH
 
 config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
         tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
-        depends on X86_INTEL_LPSS
+        depends on X86_INTEL_LPSS && I2C
         select SND_SOC_RT5670
         select SND_SST_MFLD_PLATFORM
         select SND_SST_IPC_ACPI
index 7cf95d5d5d808f77d0558ecb8a521bdd1e26f541..9cf7d01479adcbd82661c70344b5f5d4ad0969fe 100644 (file)
@@ -140,8 +140,6 @@ static struct snd_soc_ops broadwell_rt286_ops = {
 
 static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev);
        struct sst_hsw *broadwell = pdata->dsp;
        int ret;
@@ -155,14 +153,6 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
                return ret;
        }
 
-       /* always connected - check HP for jack detect */
-       snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
-       snd_soc_dapm_enable_pin(dapm, "Speaker");
-       snd_soc_dapm_enable_pin(dapm, "Mic Jack");
-       snd_soc_dapm_enable_pin(dapm, "Line Jack");
-       snd_soc_dapm_enable_pin(dapm, "DMIC1");
-       snd_soc_dapm_enable_pin(dapm, "DMIC2");
-
        return 0;
 }
 
index 0cba7830c5e9df4d20ce90bab96625bf0596ff4b..354eaad886e1c09619b0d1e2f1269b9ef715aa3a 100644 (file)
@@ -132,7 +132,6 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
        struct snd_soc_codec *codec = runtime->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        struct snd_soc_card *card = runtime->card;
        const struct snd_soc_dapm_route *custom_map;
        int num_routes;
@@ -161,7 +160,7 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
        }
 
-       ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes);
+       ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
        if (ret)
                return ret;
 
@@ -171,13 +170,8 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
                        return ret;
        }
 
-       snd_soc_dapm_ignore_suspend(dapm, "HPOL");
-       snd_soc_dapm_ignore_suspend(dapm, "HPOR");
-
-       snd_soc_dapm_ignore_suspend(dapm, "SPOLP");
-       snd_soc_dapm_ignore_suspend(dapm, "SPOLN");
-       snd_soc_dapm_ignore_suspend(dapm, "SPORP");
-       snd_soc_dapm_ignore_suspend(dapm, "SPORN");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
+       snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
 
        return ret;
 }
index f5d0fc1ab10c1efea603c568219b76735fc45db0..59308629043e62dd2c2fa0bcc9e4cb126d7a74ba 100644 (file)
@@ -215,7 +215,6 @@ static int snd_byt_mc_probe(struct platform_device *pdev)
 
 static struct platform_driver snd_byt_mc_driver = {
        .driver = {
-               .owner = THIS_MODULE,
                .name = "bytt100_rt5640",
                .pm = &snd_soc_pm_ops,
        },
@@ -227,4 +226,4 @@ module_platform_driver(snd_byt_mc_driver);
 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
 MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:bytrt5640-audio");
+MODULE_ALIAS("platform:bytt100_rt5640");
index 9b8b561171b72c421c297ca92e5491b85e1aa50a..ff016621583a63c85c96689270405cbc5640ab77 100644 (file)
@@ -140,6 +140,7 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
 {
        int ret;
        struct snd_soc_dai *codec_dai = runtime->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
 
        /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
        ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
@@ -148,6 +149,19 @@ static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
                return ret;
        }
 
+       /* Select codec ASRC clock source to track I2S1 clock, because codec
+        * is in slave mode and 100fs I2S format (BCLK = 100 * LRCLK) cannot
+        * be supported by RT5672. Otherwise, ASRC will be disabled and cause
+        * noise.
+        */
+       rt5670_sel_asrc_clk_src(codec,
+                               RT5670_DA_STEREO_FILTER
+                               | RT5670_DA_MONO_L_FILTER
+                               | RT5670_DA_MONO_R_FILTER
+                               | RT5670_AD_STEREO_FILTER
+                               | RT5670_AD_MONO_L_FILTER
+                               | RT5670_AD_MONO_R_FILTER,
+                               RT5670_CLK_SEL_I2S1_ASRC);
        return 0;
 }
 
@@ -270,7 +284,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev)
 
 static struct platform_driver snd_cht_mc_driver = {
        .driver = {
-               .owner = THIS_MODULE,
                .name = "cht-bsw-rt5672",
                .pm = &snd_soc_pm_ops,
        },
index 3bb6288d8b4d8af42a7ff866fd67832c7cc43466..224c49c9f1354200672e2a3cf782dfbb16b6aa7f 100644 (file)
@@ -320,11 +320,6 @@ static struct snd_pcm_ops sst_byt_pcm_ops = {
        .mmap           = sst_byt_pcm_mmap,
 };
 
-static void sst_byt_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -403,7 +398,6 @@ static struct snd_soc_platform_driver byt_soc_platform = {
        .remove         = sst_byt_pcm_remove,
        .ops            = &sst_byt_pcm_ops,
        .pcm_new        = sst_byt_pcm_new,
-       .pcm_free       = sst_byt_pcm_free,
 };
 
 static const struct snd_soc_component_driver byt_dai_component = {
index 86e41084567002ebb999dca591b598a7224690fe..64e94212d2d2b129ebeddf9f1e4e55ac24775826 100644 (file)
@@ -410,8 +410,7 @@ void sst_dsp_free(struct sst_dsp *sst)
        if (sst->ops->free)
                sst->ops->free(sst);
 
-       if (sst->dma)
-               sst_dma_free(sst->dma);
+       sst_dma_free(sst->dma);
 }
 EXPORT_SYMBOL_GPL(sst_dsp_free);
 
index 4a5bde9c686be2bbe967fcdd899f7c10f52a74c1..5f71ef607a57e417715154b1697ee04ef0a13772 100644 (file)
@@ -497,6 +497,7 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw,
        sst_module->sst_fw = sst_fw;
        sst_module->scratch_size = template->scratch_size;
        sst_module->persistent_size = template->persistent_size;
+       sst_module->entry = template->entry;
 
        INIT_LIST_HEAD(&sst_module->block_list);
        INIT_LIST_HEAD(&sst_module->runtime_list);
@@ -706,6 +707,7 @@ static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba
        struct list_head *block_list)
 {
        struct sst_mem_block *block, *tmp;
+       struct sst_block_allocator ba_tmp = *ba;
        u32 end = ba->offset + ba->size, block_end;
        int err;
 
@@ -730,9 +732,9 @@ static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba
                if (ba->offset >= block->offset && ba->offset < block_end) {
 
                        /* align ba to block boundary */
-                       ba->size -= block_end - ba->offset;
-                       ba->offset = block_end;
-                       err = block_alloc_contiguous(dsp, ba, block_list);
+                       ba_tmp.size -= block_end - ba->offset;
+                       ba_tmp.offset = block_end;
+                       err = block_alloc_contiguous(dsp, &ba_tmp, block_list);
                        if (err < 0)
                                return -ENOMEM;
 
@@ -763,10 +765,14 @@ static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba
                /* does block span more than 1 section */
                if (ba->offset >= block->offset && ba->offset < block_end) {
 
+                       /* add block */
+                       list_move(&block->list, &dsp->used_block_list);
+                       list_add(&block->module_list, block_list);
                        /* align ba to block boundary */
-                       ba->offset = block->offset;
+                       ba_tmp.size -= block_end - ba->offset;
+                       ba_tmp.offset = block_end;
 
-                       err = block_alloc_contiguous(dsp, ba, block_list);
+                       err = block_alloc_contiguous(dsp, &ba_tmp, block_list);
                        if (err < 0)
                                return -ENOMEM;
 
@@ -785,6 +791,7 @@ int sst_module_alloc_blocks(struct sst_module *module)
        struct sst_block_allocator ba;
        int ret;
 
+       memset(&ba, 0, sizeof(ba));
        ba.size = module->size;
        ba.type = module->type;
        ba.offset = module->offset;
@@ -858,6 +865,7 @@ int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
        if (module->persistent_size == 0)
                return 0;
 
+       memset(&ba, 0, sizeof(ba));
        ba.size = module->persistent_size;
        ba.type = SST_MEM_DRAM;
 
index 57039b00efc222481f872e2c0426c85cdf84391d..c42ffae5fe9f6acab9ebe5723862c4e3a3b4bf8d 100644 (file)
@@ -306,7 +306,7 @@ static void hsw_reset(struct sst_dsp *sst)
 static int hsw_set_dsp_D0(struct sst_dsp *sst)
 {
        int tries = 10;
-       u32 reg;
+       u32 reg, fw_dump_bit;
 
        /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
@@ -368,7 +368,9 @@ finish:
        can't be accessed, please enable each block before accessing. */
        reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
        reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
-       writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+       /* for D0, always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
+       writel(reg & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 
 
        /* disable DMA finish function for SSP0 & SSP1 */
@@ -491,6 +493,7 @@ static const struct sst_sram_shift sram_shift[] = {
        {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */
        {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */
 };
+
 static u32 hsw_block_get_bit(struct sst_mem_block *block)
 {
        u32 bit = 0, shift = 0, index;
@@ -587,7 +590,9 @@ static int hsw_block_disable(struct sst_mem_block *block)
 
        val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
        bit = hsw_block_get_bit(block);
-       writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+       /* don't disable DSRAM[0], keep it always enable for FW dump*/
+       if (bit != (1 << SST_VDRTCL0_DSRAMPGE_SHIFT))
+               writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 
        /* wait 18 DSP clock ticks */
        udelay(10);
@@ -612,7 +617,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
        const struct sst_adsp_memregion *region;
        struct device *dev;
        int ret = -ENODEV, i, j, region_count;
-       u32 offset, size;
+       u32 offset, size, fw_dump_bit;
 
        dev = sst->dma_dev;
 
@@ -669,9 +674,11 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
                }
        }
 
+       /* always enable the block(DSRAM[0]) used for FW dump */
+       fw_dump_bit = 1 << SST_VDRTCL0_DSRAMPGE_SHIFT;
        /* set default power gating control, enable power gating control for all blocks. that is,
        can't be accessed, please enable each block before accessing. */
-       writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0);
+       writel(0xffffffff & ~fw_dump_bit, sst->addr.pci_cfg + SST_VDRTCTL0);
 
        return 0;
 }
index 3f8c48231364c6c7b9510da4eb9d73c6e291cace..a282179a3064b1645203815df62e7e3fb52b72ea 100644 (file)
@@ -94,6 +94,8 @@
 /* Mailbox */
 #define IPC_MAX_MAILBOX_BYTES  256
 
+#define INVALID_STREAM_HW_ID   0xffffffff
+
 /* Global Message - Types and Replies */
 enum ipc_glb_type {
        IPC_GLB_GET_FW_VERSION = 0,             /* Retrieves firmware version */
@@ -275,7 +277,6 @@ struct sst_hsw {
        /* FW config */
        struct sst_hsw_ipc_fw_ready fw_ready;
        struct sst_hsw_ipc_fw_version version;
-       struct sst_module *scratch;
        bool fw_done;
        struct sst_fw *sst_fw;
 
@@ -651,11 +652,11 @@ static void hsw_notification_work(struct work_struct *work)
        }
 
        /* tell DSP that notification has been handled */
-       sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD,
+       sst_dsp_shim_update_bits(hsw->dsp, SST_IPCD,
                SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE);
 
        /* unmask busy interrupt */
-       sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
+       sst_dsp_shim_update_bits(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0);
 }
 
 static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header)
@@ -1208,6 +1209,7 @@ struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id,
                return NULL;
 
        spin_lock_irqsave(&sst->spinlock, flags);
+       stream->reply.stream_hw_id = INVALID_STREAM_HW_ID;
        list_add(&stream->node, &hsw->stream_list);
        stream->notify_position = notify_position;
        stream->pdata = data;
@@ -1228,6 +1230,11 @@ int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        struct sst_dsp *sst = hsw->dsp;
        unsigned long flags;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to free, ignore it.\n");
+               return 0;
+       }
+
        /* dont free DSP streams that are not commited */
        if (!stream->commited)
                goto out;
@@ -1415,6 +1422,16 @@ int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
        u32 header;
        int ret;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to commit, ignore it.\n");
+               return 0;
+       }
+
+       if (stream->commited) {
+               dev_warn(hsw->dev, "warning: stream is already committed, ignore it.\n");
+               return 0;
+       }
+
        trace_ipc_request("stream alloc", stream->host_id);
 
        header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM);
@@ -1519,6 +1536,11 @@ int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
 {
        int ret;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to pause, ignore it.\n");
+               return 0;
+       }
+
        trace_ipc_request("stream pause", stream->reply.stream_hw_id);
 
        ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE,
@@ -1535,6 +1557,11 @@ int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
 {
        int ret;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to resume, ignore it.\n");
+               return 0;
+       }
+
        trace_ipc_request("stream resume", stream->reply.stream_hw_id);
 
        ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME,
@@ -1550,6 +1577,11 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream)
 {
        int ret, tries = 10;
 
+       if (!stream) {
+               dev_warn(hsw->dev, "warning: stream is NULL, no stream to reset, ignore it.\n");
+               return 0;
+       }
+
        /* dont reset streams that are not commited */
        if (!stream->commited)
                return 0;
@@ -2102,7 +2134,6 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
        dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
                        hsw->dx_context, hsw->dx_context_paddr);
        sst_dsp_free(hsw->dsp);
-       kfree(hsw->scratch);
        kthread_stop(hsw->tx_thread);
        kfree(hsw->msg);
 }
index 619525200705e3651be1780a229d3b7dc2d35537..ad7f4a51e138b7ada95059d9c8251e9413b97f70 100644 (file)
@@ -78,7 +78,6 @@ static const u32 volume_map[] = {
 #define HSW_PCM_DAI_ID_OFFLOAD0        1
 #define HSW_PCM_DAI_ID_OFFLOAD1        2
 #define HSW_PCM_DAI_ID_LOOPBACK        3
-#define HSW_PCM_DAI_ID_CAPTURE 4
 
 
 static const struct snd_pcm_hardware hsw_pcm_hardware = {
@@ -99,6 +98,7 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = {
 
 struct hsw_pcm_module_map {
        int dai_id;
+       int stream;
        enum sst_hsw_module_id mod_id;
 };
 
@@ -135,7 +135,17 @@ struct hsw_priv_data {
        struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
 
        /* DAI data */
-       struct hsw_pcm_data pcm[HSW_PCM_COUNT];
+       struct hsw_pcm_data pcm[HSW_PCM_COUNT][2];
+};
+
+
+/* static mappings between PCMs and modules - may be dynamic in future */
+static struct hsw_pcm_module_map mod_map[] = {
+       {HSW_PCM_DAI_ID_SYSTEM, 0, SST_HSW_MODULE_PCM_SYSTEM},
+       {HSW_PCM_DAI_ID_OFFLOAD0, 0, SST_HSW_MODULE_PCM},
+       {HSW_PCM_DAI_ID_OFFLOAD1, 0, SST_HSW_MODULE_PCM},
+       {HSW_PCM_DAI_ID_LOOPBACK, 1, SST_HSW_MODULE_PCM_REFERENCE},
+       {HSW_PCM_DAI_ID_SYSTEM, 1, SST_HSW_MODULE_PCM_CAPTURE},
 };
 
 static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data);
@@ -168,9 +178,14 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(platform);
-       struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
+       int dai, stream;
+
+       dai = mod_map[mc->reg].dai_id;
+       stream = mod_map[mc->reg].stream;
+       pcm_data = &pdata->pcm[dai][stream];
 
        mutex_lock(&pcm_data->mutex);
        pm_runtime_get_sync(pdata->dev);
@@ -212,9 +227,14 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(platform);
-       struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        u32 volume;
+       int dai, stream;
+
+       dai = mod_map[mc->reg].dai_id;
+       stream = mod_map[mc->reg].stream;
+       pcm_data = &pdata->pcm[dai][stream];
 
        mutex_lock(&pcm_data->mutex);
        pm_runtime_get_sync(pdata->dev);
@@ -309,7 +329,7 @@ static const struct snd_kcontrol_new hsw_volume_controls[] = {
                ARRAY_SIZE(volume_map) - 1, 0,
                hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
        /* Mic Capture volume */
-       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8,
+       SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
                ARRAY_SIZE(volume_map) - 1, 0,
                hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
 };
@@ -353,7 +373,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        struct sst_module *module_data;
        struct sst_dsp *dsp;
@@ -362,7 +382,10 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
        enum sst_hsw_stream_path_id path_id;
        u32 rate, bits, map, pages, module_id;
        u8 channels;
-       int ret;
+       int ret, dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        /* check if we are being called a subsequent time */
        if (pcm_data->allocated) {
@@ -552,8 +575,12 @@ static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -597,11 +624,16 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
        snd_pcm_uframes_t offset;
        uint64_t ppos;
-       u32 position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
+       u32 position;
+       int dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
+       position = sst_hsw_get_dsp_position(hsw, pcm_data->stream);
 
        offset = bytes_to_frames(runtime, position);
        ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
@@ -618,8 +650,10 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
                snd_soc_platform_get_drvdata(rtd->platform);
        struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
+       int dai;
 
-       pcm_data = &pdata->pcm[rtd->cpu_dai->id];
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        mutex_lock(&pcm_data->mutex);
        pm_runtime_get_sync(pdata->dev);
@@ -648,9 +682,12 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct hsw_priv_data *pdata =
                snd_soc_platform_get_drvdata(rtd->platform);
-       struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd);
+       struct hsw_pcm_data *pcm_data;
        struct sst_hsw *hsw = pdata->hsw;
-       int ret;
+       int ret, dai;
+
+       dai = mod_map[rtd->cpu_dai->id].dai_id;
+       pcm_data = &pdata->pcm[dai][substream->stream];
 
        mutex_lock(&pcm_data->mutex);
        ret = sst_hsw_stream_reset(hsw, pcm_data->stream);
@@ -685,15 +722,6 @@ static struct snd_pcm_ops hsw_pcm_ops = {
        .page           = snd_pcm_sgbuf_ops_page,
 };
 
-/* static mappings between PCMs and modules - may be dynamic in future */
-static struct hsw_pcm_module_map mod_map[] = {
-       {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM},
-       {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM},
-       {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM},
-       {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE},
-       {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE},
-};
-
 static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
 {
        struct sst_hsw *hsw = pdata->hsw;
@@ -701,7 +729,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[i];
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                /* create new runtime module, use same offset if recreated */
                pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
@@ -716,7 +744,7 @@ static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
 
 err:
        for (--i; i >= 0; i--) {
-               pcm_data = &pdata->pcm[i];
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
                sst_hsw_runtime_module_free(pcm_data->runtime);
        }
 
@@ -729,17 +757,12 @@ static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
-               pcm_data = &pdata->pcm[i];
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                sst_hsw_runtime_module_free(pcm_data->runtime);
        }
 }
 
-static void hsw_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -762,7 +785,10 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
                        return ret;
                }
        }
-       priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm;
+       if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
+               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_PLAYBACK].hsw_pcm = pcm;
+       if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
+               priv_data->pcm[rtd->cpu_dai->id][SNDRV_PCM_STREAM_CAPTURE].hsw_pcm = pcm;
 
        return ret;
 }
@@ -871,10 +897,9 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
        /* allocate DSP buffer page tables */
        for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
 
-               mutex_init(&priv_data->pcm[i].mutex);
-
                /* playback */
                if (hsw_dais[i].playback.channels_min) {
+                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_PLAYBACK].mutex);
                        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
                                PAGE_SIZE, &priv_data->dmab[i][0]);
                        if (ret < 0)
@@ -883,6 +908,7 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
 
                /* capture */
                if (hsw_dais[i].capture.channels_min) {
+                       mutex_init(&priv_data->pcm[i][SNDRV_PCM_STREAM_CAPTURE].mutex);
                        ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dma_dev,
                                PAGE_SIZE, &priv_data->dmab[i][1]);
                        if (ret < 0)
@@ -936,7 +962,6 @@ static struct snd_soc_platform_driver hsw_soc_platform = {
        .remove         = hsw_pcm_remove,
        .ops            = &hsw_pcm_ops,
        .pcm_new        = hsw_pcm_new,
-       .pcm_free       = hsw_pcm_free,
 };
 
 static const struct snd_soc_component_driver hsw_dai_component = {
@@ -1081,8 +1106,8 @@ static void hsw_pcm_complete(struct device *dev)
                return;
        }
 
-       for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
-               pcm_data = &pdata->pcm[i];
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                if (!pcm_data->substream)
                        continue;
@@ -1115,8 +1140,8 @@ static int hsw_pcm_prepare(struct device *dev)
        if (pdata->pm_state == HSW_PM_STATE_D3)
                return 0;
        /* suspend all active streams */
-       for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
-               pcm_data = &pdata->pcm[i];
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                if (!pcm_data->substream)
                        continue;
@@ -1134,8 +1159,8 @@ static int hsw_pcm_prepare(struct device *dev)
        sst_hsw_dsp_runtime_suspend(hsw);
 
        /* preserve persistent memory */
-       for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
-               pcm_data = &pdata->pcm[i];
+       for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+               pcm_data = &pdata->pcm[mod_map[i].dai_id][mod_map[i].stream];
 
                if (!pcm_data->substream)
                        continue;
index a1a8d9d91539cb6625042d0a5c530a2b0d84c3a9..7523cbef87807f2b3ac0d4209e939a5b1bda7567 100644 (file)
@@ -643,12 +643,6 @@ static struct snd_pcm_ops sst_platform_ops = {
        .pointer = sst_platform_pcm_pointer,
 };
 
-static void sst_pcm_free(struct snd_pcm *pcm)
-{
-       dev_dbg(pcm->dev, "sst_pcm_free called\n");
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_dai *dai = rtd->cpu_dai;
@@ -679,7 +673,6 @@ static struct snd_soc_platform_driver sst_soc_platform_drv  = {
        .ops            = &sst_platform_ops,
        .compr_ops      = &sst_platform_compr_ops,
        .pcm_new        = sst_pcm_new,
-       .pcm_free       = sst_pcm_free,
 };
 
 static const struct snd_soc_component_driver sst_component = {
index 3abc29e8a9287d133636d97fe74a96687c953bc0..43bc1c4b920703fab576408e7883da7c18d8784a 100644 (file)
@@ -245,7 +245,7 @@ static struct sst_machines *sst_acpi_find_machine(
        return NULL;
 }
 
-int sst_acpi_probe(struct platform_device *pdev)
+static int sst_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        int ret = 0;
@@ -332,7 +332,7 @@ do_sst_cleanup:
 * This function is called by OS when a device is unloaded
 * This frees the interrupt etc
 */
-int sst_acpi_remove(struct platform_device *pdev)
+static int sst_acpi_remove(struct platform_device *pdev)
 {
        struct intel_sst_drv *ctx;
 
@@ -343,7 +343,7 @@ int sst_acpi_remove(struct platform_device *pdev)
 }
 
 static struct sst_machines sst_acpi_bytcr[] = {
-       {"10EC5640", "T100", "bytt100_rt5640", NULL, "fw_sst_0f28.bin",
+       {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin",
                                                &byt_rvp_platform_data },
        {},
 };
@@ -352,6 +352,8 @@ static struct sst_machines sst_acpi_bytcr[] = {
 static struct sst_machines sst_acpi_chv[] = {
        {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin",
                                                &chv_platform_data },
+       {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "fw_sst_22a8.bin",
+                                               &chv_platform_data },
        {},
 };
 
@@ -366,7 +368,6 @@ MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
 static struct platform_driver sst_acpi_driver = {
        .driver = {
                .name                   = "intel_sst_acpi",
-               .owner                  = THIS_MODULE,
                .acpi_match_table       = ACPI_PTR(sst_acpi_ids),
                .pm                     = &intel_sst_pm,
        },
index b580f96e25e5e0c57a6699765adb8fe4ac9a8dba..7888cd707853db0a9819125d71cb063629514d9d 100644 (file)
@@ -324,8 +324,7 @@ void sst_firmware_load_cb(const struct firmware *fw, void *context)
 
        if (ctx->sst_state != SST_RESET ||
                        ctx->fw_in_mem != NULL) {
-               if (fw != NULL)
-                       release_firmware(fw);
+               release_firmware(fw);
                mutex_unlock(&ctx->sst_lock);
                return;
        }
index d9865082160cbe6b2081a5c2748c04e048343459..c866ade28ad0a6a0005a9ec97e09c05bfa63a783 100644 (file)
@@ -710,7 +710,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        struct resource *iores;
        struct mxs_saif *saif;
-       int ret = 0;
+       int irq, ret = 0;
        struct device_node *master;
 
        if (!np)
@@ -763,16 +763,16 @@ static int mxs_saif_probe(struct platform_device *pdev)
        if (IS_ERR(saif->base))
                return PTR_ERR(saif->base);
 
-       saif->irq = platform_get_irq(pdev, 0);
-       if (saif->irq < 0) {
-               ret = saif->irq;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               ret = irq;
                dev_err(&pdev->dev, "failed to get irq resource: %d\n",
                        ret);
                return ret;
        }
 
        saif->dev = &pdev->dev;
-       ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0,
+       ret = devm_request_irq(&pdev->dev, irq, mxs_saif_irq, 0,
                               dev_name(&pdev->dev), saif);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
index fbaf7badfdfb03b7d26eb84fd5c1be5850d06d1a..9a4c0b291b9e4c3675ed221f8c862266d290e01a 100644 (file)
@@ -116,7 +116,6 @@ struct mxs_saif {
        unsigned int mclk;
        unsigned int mclk_in_use;
        void __iomem *base;
-       int irq;
        unsigned int id;
        unsigned int master_id;
        unsigned int cur_rate;
index 6f1916b71815f3d5e509e2abbee69d1ccfdc8df4..6e6fce6a14ba6dc1c2ab14d054df8f5b07b2caea 100644 (file)
@@ -36,7 +36,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int rate = params_rate(params);
-       u32 dai_format, mclk;
+       u32 mclk;
        int ret;
 
        /* sgtl5000 does not support 512*rate when in 96000 fs */
@@ -65,26 +65,6 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
-       /* set codec to slave mode */
-       dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-                       SND_SOC_DAIFMT_CBS_CFS;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
-       if (ret) {
-               dev_err(codec_dai->dev, "Failed to set dai format to %08x\n",
-                       dai_format);
-               return ret;
-       }
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
-       if (ret) {
-               dev_err(cpu_dai->dev, "Failed to set dai format to %08x\n",
-                       dai_format);
-               return ret;
-       }
-
        return 0;
 }
 
@@ -92,17 +72,22 @@ static struct snd_soc_ops mxs_sgtl5000_hifi_ops = {
        .hw_params = mxs_sgtl5000_hw_params,
 };
 
+#define MXS_SGTL5000_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
+       SND_SOC_DAIFMT_CBS_CFS)
+
 static struct snd_soc_dai_link mxs_sgtl5000_dai[] = {
        {
                .name           = "HiFi Tx",
                .stream_name    = "HiFi Playback",
                .codec_dai_name = "sgtl5000",
+               .dai_fmt        = MXS_SGTL5000_DAI_FMT,
                .ops            = &mxs_sgtl5000_hifi_ops,
                .playback_only  = true,
        }, {
                .name           = "HiFi Rx",
                .stream_name    = "HiFi Capture",
                .codec_dai_name = "sgtl5000",
+               .dai_fmt        = MXS_SGTL5000_DAI_FMT,
                .ops            = &mxs_sgtl5000_hifi_ops,
                .capture_only   = true,
        },
index b779a3d9b5dd4ded757e565141e98f5cbc0f3394..b809fa909e4d6d6f91a78bdf5e9cda0e7f9c2fa8 100644 (file)
@@ -306,11 +306,6 @@ static struct snd_pcm_ops nuc900_dma_ops = {
        .mmap           = nuc900_dma_mmap,
 };
 
-static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
@@ -330,7 +325,6 @@ static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver nuc900_soc_platform = {
        .ops            = &nuc900_dma_ops,
        .pcm_new        = nuc900_dma_new,
-       .pcm_free       = nuc900_dma_free_dma_buffers,
 };
 
 static int nuc900_soc_platform_probe(struct platform_device *pdev)
index 4c6afb75eea61eeb5c89014f2fc27fb80e3bae96..706613077c155e93d7952aab02c49ccfccafaecc 100644 (file)
@@ -412,21 +412,7 @@ static struct tty_ldisc_ops cx81801_ops = {
  * over the modem port.
  */
 
-static int ams_delta_hw_params(struct snd_pcm_substream *substream,
-                        struct snd_pcm_hw_params *params)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-
-       /* Set cpu DAI configuration */
-       return snd_soc_dai_set_fmt(rtd->cpu_dai,
-                                  SND_SOC_DAIFMT_DSP_A |
-                                  SND_SOC_DAIFMT_NB_NF |
-                                  SND_SOC_DAIFMT_CBM_CFM);
-}
-
-static struct snd_soc_ops ams_delta_ops = {
-       .hw_params = ams_delta_hw_params,
-};
+static struct snd_soc_ops ams_delta_ops;
 
 
 /* Digital mute implemented using modem/CPU multiplexer.
@@ -546,6 +532,8 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
        .platform_name = "omap-mcbsp.1",
        .codec_name = "cx20442-codec",
        .ops = &ams_delta_ops,
+       .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
 };
 
 /* Audio card driver */
index 3f9ac7dbdc80141e15737105b8c29a0f5317caba..ccfb41c22e53b11cedbf5d8272a56a757ad283d1 100644 (file)
@@ -393,7 +393,6 @@ static int omap_hdmi_audio_remove(struct platform_device *pdev)
 static struct platform_driver hdmi_audio_driver = {
        .driver = {
                .name = DRV_NAME,
-               .owner = THIS_MODULE,
        },
        .probe = omap_hdmi_audio_probe,
        .remove = omap_hdmi_audio_remove,
index 8b79cafab1e2299af486c343565e68a162060c72..c7eb9dd67f608c47ffa93a97c1824e3dae3c867b 100644 (file)
@@ -434,7 +434,7 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai,
        case SND_SOC_DAIFMT_CBM_CFS:
                /* McBSP slave. FS clock as output */
                regs->srgr2     |= FSGM;
-               regs->pcr0      |= FSXM;
+               regs->pcr0      |= FSXM | FSRM;
                break;
        case SND_SOC_DAIFMT_CBM_CFM:
                /* McBSP slave */
index 5e551c762b7a9ccc04532b1bf4855e3dfeba42c2..fb1f6bb87cd430d816e250a2b5d7317c4744c6a7 100644 (file)
@@ -53,11 +53,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_card *card = rtd->card;
        unsigned int fmt;
-       int ret;
 
        switch (params_channels(params)) {
        case 2: /* Stereo I2S mode */
@@ -74,21 +70,7 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* Set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0) {
-               dev_err(card->dev, "can't set codec DAI configuration\n");
-               return ret;
-       }
-
-       /* Set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0) {
-               dev_err(card->dev, "can't set cpu DAI configuration\n");
-               return ret;
-       }
-
-       return 0;
+       return snd_soc_runtime_set_dai_fmt(rtd, fmt);
 }
 
 static struct snd_soc_ops omap_twl4030_ops = {
index 04896d6252a23909ff62a6cb36121e312718d9ce..7f299357c2d207c457cb9918a5b0a9cc618a3253 100644 (file)
@@ -250,14 +250,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"FM Transmitter", NULL, "LLOUT"},
        {"FM Transmitter", NULL, "RLOUT"},
 
-       {"DMic Rate 64", NULL, "Mic Bias"},
-       {"Mic Bias", NULL, "DMic"},
+       {"DMic Rate 64", NULL, "DMic"},
+       {"DMic", NULL, "Mic Bias"},
 
        {"b LINE2R", NULL, "MONO_LOUT"},
        {"Earphone", NULL, "b HPLOUT"},
 
-       {"LINE1L", NULL, "b Mic Bias"},
-       {"b Mic Bias", NULL, "HS Mic"}
+       {"LINE1L", NULL, "HS Mic"},
+       {"HS Mic", NULL, "b Mic Bias"},
 };
 
 static const char * const spk_function[] = {"Off", "On"};
index 2434b6d61675af01959c2f20db2af26db3ffb639..39cea80846c313f552a1a39f4ba9e015b9958a5a 100644 (file)
@@ -140,7 +140,7 @@ config SND_PXA910_SOC
          Marvell PXA910 reference platform.
 
 config SND_SOC_TTC_DKB
-       bool "SoC Audio support for TTC DKB"
+       tristate "SoC Audio support for TTC DKB"
        depends on SND_PXA910_SOC && MACH_TTC_DKB && I2C=y
        select PXA_SSP
        select SND_PXA_SOC_SSP
index b7cd0a71fd707bc2d27807a4813be4f0025d762b..3580d10c9f282312056d6ad3952b6adbcf632ffe 100644 (file)
@@ -259,20 +259,6 @@ static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
                corgi_set_spk),
 };
 
-/*
- * Logic for a wm8731 as connected on a Sharp SL-C7x0 Device
- */
-static int corgi_wm8731_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "LLINEIN");
-       snd_soc_dapm_nc_pin(dapm, "RLINEIN");
-
-       return 0;
-}
-
 /* corgi digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link corgi_dai = {
        .name = "WM8731",
@@ -281,7 +267,6 @@ static struct snd_soc_dai_link corgi_dai = {
        .codec_dai_name = "wm8731-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8731.0-001b",
-       .init = corgi_wm8731_init,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBS_CFS,
        .ops = &corgi_ops,
@@ -300,6 +285,7 @@ static struct snd_soc_card corgi = {
        .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
        .dapm_routes = corgi_audio_map,
        .num_dapm_routes = ARRAY_SIZE(corgi_audio_map),
+       .fully_routed = true,
 };
 
 static int corgi_probe(struct platform_device *pdev)
index 7c691aae8af29f4307a2a1c5be4ef4df47747ed0..d72e124a3676bf545be9d0afa49e6180973a00b2 100644 (file)
@@ -88,24 +88,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Mic Amp", NULL, "Mic (Internal)"},
 };
 
-static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "HPOUTL");
-       snd_soc_dapm_nc_pin(dapm, "HPOUTR");
-       snd_soc_dapm_nc_pin(dapm, "PHONE");
-       snd_soc_dapm_nc_pin(dapm, "LINEINL");
-       snd_soc_dapm_nc_pin(dapm, "LINEINR");
-       snd_soc_dapm_nc_pin(dapm, "CDINL");
-       snd_soc_dapm_nc_pin(dapm, "CDINR");
-       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
-       snd_soc_dapm_nc_pin(dapm, "MIC2");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link e740_dai[] = {
        {
                .name = "AC97",
@@ -114,7 +96,6 @@ static struct snd_soc_dai_link e740_dai[] = {
                .codec_dai_name = "wm9705-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
-               .init = e740_ac97_init,
        },
        {
                .name = "AC97 Aux",
@@ -136,6 +117,7 @@ static struct snd_soc_card e740 = {
        .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static struct gpio e740_audio_gpios[] = {
index 30544b65b5a812a6f62f9de1757900a2c929af05..48f2d7c2e68c2621f7cce3c6225a166ae8f0920f 100644 (file)
@@ -70,24 +70,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"MIC1", NULL, "Mic (Internal)"},
 };
 
-static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_nc_pin(dapm, "LOUT");
-       snd_soc_dapm_nc_pin(dapm, "ROUT");
-       snd_soc_dapm_nc_pin(dapm, "PHONE");
-       snd_soc_dapm_nc_pin(dapm, "LINEINL");
-       snd_soc_dapm_nc_pin(dapm, "LINEINR");
-       snd_soc_dapm_nc_pin(dapm, "CDINL");
-       snd_soc_dapm_nc_pin(dapm, "CDINR");
-       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
-       snd_soc_dapm_nc_pin(dapm, "MIC2");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link e750_dai[] = {
        {
                .name = "AC97",
@@ -96,7 +78,6 @@ static struct snd_soc_dai_link e750_dai[] = {
                .codec_dai_name = "wm9705-hifi",
                .platform_name = "pxa-pcm-audio",
                .codec_name = "wm9705-codec",
-               .init = e750_ac97_init,
                /* use ops to check startup state */
        },
        {
@@ -119,6 +100,7 @@ static struct snd_soc_card e750 = {
        .num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static struct gpio e750_audio_gpios[] = {
index ce26551052a325eb7f8f496b6679d422db71e398..73eb5ddf9753beb405b7d64fae88ede40d57bab2 100644 (file)
@@ -127,15 +127,8 @@ static const struct snd_soc_dapm_route hx4700_audio_map[] = {
 static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       /* NC codec pins */
-       /* FIXME: is anything connected here? */
-       snd_soc_dapm_nc_pin(dapm, "MOUT1");
-       snd_soc_dapm_nc_pin(dapm, "MICEXT");
-       snd_soc_dapm_nc_pin(dapm, "AUX");
-
        /* Jack detection API stuff */
        err = snd_soc_jack_new(codec, "Headphone Jack",
                                SND_JACK_HEADPHONE, &hs_jack);
@@ -184,6 +177,7 @@ static struct snd_soc_card snd_soc_card_hx4700 = {
        .num_dapm_widgets       = ARRAY_SIZE(hx4700_dapm_widgets),
        .dapm_routes            = hx4700_audio_map,
        .num_dapm_routes        = ARRAY_SIZE(hx4700_audio_map),
+       .fully_routed           = true,
 };
 
 static struct gpio hx4700_audio_gpios[] = {
index 259e048681c0fd4bdfc1d4e67c3b3b804fe73504..241d0be42d7a0c6779bb6459c5165728cbedb302 100644 (file)
@@ -391,25 +391,6 @@ static const struct snd_kcontrol_new uda1380_magician_controls[] = {
                        magician_get_input, magician_set_input),
 };
 
-/*
- * Logic for a uda1380 as connected on a HTC Magician
- */
-static int magician_uda1380_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* NC codec pins */
-       snd_soc_dapm_nc_pin(dapm, "VOUTLHP");
-       snd_soc_dapm_nc_pin(dapm, "VOUTRHP");
-
-       /* FIXME: is anything connected here? */
-       snd_soc_dapm_nc_pin(dapm, "VINL");
-       snd_soc_dapm_nc_pin(dapm, "VINR");
-
-       return 0;
-}
-
 /* magician digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link magician_dai[] = {
 {
@@ -419,7 +400,6 @@ static struct snd_soc_dai_link magician_dai[] = {
        .codec_dai_name = "uda1380-hifi-playback",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "uda1380-codec.0-0018",
-       .init = magician_uda1380_init,
        .ops = &magician_playback_ops,
 },
 {
@@ -446,6 +426,7 @@ static struct snd_soc_card snd_soc_card_magician = {
        .num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
        .dapm_routes = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static struct platform_device *magician_snd_device;
index 396dbd51a64f0183d787841b78a35adffd96de2f..a9615a574546988f6fc8e83fe5a018dc05528cba 100644 (file)
@@ -81,7 +81,7 @@ static int rear_amp_power(struct snd_soc_codec *codec, int power)
 static int rear_amp_event(struct snd_soc_dapm_widget *widget,
                          struct snd_kcontrol *kctl, int event)
 {
-       struct snd_soc_codec *codec = widget->codec;
+       struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec;
 
        return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event));
 }
index 1eebca2f0a97e9356c09273e1c94eed1ef7da14d..910336c5ebebd1486048552af7f598b6d7747b0d 100644 (file)
@@ -68,7 +68,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
        {"Ext. Speaker", NULL, "ROUT2"},
 
        /* mic connected to MIC1 */
-       {"Ext. Microphone", NULL, "MIC1"},
+       {"MIC1", NULL, "Ext. Microphone"},
 };
 
 static struct snd_soc_card palm27x_asoc;
@@ -76,18 +76,8 @@ static struct snd_soc_card palm27x_asoc;
 static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
        int err;
 
-       /* not connected pins */
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONOOUT");
-       snd_soc_dapm_nc_pin(dapm, "LINEINL");
-       snd_soc_dapm_nc_pin(dapm, "LINEINR");
-       snd_soc_dapm_nc_pin(dapm, "PCBEEP");
-       snd_soc_dapm_nc_pin(dapm, "PHONE");
-       snd_soc_dapm_nc_pin(dapm, "MIC2");
-
        /* Jack detection API stuff */
        err = snd_soc_jack_new(codec, "Headphone Jack",
                                SND_JACK_HEADPHONE, &hs_jack);
@@ -133,7 +123,8 @@ static struct snd_soc_card palm27x_asoc = {
        .dapm_widgets = palm27x_dapm_widgets,
        .num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets),
        .dapm_routes = audio_map,
-       .num_dapm_routes = ARRAY_SIZE(audio_map)
+       .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed = true,
 };
 
 static int palm27x_asoc_probe(struct platform_device *pdev)
index 083706595495956005fa6b91e731dc1796de44db..552b763005ed34d14ae46ebb82cb71bafa6c6c40 100644 (file)
@@ -88,7 +88,7 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       unsigned int fmt, clk = 0;
+       unsigned int clk = 0;
        int ret = 0;
 
        switch (params_rate(params)) {
@@ -112,15 +112,6 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       fmt = SND_SOC_DAIFMT_I2S |
-             SND_SOC_DAIFMT_NB_NF |
-             SND_SOC_DAIFMT_CBS_CFS;
-
-       /* setup the CODEC DAI */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
        if (ret < 0)
                return ret;
@@ -130,10 +121,6 @@ static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
        if (ret < 0)
                return ret;
@@ -169,9 +156,8 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
                                     struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       int fmt, ret = 0, clk = 0;
+       int ret = 0, clk = 0;
 
        switch (params_rate(params)) {
        case 44100:
@@ -194,22 +180,11 @@ static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
-
-       /* setup the CODEC DAI */
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* setup the CPU DAI */
        ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
        if (ret < 0)
                return ret;
@@ -233,6 +208,9 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .platform_name  = "pxa-pcm-audio",              \
        .codec_dai_name = "cs4270-hifi",                \
        .codec_name     = "cs4270.0-0048",      \
+       .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
+                         SND_SOC_DAIFMT_NB_NF |        \
+                         SND_SOC_DAIFMT_CBS_CFS,       \
        .ops            = &raumfeld_cs4270_ops,         \
 }
 
@@ -243,6 +221,9 @@ static struct snd_soc_ops raumfeld_ak4104_ops = {
        .cpu_dai_name   = "pxa-ssp-dai.1",              \
        .codec_dai_name = "ak4104-hifi",                \
        .platform_name  = "pxa-pcm-audio",              \
+       .dai_fmt        = SND_SOC_DAIFMT_I2S |          \
+                         SND_SOC_DAIFMT_NB_NF |        \
+                         SND_SOC_DAIFMT_CBS_CFS,       \
        .ops            = &raumfeld_ak4104_ops,         \
        .codec_name     = "spi0.0",                     \
 }
index d7d5fb20ea6f461f70fcfca85f928db617fba1bb..461123ad5ff2d4c56e21a97a14e27f8ce7d841c4 100644 (file)
@@ -256,26 +256,6 @@ static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
                spitz_set_spk),
 };
 
-/*
- * Logic for a wm8750 as connected on a Sharp SL-Cxx00 Device
- */
-static int spitz_wm8750_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* NC codec pins */
-       snd_soc_dapm_nc_pin(dapm, "RINPUT1");
-       snd_soc_dapm_nc_pin(dapm, "LINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "LINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONO1");
-
-       return 0;
-}
-
 /* spitz digital audio interface glue - connects codec <--> CPU */
 static struct snd_soc_dai_link spitz_dai = {
        .name = "wm8750",
@@ -284,7 +264,6 @@ static struct snd_soc_dai_link spitz_dai = {
        .codec_dai_name = "wm8750-hifi",
        .platform_name = "pxa-pcm-audio",
        .codec_name = "wm8750.0-001b",
-       .init = spitz_wm8750_init,
        .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
                   SND_SOC_DAIFMT_CBS_CFS,
        .ops = &spitz_ops,
@@ -303,6 +282,7 @@ static struct snd_soc_card snd_soc_spitz = {
        .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
        .dapm_routes = spitz_audio_map,
        .num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
+       .fully_routed = true,
 };
 
 static int spitz_probe(struct platform_device *pdev)
@@ -352,7 +332,6 @@ static int spitz_remove(struct platform_device *pdev)
 static struct platform_driver spitz_driver = {
        .driver         = {
                .name   = "spitz-audio",
-               .owner  = THIS_MODULE,
                .pm     = &snd_soc_pm_ops,
        },
        .probe          = spitz_probe,
index e3d7257ad09ca1fa115c674d0d75eb6abae653e7..5001dbb9b257764d9b88427de5bc86bebfba5a7b 100644 (file)
@@ -76,10 +76,6 @@ static const struct snd_soc_dapm_route ttc_audio_map[] = {
 static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       snd_soc_dapm_disable_pin(dapm, "Headset Mic 2");
-       snd_soc_dapm_disable_pin(dapm, "Headset Stereophone");
 
        /* Headset jack detection */
        snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
index 23bf991e95d53fa282f3b8e6dfbd2e9e2eeada21..8f301c72ee5e2b9ffe8eeb975db0f75afd1d1a16 100644 (file)
@@ -130,16 +130,6 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        return 0;
 }
 
@@ -172,6 +162,8 @@ static struct snd_soc_dai_link zylonite_dai[] = {
        .platform_name = "pxa-pcm-audio",
        .cpu_dai_name = "pxa-ssp-dai.2",
        .codec_dai_name = "wm9713-voice",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &zylonite_voice_ops,
 },
 };
index 26ec5117b35c1ace8b5b089200dbd367b06bbbf0..acb5be53bfb4ddbd6879437e58b7dcfe990bd201 100644 (file)
@@ -247,6 +247,10 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 
        regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val);
        regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val);
+       regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,
+                          I2S_DMACR_TDL(16));
+       regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,
+                          I2S_DMACR_RDL(16));
 
        return 0;
 }
@@ -335,6 +339,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
                            SNDRV_PCM_FMTBIT_S24_LE),
        },
        .ops = &rockchip_i2s_dai_ops,
+       .symmetric_rates = 1,
 };
 
 static const struct snd_soc_component_driver rockchip_i2s_component = {
@@ -454,11 +459,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
 
        i2s->playback_dma_data.addr = res->start + I2S_TXDR;
        i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       i2s->playback_dma_data.maxburst = 16;
+       i2s->playback_dma_data.maxburst = 4;
 
        i2s->capture_dma_data.addr = res->start + I2S_RXDR;
        i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-       i2s->capture_dma_data.maxburst = 16;
+       i2s->capture_dma_data.maxburst = 4;
 
        i2s->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, i2s);
index 89a5d8bc6ee7c9a356a0a9f58e1b6e938c354dce..93f456f518a97dc9a048350093acae715852e10a 100644 (file)
 #define I2S_DMACR_TDE_DISABLE  (0 << I2S_DMACR_TDE_SHIFT)
 #define I2S_DMACR_TDE_ENABLE   (1 << I2S_DMACR_TDE_SHIFT)
 #define I2S_DMACR_TDL_SHIFT    0
-#define I2S_DMACR_TDL(x)       ((x - 1) << I2S_DMACR_TDL_SHIFT)
+#define I2S_DMACR_TDL(x)       ((x) << I2S_DMACR_TDL_SHIFT)
 #define I2S_DMACR_TDL_MASK     (0x1f << I2S_DMACR_TDL_SHIFT)
 
 /*
index fc67f97f19f6338bdc01ddded64310181edcfc75..e817a2f43ea85cb26672be11691ff90de8073ad7 100644 (file)
@@ -54,7 +54,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750
 config SND_SOC_SAMSUNG_SMDK_WM8580
        tristate "SoC I2S Audio support for WM8580 on SMDK"
        depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
-       depends on REGMAP_I2C
+       depends on I2C
        select SND_SOC_WM8580
        select SND_SAMSUNG_I2S
        help
@@ -167,7 +167,7 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF
 config SND_SOC_SMDK_WM8580_PCM
        tristate "SoC PCM Audio support for WM8580 on SMDK"
        depends on SND_SOC_SAMSUNG && (MACH_SMDKV210 || MACH_SMDKC110)
-       depends on REGMAP_I2C
+       depends on I2C
        select SND_SOC_WM8580
        select SND_SAMSUNG_PCM
        help
index 1e2b61ca8db2f04860415aa71a0486c9478500a8..8bf2e2c4bafb97f64eafab4d81a87be20e68f8f7 100644 (file)
@@ -135,7 +135,6 @@ MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
 static struct platform_driver arndale_audio_driver = {
        .driver = {
                .name   = "arndale-audio",
-               .owner  = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
                .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
        },
index 3b527dcfc0aae5446bb8b1f06b3713ec3f2e0f85..fad56b9e73698ae605079ba331972f8a772163cb 100644 (file)
@@ -136,22 +136,9 @@ static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        unsigned int pll_out = 24000000;
        int ret = 0;
 
-       /* set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        /* set the codec FLL */
        ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
                        params_rate(params) * 256);
@@ -182,12 +169,6 @@ static int goni_voice_hw_params(struct snd_pcm_substream *substream,
        if (params_rate(params) != 8000)
                return -EINVAL;
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
-                       SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        /* set the codec FLL */
        ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
                        params_rate(params) * 256);
@@ -234,6 +215,8 @@ static struct snd_soc_dai_link goni_dai[] = {
        .codec_dai_name = "wm8994-aif1",
        .platform_name = "samsung-i2s.0",
        .codec_name = "wm8994-codec.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
        .init = goni_wm8994_init,
        .ops = &goni_hifi_ops,
 }, {
@@ -242,6 +225,8 @@ static struct snd_soc_dai_link goni_dai[] = {
        .cpu_dai_name = "goni-voice-dai",
        .codec_dai_name = "wm8994-aif2",
        .codec_name = "wm8994-codec.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_IB_IF |
+                  SND_SOC_DAIFMT_CBM_CFM,
        .ops = &goni_voice_ops,
 },
 };
index f2d7980d7ddc56ffea24da2cb6efcdddb4e081de..59b044255b781c68c733f30f397ff266059ac507 100644 (file)
@@ -76,7 +76,6 @@ static int h1940_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int div;
        int ret;
        unsigned int rate = params_rate(params);
@@ -95,18 +94,6 @@ static int h1940_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* select clock source */
        ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_PCLK, rate,
                        SND_SOC_CLOCK_OUT);
@@ -207,6 +194,8 @@ static struct snd_soc_dai_link h1940_uda1380_dai[] = {
                .init           = h1940_uda1380_init,
                .platform_name  = "s3c24xx-iis",
                .codec_name     = "uda1380-codec.0-001a",
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS,
                .ops            = &h1940_ops,
        },
 };
index b5a80c528d869e58cbbb58c44ba3cf6a531616ae..b92ab40d2be6ebf46b67bc355c6d75da1a065692 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#include <dt-bindings/sound/samsung-i2s.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
@@ -59,10 +61,8 @@ struct samsung_i2s_dai_data {
 struct i2s_dai {
        /* Platform device for this DAI */
        struct platform_device *pdev;
-       /* IOREMAP'd SFRs */
+       /* Memory mapped SFR region */
        void __iomem    *addr;
-       /* Physical base address of SFRs */
-       u32     base;
        /* Rate of RCLK source clock */
        unsigned long rclk_srcrate;
        /* Frame Clock */
@@ -83,8 +83,6 @@ struct i2s_dai {
 #define DAI_OPENED     (1 << 0) /* Dai is opened */
 #define DAI_MANAGER    (1 << 1) /* Dai is the manager */
        unsigned mode;
-       /* CDCLK pin direction: 0  - input, 1 - output */
-       unsigned int cdclk_out:1;
        /* Driver for this DAI */
        struct snd_soc_dai_driver i2s_dai_drv;
        /* DMA parameters */
@@ -95,8 +93,15 @@ struct i2s_dai {
        u32     suspend_i2smod;
        u32     suspend_i2scon;
        u32     suspend_i2spsr;
-       unsigned long gpios[7]; /* i2s gpio line numbers */
        const struct samsung_i2s_variant_regs *variant_regs;
+
+       /* Spinlock protecting access to the device's registers */
+       spinlock_t spinlock;
+       spinlock_t *lock;
+
+       /* Below fields are only valid if this is the primary FIFO */
+       struct clk *clk_table[3];
+       struct clk_onecell_data clk_data;
 };
 
 /* Lock for cross i/f checks */
@@ -133,10 +138,16 @@ static inline bool tx_active(struct i2s_dai *i2s)
        return active ? true : false;
 }
 
+/* Return pointer to the other DAI */
+static inline struct i2s_dai *get_other_dai(struct i2s_dai *i2s)
+{
+       return i2s->pri_dai ? : i2s->sec_dai;
+}
+
 /* If the other interface of the controller is transmitting data */
 static inline bool other_tx_active(struct i2s_dai *i2s)
 {
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
 
        return tx_active(other);
 }
@@ -163,7 +174,7 @@ static inline bool rx_active(struct i2s_dai *i2s)
 /* If the other interface of the controller is receiving data */
 static inline bool other_rx_active(struct i2s_dai *i2s)
 {
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
 
        return rx_active(other);
 }
@@ -464,18 +475,23 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
          int clk_id, unsigned int rfs, int dir)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-       u32 mod = readl(i2s->addr + I2SMOD);
+       struct i2s_dai *other = get_other_dai(i2s);
        const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
        unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
        unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
+       u32 mod, mask, val = 0;
+
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        switch (clk_id) {
        case SAMSUNG_I2S_OPCLK:
-               mod &= ~MOD_OPCLK_MASK;
-               mod |= dir;
+               mask = MOD_OPCLK_MASK;
+               val = dir;
                break;
        case SAMSUNG_I2S_CDCLK:
+               mask = 1 << i2s_regs->cdclkcon_off;
                /* Shouldn't matter in GATING(CLOCK_IN) mode */
                if (dir == SND_SOC_CLOCK_IN)
                        rfs = 0;
@@ -492,15 +508,15 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
                }
 
                if (dir == SND_SOC_CLOCK_IN)
-                       mod |= 1 << i2s_regs->cdclkcon_off;
-               else
-                       mod &= ~(1 << i2s_regs->cdclkcon_off);
+                       val = 1 << i2s_regs->cdclkcon_off;
 
                i2s->rfs = rfs;
                break;
 
        case SAMSUNG_I2S_RCLKSRC_0: /* clock corrsponding to IISMOD[10] := 0 */
        case SAMSUNG_I2S_RCLKSRC_1: /* clock corrsponding to IISMOD[10] := 1 */
+               mask = 1 << i2s_regs->rclksrc_off;
+
                if ((i2s->quirks & QUIRK_NO_MUXPSR)
                                || (clk_id == SAMSUNG_I2S_RCLKSRC_0))
                        clk_id = 0;
@@ -550,18 +566,19 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
                        return 0;
                }
 
-               if (clk_id == 0)
-                       mod &= ~(1 << i2s_regs->rclksrc_off);
-               else
-                       mod |= 1 << i2s_regs->rclksrc_off;
-
+               if (clk_id == 1)
+                       val = 1 << i2s_regs->rclksrc_off;
                break;
        default:
                dev_err(&i2s->pdev->dev, "We don't serve that!\n");
                return -EINVAL;
        }
 
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
+       mod = (mod & ~mask) | val;
        writel(mod, i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        return 0;
 }
@@ -570,9 +587,8 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
        unsigned int fmt)
 {
        struct i2s_dai *i2s = to_info(dai);
-       u32 mod = readl(i2s->addr + I2SMOD);
        int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
-       u32 tmp = 0;
+       u32 mod, tmp = 0;
 
        lrp_shift = i2s->variant_regs->lrp_off;
        sdf_shift = i2s->variant_regs->sdf_off;
@@ -632,12 +648,15 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
                return -EINVAL;
        }
 
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
        /*
         * Don't change the I2S mode if any controller is active on this
         * channel.
         */
        if (any_active(i2s) &&
                ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
+               spin_unlock(i2s->lock);
                dev_err(&i2s->pdev->dev,
                                "%s:%d Other DAI busy\n", __func__, __LINE__);
                return -EAGAIN;
@@ -646,6 +665,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
        mod &= ~(sdf_mask | lrp_rlow | mod_slave);
        mod |= tmp;
        writel(mod, i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        return 0;
 }
@@ -654,16 +674,16 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       u32 mod = readl(i2s->addr + I2SMOD);
+       u32 mod, mask = 0, val = 0;
 
        if (!is_secondary(i2s))
-               mod &= ~(MOD_DC2_EN | MOD_DC1_EN);
+               mask |= (MOD_DC2_EN | MOD_DC1_EN);
 
        switch (params_channels(params)) {
        case 6:
-               mod |= MOD_DC2_EN;
+               val |= MOD_DC2_EN;
        case 4:
-               mod |= MOD_DC1_EN;
+               val |= MOD_DC1_EN;
                break;
        case 2:
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -685,44 +705,49 @@ static int i2s_hw_params(struct snd_pcm_substream *substream,
        }
 
        if (is_secondary(i2s))
-               mod &= ~MOD_BLCS_MASK;
+               mask |= MOD_BLCS_MASK;
        else
-               mod &= ~MOD_BLCP_MASK;
+               mask |= MOD_BLCP_MASK;
 
        if (is_manager(i2s))
-               mod &= ~MOD_BLC_MASK;
+               mask |= MOD_BLC_MASK;
 
        switch (params_width(params)) {
        case 8:
                if (is_secondary(i2s))
-                       mod |= MOD_BLCS_8BIT;
+                       val |= MOD_BLCS_8BIT;
                else
-                       mod |= MOD_BLCP_8BIT;
+                       val |= MOD_BLCP_8BIT;
                if (is_manager(i2s))
-                       mod |= MOD_BLC_8BIT;
+                       val |= MOD_BLC_8BIT;
                break;
        case 16:
                if (is_secondary(i2s))
-                       mod |= MOD_BLCS_16BIT;
+                       val |= MOD_BLCS_16BIT;
                else
-                       mod |= MOD_BLCP_16BIT;
+                       val |= MOD_BLCP_16BIT;
                if (is_manager(i2s))
-                       mod |= MOD_BLC_16BIT;
+                       val |= MOD_BLC_16BIT;
                break;
        case 24:
                if (is_secondary(i2s))
-                       mod |= MOD_BLCS_24BIT;
+                       val |= MOD_BLCS_24BIT;
                else
-                       mod |= MOD_BLCP_24BIT;
+                       val |= MOD_BLCP_24BIT;
                if (is_manager(i2s))
-                       mod |= MOD_BLC_24BIT;
+                       val |= MOD_BLC_24BIT;
                break;
        default:
                dev_err(&i2s->pdev->dev, "Format(%d) not supported\n",
                                params_format(params));
                return -EINVAL;
        }
+
+       spin_lock(i2s->lock);
+       mod = readl(i2s->addr + I2SMOD);
+       mod = (mod & ~mask) | val;
        writel(mod, i2s->addr + I2SMOD);
+       spin_unlock(i2s->lock);
 
        samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
 
@@ -736,7 +761,7 @@ static int i2s_startup(struct snd_pcm_substream *substream,
          struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
        unsigned long flags;
 
        spin_lock_irqsave(&lock, flags);
@@ -753,9 +778,6 @@ static int i2s_startup(struct snd_pcm_substream *substream,
 
        spin_unlock_irqrestore(&lock, flags);
 
-       if (!is_opened(other) && i2s->cdclk_out)
-               i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
-                               0, SND_SOC_CLOCK_OUT);
        return 0;
 }
 
@@ -763,38 +785,27 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
        struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
        unsigned long flags;
-       const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
 
        spin_lock_irqsave(&lock, flags);
 
        i2s->mode &= ~DAI_OPENED;
        i2s->mode &= ~DAI_MANAGER;
 
-       if (is_opened(other)) {
+       if (is_opened(other))
                other->mode |= DAI_MANAGER;
-       } else {
-               u32 mod = readl(i2s->addr + I2SMOD);
-               i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
-               if (other)
-                       other->cdclk_out = i2s->cdclk_out;
-       }
+
        /* Reset any constraint on RFS and BFS */
        i2s->rfs = 0;
        i2s->bfs = 0;
 
        spin_unlock_irqrestore(&lock, flags);
-
-       /* Gate CDCLK by default */
-       if (!is_opened(other))
-               i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK,
-                               0, SND_SOC_CLOCK_IN);
 }
 
 static int config_setup(struct i2s_dai *i2s)
 {
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
        unsigned rfs, bfs, blc;
        u32 psr;
 
@@ -864,10 +875,10 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               local_irq_save(flags);
+               spin_lock_irqsave(i2s->lock, flags);
 
                if (config_setup(i2s)) {
-                       local_irq_restore(flags);
+                       spin_unlock_irqrestore(i2s->lock, flags);
                        return -EINVAL;
                }
 
@@ -876,12 +887,12 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
                else
                        i2s_txctrl(i2s, 1);
 
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(i2s->lock, flags);
                break;
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               local_irq_save(flags);
+               spin_lock_irqsave(i2s->lock, flags);
 
                if (capture) {
                        i2s_rxctrl(i2s, 0);
@@ -891,7 +902,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream,
                        i2s_fifo(i2s, FIC_TXFLUSH);
                }
 
-               local_irq_restore(flags);
+               spin_unlock_irqrestore(i2s->lock, flags);
                break;
        }
 
@@ -902,7 +913,7 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+       struct i2s_dai *other = get_other_dai(i2s);
 
        switch (div_id) {
        case SAMSUNG_I2S_DIV_BCLK:
@@ -971,58 +982,36 @@ static int i2s_resume(struct snd_soc_dai *dai)
 static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = to_info(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-       int ret;
+       struct i2s_dai *other = get_other_dai(i2s);
+       unsigned long flags;
 
-       if (other && other->clk) { /* If this is probe on secondary */
+       if (is_secondary(i2s)) { /* If this is probe on the secondary DAI */
                samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
                                           NULL);
-               goto probe_exit;
-       }
-
-       i2s->addr = ioremap(i2s->base, 0x100);
-       if (i2s->addr == NULL) {
-               dev_err(&i2s->pdev->dev, "cannot ioremap registers\n");
-               return -ENXIO;
-       }
-
-       i2s->clk = clk_get(&i2s->pdev->dev, "iis");
-       if (IS_ERR(i2s->clk)) {
-               dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
-               iounmap(i2s->addr);
-               return PTR_ERR(i2s->clk);
-       }
-
-       ret = clk_prepare_enable(i2s->clk);
-       if (ret != 0) {
-               dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret);
-               return ret;
-       }
-
-       samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
-
-       if (other) {
-               other->addr = i2s->addr;
-               other->clk = i2s->clk;
-       }
+       } else {
+               samsung_asoc_init_dma_data(dai, &i2s->dma_playback,
+                                          &i2s->dma_capture);
 
-       if (i2s->quirks & QUIRK_NEED_RSTCLR)
-               writel(CON_RSTCLR, i2s->addr + I2SCON);
+               if (i2s->quirks & QUIRK_NEED_RSTCLR)
+                       writel(CON_RSTCLR, i2s->addr + I2SCON);
 
-       if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
-               idma_reg_addr_init(i2s->addr,
+               if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
+                       idma_reg_addr_init(i2s->addr,
                                        i2s->sec_dai->idma_playback.dma_addr);
+       }
 
-probe_exit:
        /* Reset any constraint on RFS and BFS */
        i2s->rfs = 0;
        i2s->bfs = 0;
        i2s->rclk_srcrate = 0;
+
+       spin_lock_irqsave(i2s->lock, flags);
        i2s_txctrl(i2s, 0);
        i2s_rxctrl(i2s, 0);
        i2s_fifo(i2s, FIC_TXFLUSH);
        i2s_fifo(other, FIC_TXFLUSH);
        i2s_fifo(i2s, FIC_RXFLUSH);
+       spin_unlock_irqrestore(i2s->lock, flags);
 
        /* Gate CDCLK by default */
        if (!is_opened(other))
@@ -1035,21 +1024,15 @@ probe_exit:
 static int samsung_i2s_dai_remove(struct snd_soc_dai *dai)
 {
        struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai);
-       struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
-
-       if (!other || !other->clk) {
 
-               if (i2s->quirks & QUIRK_NEED_RSTCLR)
+       if (!is_secondary(i2s)) {
+               if (i2s->quirks & QUIRK_NEED_RSTCLR) {
+                       spin_lock(i2s->lock);
                        writel(0, i2s->addr + I2SCON);
-
-               clk_disable_unprepare(i2s->clk);
-               clk_put(i2s->clk);
-
-               iounmap(i2s->addr);
+                       spin_unlock(i2s->lock);
+               }
        }
 
-       i2s->clk = NULL;
-
        return 0;
 }
 
@@ -1124,15 +1107,14 @@ static const struct of_device_id exynos_i2s_match[];
 static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data(
                                                struct platform_device *pdev)
 {
-#ifdef CONFIG_OF
-       if (pdev->dev.of_node) {
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(exynos_i2s_match, pdev->dev.of_node);
-               return match->data;
-       } else
-#endif
+               return match ? match->data : NULL;
+       } else {
                return (struct samsung_i2s_dai_data *)
                                platform_get_device_id(pdev)->driver_data;
+       }
 }
 
 #ifdef CONFIG_PM
@@ -1155,6 +1137,87 @@ static int i2s_runtime_resume(struct device *dev)
 }
 #endif /* CONFIG_PM */
 
+static void i2s_unregister_clocks(struct i2s_dai *i2s)
+{
+       int i;
+
+       for (i = 0; i < i2s->clk_data.clk_num; i++) {
+               if (!IS_ERR(i2s->clk_table[i]))
+                       clk_unregister(i2s->clk_table[i]);
+       }
+}
+
+static void i2s_unregister_clock_provider(struct platform_device *pdev)
+{
+       struct i2s_dai *i2s = dev_get_drvdata(&pdev->dev);
+
+       of_clk_del_provider(pdev->dev.of_node);
+       i2s_unregister_clocks(i2s);
+}
+
+static int i2s_register_clock_provider(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct i2s_dai *i2s = dev_get_drvdata(dev);
+       const char *clk_name[2] = { "i2s_opclk0", "i2s_opclk1" };
+       const char *p_names[2] = { NULL };
+       const struct samsung_i2s_variant_regs *reg_info = i2s->variant_regs;
+       struct clk *rclksrc;
+       int ret, i;
+
+       /* Register the clock provider only if it's expected in the DTB */
+       if (!of_find_property(dev->of_node, "#clock-cells", NULL))
+               return 0;
+
+       /* Get the RCLKSRC mux clock parent clock names */
+       for (i = 0; i < ARRAY_SIZE(p_names); i++) {
+               rclksrc = clk_get(dev, clk_name[i]);
+               if (IS_ERR(rclksrc))
+                       continue;
+               p_names[i] = __clk_get_name(rclksrc);
+               clk_put(rclksrc);
+       }
+
+       if (!(i2s->quirks & QUIRK_NO_MUXPSR)) {
+               /* Activate the prescaler */
+               u32 val = readl(i2s->addr + I2SPSR);
+               writel(val | PSR_PSREN, i2s->addr + I2SPSR);
+
+               i2s->clk_table[CLK_I2S_RCLK_SRC] = clk_register_mux(NULL,
+                               "i2s_rclksrc", p_names, ARRAY_SIZE(p_names),
+                               CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+                               i2s->addr + I2SMOD, reg_info->rclksrc_off,
+                               1, 0, i2s->lock);
+
+               i2s->clk_table[CLK_I2S_RCLK_PSR] = clk_register_divider(NULL,
+                               "i2s_presc", "i2s_rclksrc",
+                               CLK_SET_RATE_PARENT,
+                               i2s->addr + I2SPSR, 8, 6, 0, i2s->lock);
+
+               p_names[0] = "i2s_presc";
+               i2s->clk_data.clk_num = 2;
+       }
+       of_property_read_string_index(dev->of_node,
+                               "clock-output-names", 0, &clk_name[0]);
+
+       i2s->clk_table[CLK_I2S_CDCLK] = clk_register_gate(NULL, clk_name[0],
+                               p_names[0], CLK_SET_RATE_PARENT,
+                               i2s->addr + I2SMOD, reg_info->cdclkcon_off,
+                               CLK_GATE_SET_TO_DISABLE, i2s->lock);
+
+       i2s->clk_data.clk_num += 1;
+       i2s->clk_data.clks = i2s->clk_table;
+
+       ret = of_clk_add_provider(dev->of_node, of_clk_src_onecell_get,
+                                 &i2s->clk_data);
+       if (ret < 0) {
+               dev_err(dev, "failed to add clock provider: %d\n", ret);
+               i2s_unregister_clocks(i2s);
+       }
+
+       return ret;
+}
+
 static int samsung_i2s_probe(struct platform_device *pdev)
 {
        struct i2s_dai *pri_dai, *sec_dai = NULL;
@@ -1164,7 +1227,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        u32 regs_base, quirks = 0, idma_addr = 0;
        struct device_node *np = pdev->dev.of_node;
        const struct samsung_i2s_dai_data *i2s_dai_data;
-       int ret = 0;
+       int ret;
 
        /* Call during Seconday interface registration */
        i2s_dai_data = samsung_i2s_get_driver_data(pdev);
@@ -1175,11 +1238,13 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "Unable to get drvdata\n");
                        return -EFAULT;
                }
-               devm_snd_soc_register_component(&sec_dai->pdev->dev,
+               ret = devm_snd_soc_register_component(&sec_dai->pdev->dev,
                                                &samsung_i2s_component,
                                                &sec_dai->i2s_dai_drv, 1);
-               samsung_asoc_dma_platform_register(&pdev->dev);
-               return 0;
+               if (ret != 0)
+                       return ret;
+
+               return samsung_asoc_dma_platform_register(&pdev->dev);
        }
 
        pri_dai = i2s_alloc_dai(pdev, false);
@@ -1188,6 +1253,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       spin_lock_init(&pri_dai->spinlock);
+       pri_dai->lock = &pri_dai->spinlock;
+
        if (!np) {
                res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
                if (!res) {
@@ -1229,25 +1297,29 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Unable to get I2S SFR address\n");
-               return -ENXIO;
-       }
+       pri_dai->addr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pri_dai->addr))
+               return PTR_ERR(pri_dai->addr);
 
-       if (!request_mem_region(res->start, resource_size(res),
-                                                       "samsung-i2s")) {
-               dev_err(&pdev->dev, "Unable to request SFR region\n");
-               return -EBUSY;
-       }
        regs_base = res->start;
 
+       pri_dai->clk = devm_clk_get(&pdev->dev, "iis");
+       if (IS_ERR(pri_dai->clk)) {
+               dev_err(&pdev->dev, "Failed to get iis clock\n");
+               return PTR_ERR(pri_dai->clk);
+       }
+
+       ret = clk_prepare_enable(pri_dai->clk);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
+               return ret;
+       }
        pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
        pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
        pri_dai->dma_playback.ch_name = "tx";
        pri_dai->dma_capture.ch_name = "rx";
        pri_dai->dma_playback.dma_size = 4;
        pri_dai->dma_capture.dma_size = 4;
-       pri_dai->base = regs_base;
        pri_dai->quirks = quirks;
        pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
 
@@ -1258,10 +1330,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                sec_dai = i2s_alloc_dai(pdev, true);
                if (!sec_dai) {
                        dev_err(&pdev->dev, "Unable to alloc I2S_sec\n");
-                       ret = -ENOMEM;
-                       goto err;
+                       return -ENOMEM;
                }
 
+               sec_dai->lock = &pri_dai->spinlock;
                sec_dai->variant_regs = pri_dai->variant_regs;
                sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
                sec_dai->dma_playback.ch_name = "tx-sec";
@@ -1273,7 +1345,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                }
 
                sec_dai->dma_playback.dma_size = 4;
-               sec_dai->base = regs_base;
+               sec_dai->addr = pri_dai->addr;
+               sec_dai->clk = pri_dai->clk;
                sec_dai->quirks = quirks;
                sec_dai->idma_playback.dma_addr = idma_addr;
                sec_dai->pri_dai = pri_dai;
@@ -1282,8 +1355,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        if (i2s_pdata && i2s_pdata->cfg_gpio && i2s_pdata->cfg_gpio(pdev)) {
                dev_err(&pdev->dev, "Unable to configure gpio\n");
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
        devm_snd_soc_register_component(&pri_dai->pdev->dev,
@@ -1292,32 +1364,30 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        pm_runtime_enable(&pdev->dev);
 
-       samsung_asoc_dma_platform_register(&pdev->dev);
-
-       return 0;
-err:
-       if (res)
-               release_mem_region(regs_base, resource_size(res));
+       ret = samsung_asoc_dma_platform_register(&pdev->dev);
+       if (ret != 0)
+               return ret;
 
-       return ret;
+       return i2s_register_clock_provider(pdev);
 }
 
 static int samsung_i2s_remove(struct platform_device *pdev)
 {
        struct i2s_dai *i2s, *other;
-       struct resource *res;
 
        i2s = dev_get_drvdata(&pdev->dev);
-       other = i2s->pri_dai ? : i2s->sec_dai;
+       other = get_other_dai(i2s);
 
        if (other) {
                other->pri_dai = NULL;
                other->sec_dai = NULL;
        } else {
                pm_runtime_disable(&pdev->dev);
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (res)
-                       release_mem_region(res->start, resource_size(res));
+       }
+
+       if (!is_secondary(i2s)) {
+               i2s_unregister_clock_provider(pdev);
+               clk_disable_unprepare(i2s->clk);
        }
 
        i2s->pri_dai = NULL;
index b5f6abd9d2216d7f9664ca337468ff7792c93b0d..7fcb51faa2a0e98803cbc8ac67cd370b7f2fd02b 100644 (file)
@@ -61,20 +61,6 @@ static int jive_hw_params(struct snd_pcm_substream *substream,
        s3c_i2sv2_iis_calc_rate(&div, NULL, params_rate(params),
                                s3c_i2sv2_get_clock(cpu_dai));
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
                                     SND_SOC_CLOCK_IN);
@@ -97,22 +83,6 @@ static struct snd_soc_ops jive_ops = {
        .hw_params      = jive_hw_params,
 };
 
-static int jive_wm8750_init(struct snd_soc_pcm_runtime *rtd)
-{
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
-       /* These endpoints are not being used. */
-       snd_soc_dapm_nc_pin(dapm, "LINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT2");
-       snd_soc_dapm_nc_pin(dapm, "LINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "RINPUT3");
-       snd_soc_dapm_nc_pin(dapm, "OUT3");
-       snd_soc_dapm_nc_pin(dapm, "MONO");
-
-       return 0;
-}
-
 static struct snd_soc_dai_link jive_dai = {
        .name           = "wm8750",
        .stream_name    = "WM8750",
@@ -120,7 +90,8 @@ static struct snd_soc_dai_link jive_dai = {
        .codec_dai_name = "wm8750-hifi",
        .platform_name  = "s3c2412-i2s",
        .codec_name     = "wm8750.0-001a",
-       .init           = jive_wm8750_init,
+       .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                         SND_SOC_DAIFMT_CBS_CFS,
        .ops            = &jive_ops,
 };
 
@@ -135,6 +106,7 @@ static struct snd_soc_card snd_soc_machine_jive = {
        .num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
        .dapm_routes    = audio_map,
        .num_dapm_routes = ARRAY_SIZE(audio_map),
+       .fully_routed   = true,
 };
 
 static struct platform_device *jive_snd_device;
index 9b4a09f14b6c4b2ed859dc45eb890049efac8de7..65602b935377df161562489f4b93ca4125a8a9cc 100644 (file)
@@ -70,20 +70,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai,
-               SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-               SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out,
                SND_SOC_CLOCK_IN);
@@ -151,13 +137,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream,
 
        pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */
 
-       /* todo: gg check mode (DSP_B) against CSR datasheet */
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* set the codec system clock for DAC and ADC */
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, 12288000,
                SND_SOC_CLOCK_IN);
@@ -300,6 +279,8 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .cpu_dai_name = "s3c24xx-iis",
        .codec_dai_name = "wm8753-hifi",
        .codec_name = "wm8753.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBM_CFM,
        .init = neo1973_wm8753_init,
        .ops = &neo1973_hifi_ops,
 },
@@ -309,6 +290,8 @@ static struct snd_soc_dai_link neo1973_dai[] = {
        .cpu_dai_name = "bt-sco-pcm",
        .codec_dai_name = "wm8753-voice",
        .codec_name = "wm8753.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &neo1973_voice_ops,
 },
 };
index fa4f1d2f69bfa0905deea745b7260488694b5a55..596f1180a3698627844a0e8746e8d64bf0441f47 100644 (file)
@@ -21,6 +21,8 @@ struct odroidx2_drv_data {
 /* The I2S CDCLK output clock frequency for the MAX98090 codec */
 #define MAX98090_MCLK 19200000
 
+static struct snd_soc_dai_link odroidx2_dai[];
+
 static int odroidx2_late_probe(struct snd_soc_card *card)
 {
        struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
@@ -29,7 +31,9 @@ static int odroidx2_late_probe(struct snd_soc_card *card)
 
        ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK,
                                                SND_SOC_CLOCK_IN);
-       if (ret < 0)
+
+       if (ret < 0 || of_find_property(odroidx2_dai[0].codec_of_node,
+                                       "clocks", NULL))
                return ret;
 
        /* Set the cpu DAI configuration in order to use CDCLK */
index 37688ebbb2b4b6be954150d1e17b721ed9ddf6f3..873f2cb4bebe3e449d6d32821da672e0916626f0 100644 (file)
@@ -89,6 +89,8 @@ static struct snd_soc_dai_link rx1950_uda1380_dai[] = {
                .init           = rx1950_uda1380_init,
                .platform_name  = "s3c24xx-iis",
                .codec_name     = "uda1380-codec.0-001a",
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS,
                .ops            = &rx1950_ops,
        },
 };
@@ -154,7 +156,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
-       struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int div;
        int ret;
        unsigned int rate = params_rate(params);
@@ -181,18 +182,6 @@ static int rx1950_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-               SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* select clock source */
        ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source, rate,
                        SND_SOC_CLOCK_OUT);
index 2c015f62ead603564683c1920ec3613ad5df7768..dcc008d1e1ab1bd896665b2c1cec40c73e497199 100644 (file)
@@ -169,24 +169,6 @@ static int simtec_hw_params(struct snd_pcm_substream *substream,
        struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        int ret;
 
-       /* Set the CODEC as the bus clock master, I2S */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               pr_err("%s: failed set cpu dai format\n", __func__);
-               return ret;
-       }
-
-       /* Set the CODEC as the bus clock master */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                 SND_SOC_DAIFMT_NB_NF |
-                                 SND_SOC_DAIFMT_CBM_CFM);
-       if (ret) {
-               pr_err("%s: failed set codec dai format\n", __func__);
-               return ret;
-       }
-
        ret = snd_soc_dai_set_sysclk(codec_dai, 0,
                                     CODEC_CLOCK, SND_SOC_CLOCK_IN);
        if (ret) {
@@ -320,6 +302,8 @@ int simtec_audio_core_probe(struct platform_device *pdev,
        int ret;
 
        card->dai_link->ops = &simtec_snd_ops;
+       card->dai_link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBM_CFM;
 
        pdata = pdev->dev.platform_data;
        if (!pdata) {
index 9c6f7db56f600090be8a804b6380436707aeaa55..50849e137fc0edf2455a7d643b17c936f2e63794 100644 (file)
@@ -173,16 +173,6 @@ static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                       SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
                        SND_SOC_CLOCK_IN);
        if (ret < 0)
@@ -223,6 +213,8 @@ static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
        .codec_name = "uda134x-codec",
        .codec_dai_name = "uda134x-hifi",
        .cpu_dai_name = "s3c24xx-iis",
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &s3c24xx_uda134x_ops,
        .platform_name  = "s3c24xx-iis",
 };
index 9b0ffacab790c7f216cf932dcf2d1b8733b64715..8291d2a5f1525957b6c4e021c8657d4590ce649e 100644 (file)
@@ -56,20 +56,6 @@ static int smartq_hifi_hw_params(struct snd_pcm_substream *substream,
                break;
        }
 
-       /* set codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
-                                            SND_SOC_DAIFMT_NB_NF |
-                                            SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* set cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
-                                          SND_SOC_DAIFMT_NB_NF |
-                                          SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        /* Use PCLK for I2S signal generation */
        ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
                                        0, SND_SOC_CLOCK_IN);
@@ -199,6 +185,8 @@ static struct snd_soc_dai_link smartq_dai[] = {
                .platform_name  = "samsung-i2s.0",
                .codec_name     = "wm8750.0-0x1a",
                .init           = smartq_wm8987_init,
+               .dai_fmt        = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                                 SND_SOC_DAIFMT_CBS_CFS,
                .ops            = &smartq_hifi_ops,
        },
 };
index b1a519f83b29ea439c262ef2263fab208514bebc..548bfd9937889dbe43df8a28ec3d6de9a3d568b1 100644 (file)
@@ -32,7 +32,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_soc_dai *codec_dai = rtd->codec_dai;
        unsigned int pll_out;
        int bfs, rfs, ret;
@@ -77,20 +76,6 @@ static int smdk_hw_params(struct snd_pcm_substream *substream,
        }
        pll_out = params_rate(params) * rfs;
 
-       /* Set the Codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
-       /* Set the AP DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
-                                        | SND_SOC_DAIFMT_NB_NF
-                                        | SND_SOC_DAIFMT_CBM_CFM);
-       if (ret < 0)
-               return ret;
-
        /* Set WM8580 to drive MCLK from its PLLA */
        ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK,
                                        WM8580_CLKSRC_PLLA);
@@ -151,13 +136,10 @@ static const struct snd_soc_dapm_route smdk_wm8580_audio_map[] = {
 
 static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd)
 {
-       struct snd_soc_codec *codec = rtd->codec;
-       struct snd_soc_dapm_context *dapm = &codec->dapm;
-
        /* Enabling the microphone requires the fitting of a 0R
         * resistor to connect the line from the microphone jack.
         */
-       snd_soc_dapm_disable_pin(dapm, "MicIn");
+       snd_soc_dapm_disable_pin(&rtd->card->dapm, "MicIn");
 
        return 0;
 }
@@ -168,6 +150,9 @@ enum {
        SEC_PLAYBACK,
 };
 
+#define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \
+       SND_SOC_DAIFMT_CBM_CFM)
+
 static struct snd_soc_dai_link smdk_dai[] = {
        [PRI_PLAYBACK] = { /* Primary Playback i/f */
                .name = "WM8580 PAIF RX",
@@ -176,6 +161,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-playback",
                .platform_name = "samsung-i2s.0",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_ops,
        },
        [PRI_CAPTURE] = { /* Primary Capture i/f */
@@ -185,6 +171,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-capture",
                .platform_name = "samsung-i2s.0",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .init = smdk_wm8580_init_paiftx,
                .ops = &smdk_ops,
        },
@@ -195,6 +182,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-playback",
                .platform_name = "samsung-i2s-sec",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_ops,
        },
 };
index 05c609c62de9fd830298c4956e222abf8ff87e80..6deec5234c92960410a222c718e270c5dd2fe072 100644 (file)
@@ -62,20 +62,6 @@ static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream,
 
        rfs = mclk_freq / params_rate(params) / 2;
 
-       /* Set the codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* Set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        if (mclk_freq == xtal_freq) {
                ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK,
                                                mclk_freq, SND_SOC_CLOCK_IN);
@@ -121,6 +107,9 @@ static struct snd_soc_ops smdk_wm8580_pcm_ops = {
        .hw_params = smdk_wm8580_pcm_hw_params,
 };
 
+#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \
+       SND_SOC_DAIFMT_CBS_CFS)
+
 static struct snd_soc_dai_link smdk_dai[] = {
        {
                .name = "WM8580 PAIF PCM RX",
@@ -129,6 +118,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-playback",
                .platform_name = "samsung-audio",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_wm8580_pcm_ops,
        }, {
                .name = "WM8580 PAIF PCM TX",
@@ -137,6 +127,7 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8580-hifi-capture",
                .platform_name = "samsung-pcm.0",
                .codec_name = "wm8580.0-001b",
+               .dai_fmt = SMDK_DAI_FMT,
                .ops = &smdk_wm8580_pcm_ops,
        },
 };
index c470e8eed6e19b1468b15720b654f225ccec434e..b1c89ec2d999ce3f410282dfdf1ecfb30b7cfe4e 100644 (file)
@@ -68,20 +68,6 @@ static int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream,
 
        mclk_freq = params_rate(params) * rfs;
 
-       /* Set the codec DAI configuration */
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       /* Set the cpu DAI configuration */
-       ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B
-                               | SND_SOC_DAIFMT_IB_NF
-                               | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
                                        mclk_freq, SND_SOC_CLOCK_IN);
        if (ret < 0)
@@ -118,6 +104,8 @@ static struct snd_soc_dai_link smdk_dai[] = {
                .codec_dai_name = "wm8994-aif1",
                .platform_name = "samsung-pcm.0",
                .codec_name = "wm8994-codec",
+               .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF |
+                          SND_SOC_DAIFMT_CBS_CFS,
                .ops = &smdk_wm8994_pcm_ops,
        },
 };
index a5b2c4ea90d96443f9f389f028de2a17d8fb8334..fd11404a3bc786f484774c28d64fa8c5a74c29da 100644 (file)
@@ -305,11 +305,6 @@ static struct snd_pcm_ops camelot_pcm_ops = {
        .pointer        = camelot_pos,
 };
 
-static void camelot_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_pcm *pcm = rtd->pcm;
@@ -328,7 +323,6 @@ static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd)
 static struct snd_soc_platform_driver sh7760_soc_platform = {
        .ops            = &camelot_pcm_ops,
        .pcm_new        = camelot_pcm_new,
-       .pcm_free       = camelot_pcm_free,
 };
 
 static int sh7760_soc_platform_probe(struct platform_device *pdev)
index 8869971d7884b93e463db07bb304f23c71b3b2c3..b87b22e88e43decf2d8e66c84ce411f2c97224fa 100644 (file)
@@ -820,12 +820,9 @@ static int fsi_clk_enable(struct device *dev,
                        return ret;
                }
 
-               if (clock->xck)
-                       clk_enable(clock->xck);
-               if (clock->ick)
-                       clk_enable(clock->ick);
-               if (clock->div)
-                       clk_enable(clock->div);
+               clk_enable(clock->xck);
+               clk_enable(clock->ick);
+               clk_enable(clock->div);
 
                clock->count++;
        }
@@ -1765,11 +1762,6 @@ static struct snd_pcm_ops fsi_pcm_ops = {
 #define PREALLOC_BUFFER                (32 * 1024)
 #define PREALLOC_BUFFER_MAX    (32 * 1024)
 
-static void fsi_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        return snd_pcm_lib_preallocate_pages_for_all(
@@ -1821,7 +1813,6 @@ static struct snd_soc_dai_driver fsi_soc_dai[] = {
 static struct snd_soc_platform_driver fsi_soc_platform = {
        .ops            = &fsi_pcm_ops,
        .pcm_new        = fsi_pcm_new,
-       .pcm_free       = fsi_pcm_free,
 };
 
 static const struct snd_soc_component_driver fsi_soc_component = {
index c58c2529f10345d01745d919124c0634a70d7deb..82f582344fe7e1dfce0e39af7c69289c5c4a3a3d 100644 (file)
@@ -63,16 +63,6 @@ static int migor_hw_params(struct snd_pcm_substream *substream,
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
-       ret = snd_soc_dai_set_fmt(rtd->cpu_dai, SND_SOC_DAIFMT_NB_IF |
-                                 SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS);
-       if (ret < 0)
-               return ret;
-
        codec_freq = rate * 512;
        /*
         * This propagates the parent frequency change to children and
@@ -144,6 +134,8 @@ static struct snd_soc_dai_link migor_dai = {
        .codec_dai_name = "wm8978-hifi",
        .platform_name = "siu-pcm-audio",
        .codec_name = "wm8978.0-001a",
+       .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S |
+                  SND_SOC_DAIFMT_CBS_CFS,
        .ops = &migor_dai_ops,
 };
 
index 14d1a71934692fb18b2155311b59a30b7cda62b1..7ac35c9d1cb8b008841a206d1eef1ed5618e4b17 100644 (file)
@@ -57,8 +57,7 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io)
        return (0x6 + ws) << 8;
 }
 
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
-                                struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io)
 {
        int id = rsnd_mod_id(mod);
@@ -75,12 +74,11 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
        return 0;
 }
 
-static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
-                                       struct rsnd_mod *mod,
+static int rsnd_adg_set_src_timsel_gen2(struct rsnd_mod *mod,
                                        struct rsnd_dai_stream *io,
                                        u32 timsel)
 {
-       int is_play = rsnd_dai_is_play(rdai, io);
+       int is_play = rsnd_io_is_play(io);
        int id = rsnd_mod_id(mod);
        int shift = (id % 2) ? 16 : 0;
        u32 mask, ws;
@@ -122,7 +120,6 @@ static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai,
 }
 
 int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
-                                 struct rsnd_dai *rdai,
                                  struct rsnd_dai_stream *io,
                                  unsigned int src_rate,
                                  unsigned int dst_rate)
@@ -178,7 +175,7 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
                return -EIO;
        }
 
-       ret = rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+       ret = rsnd_adg_set_src_timsel_gen2(mod, io, val);
        if (ret < 0) {
                dev_err(dev, "timsel error\n");
                return ret;
@@ -190,12 +187,11 @@ int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
 }
 
 int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
-                                    struct rsnd_dai *rdai,
                                     struct rsnd_dai_stream *io)
 {
        u32 val = rsnd_adg_ssi_ws_timing_gen2(io);
 
-       return rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val);
+       return rsnd_adg_set_src_timsel_gen2(mod, io, val);
 }
 
 int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
index 75308bbc2ce896e4a266ca0830cde8f5c020a225..1b53605f7154394d1746cb0a692953e296848c2a 100644 (file)
@@ -149,16 +149,16 @@ char *rsnd_mod_dma_name(struct rsnd_mod *mod)
        return mod->ops->dma_name(mod);
 }
 
-void rsnd_mod_init(struct rsnd_priv *priv,
-                  struct rsnd_mod *mod,
+void rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
+                  struct clk *clk,
                   enum rsnd_mod_type type,
                   int id)
 {
-       mod->priv       = priv;
        mod->id         = id;
        mod->ops        = ops;
        mod->type       = type;
+       mod->clk        = clk;
 }
 
 /*
@@ -412,7 +412,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
 /*
  *     rsnd_dai functions
  */
-#define __rsnd_mod_call(mod, func, rdai...)                    \
+#define __rsnd_mod_call(mod, func, param...)                   \
 ({                                                             \
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);         \
        struct device *dev = rsnd_priv_to_dev(priv);            \
@@ -422,18 +422,18 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
        if ((mod->status & mask) == call) {                             \
                dev_dbg(dev, "%s[%d] %s\n",                             \
                        rsnd_mod_name(mod), rsnd_mod_id(mod), #func);   \
-               ret = (mod)->ops->func(mod, rdai);                      \
+               ret = (mod)->ops->func(mod, param);                     \
                mod->status = (mod->status & ~mask) | (~call & mask);   \
        }                                                               \
        ret;                                                            \
 })
 
-#define rsnd_mod_call(mod, func, rdai...)      \
+#define rsnd_mod_call(mod, func, param...)     \
        (!(mod) ? -ENODEV :                     \
         !((mod)->ops->func) ? 0 :              \
-        __rsnd_mod_call(mod, func, rdai))
+        __rsnd_mod_call(mod, func, param))
 
-#define rsnd_dai_call(fn, io, rdai...)                         \
+#define rsnd_dai_call(fn, io, param...)                                \
 ({                                                             \
        struct rsnd_mod *mod;                                   \
        int ret = 0, i;                                         \
@@ -441,7 +441,7 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
                mod = (io)->mod[i];                             \
                if (!mod)                                       \
                        continue;                               \
-               ret = rsnd_mod_call(mod, fn, rdai);             \
+               ret = rsnd_mod_call(mod, fn, param);            \
                if (ret < 0)                                    \
                        break;                                  \
        }                                                       \
@@ -477,17 +477,7 @@ static void rsnd_dai_disconnect(struct rsnd_mod *mod,
        io->mod[mod->type] = NULL;
 }
 
-int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
-{
-       int id = rdai - priv->rdai;
-
-       if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
-               return -EINVAL;
-
-       return id;
-}
-
-struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id)
+struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
 {
        if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
                return NULL;
@@ -499,12 +489,7 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
 {
        struct rsnd_priv *priv = snd_soc_dai_get_drvdata(dai);
 
-       return rsnd_dai_get(priv, dai->id);
-}
-
-int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io)
-{
-       return &rdai->playback == io;
+       return rsnd_rdai_get(priv, dai->id);
 }
 
 /*
@@ -598,20 +583,20 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(init, io, rdai);
+               ret = rsnd_dai_call(init, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(start, io, rdai);
+               ret = rsnd_dai_call(start, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
                break;
        case SNDRV_PCM_TRIGGER_STOP:
-               ret = rsnd_dai_call(stop, io, rdai);
+               ret = rsnd_dai_call(stop, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
 
-               ret = rsnd_dai_call(quit, io, rdai);
+               ret = rsnd_dai_call(quit, io, priv);
                if (ret < 0)
                        goto dai_trigger_end;
 
@@ -873,15 +858,15 @@ static int rsnd_dai_probe(struct platform_device *pdev,
        priv->rdai      = rdai;
 
        for (i = 0; i < dai_nr; i++) {
-               rdai[i].info = &info->dai_info[i];
 
-               pmod = rdai[i].info->playback.ssi;
-               cmod = rdai[i].info->capture.ssi;
+               pmod = info->dai_info[i].playback.ssi;
+               cmod = info->dai_info[i].capture.ssi;
 
                /*
                 *      init rsnd_dai
                 */
                snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
+               rdai[i].priv = priv;
 
                /*
                 *      init snd_soc_dai_driver
@@ -895,6 +880,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].playback.channels_max    = 2;
 
                        rdai[i].playback.info = &info->dai_info[i].playback;
+                       rdai[i].playback.rdai = rdai + i;
                        rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
                }
                if (cmod) {
@@ -904,6 +890,7 @@ static int rsnd_dai_probe(struct platform_device *pdev,
                        drv[i].capture.channels_max     = 2;
 
                        rdai[i].capture.info = &info->dai_info[i].capture;
+                       rdai[i].capture.rdai = rdai + i;
                        rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
                }
 
@@ -1037,7 +1024,6 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
 }
 
 static int __rsnd_kctrl_new(struct rsnd_mod *mod,
-                           struct rsnd_dai *rdai,
                            struct snd_soc_pcm_runtime *rtd,
                            const unsigned char *name,
                            struct rsnd_kctrl_cfg *cfg,
@@ -1060,16 +1046,24 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
                return -ENOMEM;
 
        ret = snd_ctl_add(card, kctrl);
-       if (ret < 0)
+       if (ret < 0) {
+               snd_ctl_free_one(kctrl);
                return ret;
+       }
 
        cfg->update = update;
+       cfg->card = card;
+       cfg->kctrl = kctrl;
 
        return 0;
 }
 
+void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg)
+{
+       snd_ctl_remove(cfg->card, cfg->kctrl);
+}
+
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
@@ -1079,11 +1073,10 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
        _cfg->cfg.max   = max;
        _cfg->cfg.size  = RSND_DVC_CHANNELS;
        _cfg->cfg.val   = _cfg->val;
-       return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
 }
 
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
@@ -1093,11 +1086,10 @@ int rsnd_kctrl_new_s(struct rsnd_mod *mod,
        _cfg->cfg.max   = max;
        _cfg->cfg.size  = 1;
        _cfg->cfg.val   = &_cfg->val;
-       return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
 }
 
 int rsnd_kctrl_new_e(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     struct rsnd_kctrl_cfg_s *_cfg,
@@ -1109,7 +1101,7 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
        _cfg->cfg.size  = 1;
        _cfg->cfg.val   = &_cfg->val;
        _cfg->cfg.texts = texts;
-       return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+       return __rsnd_kctrl_new(mod, rtd, name, &_cfg->cfg, update);
 }
 
 /*
@@ -1125,11 +1117,11 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
        struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
        int ret;
 
-       ret = rsnd_dai_call(pcm_new, &rdai->playback, rdai, rtd);
+       ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd);
        if (ret)
                return ret;
 
-       ret = rsnd_dai_call(pcm_new, &rdai->capture, rdai, rtd);
+       ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd);
        if (ret)
                return ret;
 
@@ -1140,15 +1132,9 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd)
                PREALLOC_BUFFER, PREALLOC_BUFFER_MAX);
 }
 
-static void rsnd_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static struct snd_soc_platform_driver rsnd_soc_platform = {
        .ops            = &rsnd_pcm_ops,
        .pcm_new        = rsnd_pcm_new,
-       .pcm_free       = rsnd_pcm_free,
 };
 
 static const struct snd_soc_component_driver rsnd_soc_component = {
@@ -1156,13 +1142,11 @@ static const struct snd_soc_component_driver rsnd_soc_component = {
 };
 
 static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
-                                      struct rsnd_dai *rdai,
-                                      int is_play)
+                                      struct rsnd_dai_stream *io)
 {
-       struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
        int ret;
 
-       ret = rsnd_dai_call(probe, io, rdai);
+       ret = rsnd_dai_call(probe, io, priv);
        if (ret == -EAGAIN) {
                /*
                 * Fallback to PIO mode
@@ -1175,7 +1159,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                 *      rsnd_dma_init()
                 *      rsnd_ssi_fallback()
                 */
-               rsnd_dai_call(remove, io, rdai);
+               rsnd_dai_call(remove, io, priv);
 
                /*
                 * remove SRC/DVC from DAI,
@@ -1186,13 +1170,13 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                /*
                 * fallback
                 */
-               rsnd_dai_call(fallback, io, rdai);
+               rsnd_dai_call(fallback, io, priv);
 
                /*
                 * retry to "probe".
                 * DAI has SSI which is PIO mode only now.
                 */
-               ret = rsnd_dai_call(probe, io, rdai);
+               ret = rsnd_dai_call(probe, io, priv);
        }
 
        return ret;
@@ -1259,11 +1243,11 @@ static int rsnd_probe(struct platform_device *pdev)
        }
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret = rsnd_rdai_continuance_probe(priv, rdai, 1);
+               ret = rsnd_rdai_continuance_probe(priv, &rdai->playback);
                if (ret)
                        goto exit_snd_probe;
 
-               ret = rsnd_rdai_continuance_probe(priv, rdai, 0);
+               ret = rsnd_rdai_continuance_probe(priv, &rdai->capture);
                if (ret)
                        goto exit_snd_probe;
        }
@@ -1295,8 +1279,8 @@ exit_snd_soc:
        snd_soc_unregister_platform(dev);
 exit_snd_probe:
        for_each_rsnd_dai(rdai, priv, i) {
-               rsnd_dai_call(remove, &rdai->playback, rdai);
-               rsnd_dai_call(remove, &rdai->capture, rdai);
+               rsnd_dai_call(remove, &rdai->playback, priv);
+               rsnd_dai_call(remove, &rdai->capture, priv);
        }
 
        return ret;
@@ -1311,10 +1295,13 @@ static int rsnd_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
 
        for_each_rsnd_dai(rdai, priv, i) {
-               ret |= rsnd_dai_call(remove, &rdai->playback, rdai);
-               ret |= rsnd_dai_call(remove, &rdai->capture, rdai);
+               ret |= rsnd_dai_call(remove, &rdai->playback, priv);
+               ret |= rsnd_dai_call(remove, &rdai->capture, priv);
        }
 
+       snd_soc_unregister_component(&pdev->dev);
+       snd_soc_unregister_platform(&pdev->dev);
+
        return ret;
 }
 
index 5380a4827ba79ecb88bcaeb411bc6465aecb3019..d7f9ed959c4e208a8126174f76daee5a79af133f 100644 (file)
@@ -17,7 +17,6 @@
 struct rsnd_dvc {
        struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
-       struct clk *clk;
        struct rsnd_kctrl_cfg_m volume;
        struct rsnd_kctrl_cfg_m mute;
        struct rsnd_kctrl_cfg_s ren;    /* Ramp Enable */
@@ -118,9 +117,8 @@ static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
 }
 
 static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
@@ -129,12 +127,24 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
        return 0;
 }
 
+static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
+                               struct rsnd_priv *priv)
+{
+       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+
+       rsnd_kctrl_remove(dvc->volume);
+       rsnd_kctrl_remove(dvc->mute);
+       rsnd_kctrl_remove(dvc->ren);
+       rsnd_kctrl_remove(dvc->rup);
+       rsnd_kctrl_remove(dvc->rdown);
+
+       return 0;
+}
+
 static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(dvc_mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(dvc_mod);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(dvc_mod);
        struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int dvc_id = rsnd_mod_id(dvc_mod);
@@ -153,7 +163,7 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
                return -EINVAL;
        }
 
-       clk_prepare_enable(dvc->clk);
+       rsnd_mod_hw_start(dvc_mod);
 
        /*
         * fixme
@@ -173,23 +183,21 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
 
        rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
 
-       rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io);
+       rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io);
 
        return 0;
 }
 
 static int rsnd_dvc_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
-       struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
-
-       clk_disable_unprepare(dvc->clk);
+       rsnd_mod_hw_stop(mod);
 
        return 0;
 }
 
 static int rsnd_dvc_start(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai)
+                         struct rsnd_priv *priv)
 {
        rsnd_mod_write(mod, CMD_CTRL, 0x10);
 
@@ -197,7 +205,7 @@ static int rsnd_dvc_start(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        rsnd_mod_write(mod, CMD_CTRL, 0);
 
@@ -205,16 +213,16 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
 }
 
 static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
-                           struct rsnd_dai *rdai,
                            struct snd_soc_pcm_runtime *rtd)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
+       int is_play = rsnd_io_is_play(io);
        int ret;
 
        /* Volume */
-       ret = rsnd_kctrl_new_m(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_m(mod, rtd,
+                       is_play ?
                        "DVC Out Playback Volume" : "DVC In Capture Volume",
                        rsnd_dvc_volume_update,
                        &dvc->volume, 0x00800000 - 1);
@@ -222,8 +230,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                return ret;
 
        /* Mute */
-       ret = rsnd_kctrl_new_m(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_m(mod, rtd,
+                       is_play ?
                        "DVC Out Mute Switch" : "DVC In Mute Switch",
                        rsnd_dvc_volume_update,
                        &dvc->mute, 1);
@@ -231,16 +239,16 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
                return ret;
 
        /* Ramp */
-       ret = rsnd_kctrl_new_s(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_s(mod, rtd,
+                       is_play ?
                        "DVC Out Ramp Switch" : "DVC In Ramp Switch",
                        rsnd_dvc_volume_update,
                        &dvc->ren, 1);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_e(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_e(mod, rtd,
+                       is_play ?
                        "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
                        &dvc->rup,
                        rsnd_dvc_volume_update,
@@ -248,8 +256,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
        if (ret < 0)
                return ret;
 
-       ret = rsnd_kctrl_new_e(mod, rdai, rtd,
-                       rsnd_dai_is_play(rdai, io) ?
+       ret = rsnd_kctrl_new_e(mod, rtd,
+                       is_play ?
                        "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
                        &dvc->rdown,
                        rsnd_dvc_volume_update,
@@ -264,6 +272,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
 static struct rsnd_mod_ops rsnd_dvc_ops = {
        .name           = DVC_NAME,
        .probe          = rsnd_dvc_probe_gen2,
+       .remove         = rsnd_dvc_remove_gen2,
        .init           = rsnd_dvc_init,
        .quit           = rsnd_dvc_quit,
        .start          = rsnd_dvc_start,
@@ -356,9 +365,9 @@ int rsnd_dvc_probe(struct platform_device *pdev,
                        return PTR_ERR(clk);
 
                dvc->info = &info->dvc_info[i];
-               dvc->clk  = clk;
 
-               rsnd_mod_init(priv, &dvc->mod, &rsnd_dvc_ops, RSND_MOD_DVC, i);
+               rsnd_mod_init(&dvc->mod, &rsnd_dvc_ops,
+                             clk, RSND_MOD_DVC, i);
 
                dev_dbg(dev, "CMD%d probed\n", i);
        }
index 87a6f2d627753c0f69ba0b51fb7e2d0bc1438f45..de0685f2abaee64f4d729745497b7a6a4ae51e0e 100644 (file)
@@ -309,8 +309,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                RSND_GEN_M_REG(SRC_BUSIF_MODE,  0x0,    0x20),
                RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc,    0x20),
                RSND_GEN_M_REG(SRC_CTRL,        0x10,   0x20),
+               RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18,   0x20),
                RSND_GEN_M_REG(CMD_ROUTE_SLCT,  0x18c,  0x20),
                RSND_GEN_M_REG(CMD_CTRL,        0x190,  0x20),
+               RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
+               RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
+               RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
+               RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4),
                RSND_GEN_M_REG(SRC_SWRSR,       0x200,  0x40),
                RSND_GEN_M_REG(SRC_SRCIR,       0x204,  0x40),
                RSND_GEN_M_REG(SRC_ADINR,       0x214,  0x40),
@@ -403,6 +408,16 @@ static int rsnd_gen1_probe(struct platform_device *pdev,
                RSND_GEN_M_REG(SRC_IFSVR,       0x220,  0x40),
                RSND_GEN_M_REG(SRC_SRCCR,       0x224,  0x40),
                RSND_GEN_M_REG(SRC_MNFSR,       0x228,  0x40),
+               /*
+                * ADD US
+                *
+                * SRC_STATUS
+                * SRC_INT_EN
+                * SCU_SYS_STATUS0
+                * SCU_SYS_STATUS1
+                * SCU_SYS_INT_EN0
+                * SCU_SYS_INT_EN1
+                */
        };
        struct rsnd_regmap_field_conf conf_adg[] = {
                RSND_GEN_S_REG(BRRA,            0x00),
index 5826c8abf7949d3ed1807dfe1c61a7fa8a219f84..e7914bd610e2120644f616e6500bdf3ad9ec24d3 100644 (file)
@@ -44,6 +44,8 @@ enum rsnd_reg {
        RSND_REG_SRC_IFSCR,
        RSND_REG_SRC_IFSVR,
        RSND_REG_SRC_SRCCR,
+       RSND_REG_SCU_SYS_STATUS0,
+       RSND_REG_SCU_SYS_INT_EN0,
        RSND_REG_CMD_ROUTE_SLCT,
        RSND_REG_DVC_SWRSR,
        RSND_REG_DVC_DVUIR,
@@ -94,6 +96,9 @@ enum rsnd_reg {
        RSND_REG_SHARE23,
        RSND_REG_SHARE24,
        RSND_REG_SHARE25,
+       RSND_REG_SHARE26,
+       RSND_REG_SHARE27,
+       RSND_REG_SHARE28,
 
        RSND_REG_MAX,
 };
@@ -135,6 +140,9 @@ enum rsnd_reg {
 #define RSND_REG_DVC_VRCTR             RSND_REG_SHARE23
 #define RSND_REG_DVC_VRPDR             RSND_REG_SHARE24
 #define RSND_REG_DVC_VRDBR             RSND_REG_SHARE25
+#define RSND_REG_SCU_SYS_STATUS1       RSND_REG_SHARE26
+#define RSND_REG_SCU_SYS_INT_EN1       RSND_REG_SHARE27
+#define RSND_REG_SRC_INT_ENABLE0       RSND_REG_SHARE28
 
 struct rsnd_of_data;
 struct rsnd_priv;
@@ -182,9 +190,9 @@ void  rsnd_dma_quit(struct rsnd_priv *priv,
  *     R-Car sound mod
  */
 enum rsnd_mod_type {
-       RSND_MOD_SRC = 0,
+       RSND_MOD_DVC = 0,
+       RSND_MOD_SRC,
        RSND_MOD_SSI,
-       RSND_MOD_DVC,
        RSND_MOD_MAX,
 };
 
@@ -192,32 +200,31 @@ struct rsnd_mod_ops {
        char *name;
        char* (*dma_name)(struct rsnd_mod *mod);
        int (*probe)(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai);
+                    struct rsnd_priv *priv);
        int (*remove)(struct rsnd_mod *mod,
-                     struct rsnd_dai *rdai);
+                     struct rsnd_priv *priv);
        int (*init)(struct rsnd_mod *mod,
-                   struct rsnd_dai *rdai);
+                   struct rsnd_priv *priv);
        int (*quit)(struct rsnd_mod *mod,
-                   struct rsnd_dai *rdai);
+                   struct rsnd_priv *priv);
        int (*start)(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai);
+                    struct rsnd_priv *priv);
        int (*stop)(struct rsnd_mod *mod,
-                   struct rsnd_dai *rdai);
+                   struct rsnd_priv *priv);
        int (*pcm_new)(struct rsnd_mod *mod,
-                      struct rsnd_dai *rdai,
                       struct snd_soc_pcm_runtime *rtd);
        int (*fallback)(struct rsnd_mod *mod,
-                       struct rsnd_dai *rdai);
+                       struct rsnd_priv *priv);
 };
 
 struct rsnd_dai_stream;
 struct rsnd_mod {
        int id;
        enum rsnd_mod_type type;
-       struct rsnd_priv *priv;
        struct rsnd_mod_ops *ops;
        struct rsnd_dma dma;
        struct rsnd_dai_stream *io;
+       struct clk *clk;
        u32 status;
 };
 /*
@@ -248,15 +255,17 @@ struct rsnd_mod {
 #define __rsnd_mod_call_pcm_new                0
 #define __rsnd_mod_call_fallback       0
 
-#define rsnd_mod_to_priv(mod) ((mod)->priv)
+#define rsnd_mod_to_priv(mod) (rsnd_io_to_priv(rsnd_mod_to_io(mod)))
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
 #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma)
 #define rsnd_mod_to_io(mod) ((mod)->io)
 #define rsnd_mod_id(mod) ((mod)->id)
+#define rsnd_mod_hw_start(mod) clk_prepare_enable((mod)->clk)
+#define rsnd_mod_hw_stop(mod)  clk_disable_unprepare((mod)->clk)
 
-void rsnd_mod_init(struct rsnd_priv *priv,
-                  struct rsnd_mod *mod,
+void rsnd_mod_init(struct rsnd_mod *mod,
                   struct rsnd_mod_ops *ops,
+                  struct clk *clk,
                   enum rsnd_mod_type type,
                   int id);
 char *rsnd_mod_name(struct rsnd_mod *mod);
@@ -270,6 +279,7 @@ struct rsnd_dai_stream {
        struct snd_pcm_substream *substream;
        struct rsnd_mod *mod[RSND_MOD_MAX];
        struct rsnd_dai_path_info *info; /* rcar_snd.h */
+       struct rsnd_dai *rdai;
        int byte_pos;
        int period_pos;
        int byte_per_period;
@@ -278,12 +288,18 @@ struct rsnd_dai_stream {
 #define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
 #define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
 #define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC])
+#define rsnd_io_to_rdai(io)    ((io)->rdai)
+#define rsnd_io_to_priv(io)    (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
+#define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
+#define rsnd_io_to_runtime(io) ((io)->substream ? \
+                               (io)->substream->runtime : NULL)
+
 
 struct rsnd_dai {
        char name[RSND_DAI_NAME_SIZE];
-       struct rsnd_dai_platform_info *info; /* rcar_snd.h */
        struct rsnd_dai_stream playback;
        struct rsnd_dai_stream capture;
+       struct rsnd_priv *priv;
 
        unsigned int clk_master:1;
        unsigned int bit_clk_inv:1;
@@ -293,22 +309,18 @@ struct rsnd_dai {
 };
 
 #define rsnd_rdai_nr(priv) ((priv)->rdai_nr)
+#define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master)
+#define rsnd_rdai_to_priv(rdai) ((rdai)->priv)
 #define for_each_rsnd_dai(rdai, priv, i)               \
        for (i = 0;                                     \
             (i < rsnd_rdai_nr(priv)) &&                \
-            ((rdai) = rsnd_dai_get(priv, i));          \
+            ((rdai) = rsnd_rdai_get(priv, i));         \
             i++)
 
-struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
-int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
-int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
-#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
-#define rsnd_io_to_runtime(io) ((io)->substream ? \
-                               (io)->substream->runtime : NULL)
+struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id);
 
 void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
 int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
-#define rsnd_dai_is_clk_master(rdai) ((rdai)->clk_master)
 
 /*
  *     R-Car Gen1/Gen2
@@ -339,15 +351,12 @@ int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv,
                                  unsigned int src_rate,
                                  unsigned int dst_rate);
 int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod,
-                                 struct rsnd_dai *rdai,
                                  struct rsnd_dai_stream *io,
                                  unsigned int src_rate,
                                  unsigned int dst_rate);
 int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod,
-                                    struct rsnd_dai *rdai,
                                     struct rsnd_dai_stream *io);
-int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_dai *rdai,
-                                struct rsnd_mod *mod,
+int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod,
                                 struct rsnd_dai_stream *io);
 
 /*
@@ -427,6 +436,8 @@ struct rsnd_kctrl_cfg {
        u32 *val;
        const char * const *texts;
        void (*update)(struct rsnd_mod *mod);
+       struct snd_card *card;
+       struct snd_kcontrol *kctrl;
 };
 
 #define RSND_DVC_CHANNELS      2
@@ -440,22 +451,22 @@ struct rsnd_kctrl_cfg_s {
        u32 val;
 };
 
+void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg);
+#define rsnd_kctrl_remove(_cfg)        _rsnd_kctrl_remove(&((_cfg).cfg))
+
 int rsnd_kctrl_new_m(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_m *_cfg,
                     u32 max);
 int rsnd_kctrl_new_s(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     void (*update)(struct rsnd_mod *mod),
                     struct rsnd_kctrl_cfg_s *_cfg,
                     u32 max);
 int rsnd_kctrl_new_e(struct rsnd_mod *mod,
-                    struct rsnd_dai *rdai,
                     struct snd_soc_pcm_runtime *rtd,
                     const unsigned char *name,
                     struct rsnd_kctrl_cfg_s *_cfg,
@@ -474,14 +485,10 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
                                   struct rsnd_dai_stream *io,
                                   struct snd_pcm_runtime *runtime);
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-                       struct rsnd_dai *rdai,
                        int use_busif);
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-                      struct rsnd_dai *rdai);
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
-                           struct rsnd_dai *rdai);
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
-                            struct rsnd_dai *rdai);
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod);
+int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
+int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
 
 #define rsnd_src_nr(priv) ((priv)->src_nr)
 
index eede3ac6eed232b12307881574a8d041f1d88352..81c182b4bad531c8afe3a071da4c9ad41c4d868f 100644 (file)
 
 #define SRC_NAME "src"
 
+/* SRCx_STATUS */
+#define OUF_SRCO       ((1 << 12) | (1 << 13))
+#define OUF_SRCI       ((1 <<  9) | (1 <<  8))
+
+/* SCU_SYSTEM_STATUS0/1 */
+#define OUF_SRC(id)    ((1 << (id + 16)) | (1 << id))
+
 struct rsnd_src {
        struct rsnd_src_platform_info *info; /* rcar_snd.h */
        struct rsnd_mod mod;
-       struct clk *clk;
+       int err;
 };
 
 #define RSND_SRC_NAME_SIZE 16
@@ -107,10 +114,10 @@ struct rsnd_src {
  *             Gen1/Gen2 common functions
  */
 int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
-                       struct rsnd_dai *rdai,
                        int use_busif)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(ssi_mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        int ssi_id = rsnd_mod_id(ssi_mod);
 
@@ -140,7 +147,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
                if (shift >= 0)
                        rsnd_mod_bset(ssi_mod, SSI_MODE1,
                                      0x3 << shift,
-                                     rsnd_dai_is_clk_master(rdai) ?
+                                     rsnd_rdai_is_clk_master(rdai) ?
                                      0x2 << shift : 0x1 << shift);
        }
 
@@ -174,8 +181,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
-                      struct rsnd_dai *rdai)
+int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod)
 {
        /*
         * DMA settings for SSIU
@@ -185,8 +191,7 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
-                           struct rsnd_dai *rdai)
+int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
 
@@ -202,8 +207,7 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
        return 0;
 }
 
-int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
-                           struct rsnd_dai *rdai)
+int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
 
@@ -240,8 +244,7 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
        return rate;
 }
 
-static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
-                                    struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_rate(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -273,12 +276,13 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_init(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+static int rsnd_src_init(struct rsnd_mod *mod)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
 
-       clk_prepare_enable(src->clk);
+       rsnd_mod_hw_start(mod);
+
+       src->err = 0;
 
        /*
         * Initialize the operation of the SRC internal circuits
@@ -290,11 +294,16 @@ static int rsnd_src_init(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
+       struct device *dev = rsnd_priv_to_dev(priv);
+
+       rsnd_mod_hw_stop(mod);
 
-       clk_disable_unprepare(src->clk);
+       if (src->err)
+               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod), src->err);
 
        return 0;
 }
@@ -319,8 +328,7 @@ static int rsnd_src_stop(struct rsnd_mod *mod)
 /*
  *             Gen1 functions
  */
-static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
-                                  struct rsnd_dai *rdai)
+static int rsnd_src_set_route_gen1(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct src_route_config {
@@ -348,7 +356,7 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
        /*
         * SRC_ROUTE_SELECT
         */
-       val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2;
+       val = rsnd_io_is_play(io) ? 0x1 : 0x2;
        val = val               << routes[id].shift;
        mask = routes[id].mask  << routes[id].shift;
 
@@ -357,8 +365,7 @@ static int rsnd_src_set_route_gen1(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
-                                           struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
@@ -416,13 +423,12 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
-                                         struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod)
 {
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        int ret;
 
-       ret = rsnd_src_set_convert_rate(mod, rdai);
+       ret = rsnd_src_set_convert_rate(mod);
        if (ret < 0)
                return ret;
 
@@ -443,9 +449,8 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        dev_dbg(dev, "%s[%d] (Gen1) is probed\n",
@@ -455,23 +460,23 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_init_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        int ret;
 
-       ret = rsnd_src_init(mod, rdai);
+       ret = rsnd_src_init(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_route_gen1(mod, rdai);
+       ret = rsnd_src_set_route_gen1(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_rate_gen1(mod, rdai);
+       ret = rsnd_src_set_convert_rate_gen1(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_timing_gen1(mod, rdai);
+       ret = rsnd_src_set_convert_timing_gen1(mod);
        if (ret < 0)
                return ret;
 
@@ -479,7 +484,7 @@ static int rsnd_src_init_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_start_gen1(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
        int id = rsnd_mod_id(mod);
 
@@ -489,7 +494,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        int id = rsnd_mod_id(mod);
 
@@ -510,8 +515,111 @@ static struct rsnd_mod_ops rsnd_src_gen1_ops = {
 /*
  *             Gen2 functions
  */
-static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
-                                         struct rsnd_dai *rdai)
+#define rsnd_src_irq_enable_gen2(mod)  rsnd_src_irq_ctrol_gen2(mod, 1)
+#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0)
+static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
+{
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 sys_int_val, int_val, sys_int_mask;
+       int irq = src->info->irq;
+       int id = rsnd_mod_id(mod);
+
+       sys_int_val =
+       sys_int_mask = OUF_SRC(id);
+       int_val = 0x3300;
+
+       /*
+        * IRQ is not supported on non-DT
+        * see
+        *      rsnd_src_probe_gen2()
+        */
+       if ((irq <= 0) || !enable) {
+               sys_int_val = 0;
+               int_val = 0;
+       }
+
+       rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
+       rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
+       rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
+}
+
+static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
+{
+       u32 val = OUF_SRC(rsnd_mod_id(mod));
+
+       rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val);
+       rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val);
+}
+
+static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
+{
+       u32 val = OUF_SRC(rsnd_mod_id(mod));
+       bool ret = false;
+
+       if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) ||
+           (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) {
+               struct rsnd_src *src = rsnd_mod_to_src(mod);
+
+               src->err++;
+               ret = true;
+       }
+
+       /* clear error static */
+       rsnd_src_error_clear_gen2(mod);
+
+       return ret;
+}
+
+static int _rsnd_src_start_gen2(struct rsnd_mod *mod)
+{
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
+
+       rsnd_mod_write(mod, SRC_CTRL, val);
+
+       rsnd_src_error_clear_gen2(mod);
+
+       rsnd_src_start(mod);
+
+       rsnd_src_irq_enable_gen2(mod);
+
+       return 0;
+}
+
+static int _rsnd_src_stop_gen2(struct rsnd_mod *mod)
+{
+       rsnd_src_irq_disable_gen2(mod);
+
+       rsnd_mod_write(mod, SRC_CTRL, 0);
+
+       rsnd_src_error_record_gen2(mod);
+
+       return rsnd_src_stop(mod);
+}
+
+static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data)
+{
+       struct rsnd_mod *mod = data;
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+
+       if (!io)
+               return IRQ_NONE;
+
+       if (rsnd_src_error_record_gen2(mod)) {
+               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+               struct device *dev = rsnd_priv_to_dev(priv);
+
+               _rsnd_src_stop_gen2(mod);
+               _rsnd_src_start_gen2(mod);
+
+               dev_dbg(dev, "%s[%d] restart\n",
+                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
@@ -535,7 +643,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
                return -EINVAL;
        }
 
-       ret = rsnd_src_set_convert_rate(mod, rdai);
+       ret = rsnd_src_set_convert_rate(mod);
        if (ret < 0)
                return ret;
 
@@ -563,8 +671,7 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
-                                           struct rsnd_dai *rdai)
+static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod)
 {
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -573,59 +680,78 @@ static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod,
        int ret;
 
        if (convert_rate)
-               ret = rsnd_adg_set_convert_clk_gen2(mod, rdai, io,
+               ret = rsnd_adg_set_convert_clk_gen2(mod, io,
                                                    runtime->rate,
                                                    convert_rate);
        else
-               ret = rsnd_adg_set_convert_timing_gen2(mod, rdai, io);
+               ret = rsnd_adg_set_convert_timing_gen2(mod, io);
 
        return ret;
 }
 
 static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_src *src = rsnd_mod_to_src(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
+       int irq = src->info->irq;
        int ret;
 
+       if (irq > 0) {
+               /*
+                * IRQ is not supported on non-DT
+                * see
+                *      rsnd_src_irq_enable_gen2()
+                */
+               ret = devm_request_irq(dev, irq,
+                                      rsnd_src_interrupt_gen2,
+                                      IRQF_SHARED,
+                                      dev_name(dev), mod);
+               if (ret)
+                       goto rsnd_src_probe_gen2_fail;
+       }
+
        ret = rsnd_dma_init(priv,
                            rsnd_mod_to_dma(mod),
                            rsnd_info_is_playback(priv, src),
                            src->info->dma_id);
-       if (ret < 0)
-               dev_err(dev, "%s[%d] (Gen2) failed\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
-       else
-               dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
-                       rsnd_mod_name(mod), rsnd_mod_id(mod));
+       if (ret)
+               goto rsnd_src_probe_gen2_fail;
+
+       dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+       return ret;
+
+rsnd_src_probe_gen2_fail:
+       dev_err(dev, "%s[%d] (Gen2) failed\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod));
 
        return ret;
 }
 
 static int rsnd_src_remove_gen2(struct rsnd_mod *mod,
-                               struct rsnd_dai *rdai)
+                               struct rsnd_priv *priv)
 {
-       rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
 
        return 0;
 }
 
 static int rsnd_src_init_gen2(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        int ret;
 
-       ret = rsnd_src_init(mod, rdai);
+       ret = rsnd_src_init(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_rate_gen2(mod, rdai);
+       ret = rsnd_src_set_convert_rate_gen2(mod);
        if (ret < 0)
                return ret;
 
-       ret = rsnd_src_set_convert_timing_gen2(mod, rdai);
+       ret = rsnd_src_set_convert_timing_gen2(mod);
        if (ret < 0)
                return ret;
 
@@ -633,29 +759,23 @@ static int rsnd_src_init_gen2(struct rsnd_mod *mod,
 }
 
 static int rsnd_src_start_gen2(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
-       u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
-
-       rsnd_dma_start(rsnd_mod_to_dma(&src->mod));
+       rsnd_dma_start(rsnd_mod_to_dma(mod));
 
-       rsnd_mod_write(mod, SRC_CTRL, val);
-
-       return rsnd_src_start(mod);
+       return _rsnd_src_start_gen2(mod);
 }
 
 static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       int ret;
 
-       rsnd_mod_write(mod, SRC_CTRL, 0);
+       ret = _rsnd_src_stop_gen2(mod);
 
-       rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
+       rsnd_dma_stop(rsnd_mod_to_dma(mod));
 
-       return rsnd_src_stop(mod);
+       return ret;
 }
 
 static struct rsnd_mod_ops rsnd_src_gen2_ops = {
@@ -681,10 +801,11 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
                              struct rsnd_priv *priv)
 {
        struct device_node *src_node;
+       struct device_node *np;
        struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct rsnd_src_platform_info *src_info;
        struct device *dev = &pdev->dev;
-       int nr;
+       int nr, i;
 
        if (!of_data)
                return;
@@ -708,6 +829,13 @@ static void rsnd_of_parse_src(struct platform_device *pdev,
        info->src_info          = src_info;
        info->src_info_nr       = nr;
 
+       i = 0;
+       for_each_child_of_node(src_node, np) {
+               src_info[i].irq = irq_of_parse_and_map(np, 0);
+
+               i++;
+       }
+
 rsnd_of_parse_src_end:
        of_node_put(src_node);
 }
@@ -761,9 +889,8 @@ int rsnd_src_probe(struct platform_device *pdev,
                        return PTR_ERR(clk);
 
                src->info = &info->src_info[i];
-               src->clk = clk;
 
-               rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i);
+               rsnd_mod_init(&src->mod, ops, clk, RSND_MOD_SRC, i);
 
                dev_dbg(dev, "SRC%d probed\n", i);
        }
index 3844fbef46649db6133b7e3e4266d8f014eb28ae..9e7b627c08e2256dbe09acd063432b7b3b7c1107 100644 (file)
 #define SSI_NAME "ssi"
 
 struct rsnd_ssi {
-       struct clk *clk;
        struct rsnd_ssi_platform_info *info; /* rcar_snd.h */
        struct rsnd_ssi *parent;
        struct rsnd_mod mod;
 
-       struct rsnd_dai *rdai;
        u32 cr_own;
        u32 cr_clk;
        int err;
        unsigned int usrcnt;
-       unsigned int rate;
 };
 
 #define for_each_rsnd_ssi(pos, priv, i)                                        \
@@ -128,7 +125,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod,
 static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
                                     struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        int i, j, ret;
@@ -157,7 +154,6 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
                        ret = rsnd_adg_ssi_clk_try_start(&ssi->mod, main_rate);
                        if (0 == ret) {
-                               ssi->rate       = rate;
                                ssi->cr_clk     = FORCE | SWL_32 |
                                                  SCKD | SWSD | CKDV(j);
 
@@ -176,26 +172,25 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
 
 static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi)
 {
-       ssi->rate = 0;
        ssi->cr_clk = 0;
        rsnd_adg_ssi_clk_stop(&ssi->mod);
 }
 
 static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
-                             struct rsnd_dai *rdai,
                              struct rsnd_dai_stream *io)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_priv *priv = rsnd_io_to_priv(io);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 cr_mode;
        u32 cr;
 
        if (0 == ssi->usrcnt) {
-               clk_prepare_enable(ssi->clk);
+               rsnd_mod_hw_start(&ssi->mod);
 
-               if (rsnd_dai_is_clk_master(rdai)) {
+               if (rsnd_rdai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
-                               rsnd_ssi_hw_start(ssi->parent, rdai, io);
+                               rsnd_ssi_hw_start(ssi->parent, io);
                        else
                                rsnd_ssi_master_clk_start(ssi, io);
                }
@@ -214,7 +209,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
        rsnd_mod_write(&ssi->mod, SSICR, cr);
 
        /* enable WS continue */
-       if (rsnd_dai_is_clk_master(rdai))
+       if (rsnd_rdai_is_clk_master(rdai))
                rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
 
        /* clear error status */
@@ -226,10 +221,11 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
                rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
 }
 
-static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
-                            struct rsnd_dai *rdai)
+static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
+       struct rsnd_dai_stream *io = rsnd_mod_to_io(&ssi->mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct device *dev = rsnd_priv_to_dev(priv);
        u32 cr;
 
@@ -256,14 +252,14 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
                rsnd_mod_write(&ssi->mod, SSICR, cr);   /* disabled all */
                rsnd_ssi_status_check(&ssi->mod, IIRQ);
 
-               if (rsnd_dai_is_clk_master(rdai)) {
+               if (rsnd_rdai_is_clk_master(rdai)) {
                        if (rsnd_ssi_clk_from_parent(ssi))
-                               rsnd_ssi_hw_stop(ssi->parent, rdai);
+                               rsnd_ssi_hw_stop(ssi->parent);
                        else
                                rsnd_ssi_master_clk_stop(ssi);
                }
 
-               clk_disable_unprepare(ssi->clk);
+               rsnd_mod_hw_stop(&ssi->mod);
        }
 
        dev_dbg(dev, "%s[%d] hw stopped\n",
@@ -274,10 +270,11 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
  *     SSI mod common functions
  */
 static int rsnd_ssi_init(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        u32 cr;
 
@@ -311,13 +308,12 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
                cr |= SDTA;
        if (rdai->sys_delay)
                cr |= DEL;
-       if (rsnd_dai_is_play(rdai, io))
+       if (rsnd_io_is_play(io))
                cr |= TRMD;
 
        /*
         * set ssi parameter
         */
-       ssi->rdai       = rdai;
        ssi->cr_own     = cr;
        ssi->err        = -1; /* ignore 1st error */
 
@@ -325,16 +321,15 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_quit(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        if (ssi->err > 0)
-               dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err);
+               dev_warn(dev, "%s[%d] under/over flow err = %d\n",
+                        rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err);
 
-       ssi->rdai       = NULL;
        ssi->cr_own     = 0;
        ssi->err        = 0;
 
@@ -353,32 +348,32 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
 }
 
 static int rsnd_ssi_start(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai)
+                         struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
 
-       rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
+       rsnd_src_ssiu_start(mod, rsnd_ssi_use_busif(mod));
 
-       rsnd_ssi_hw_start(ssi, rdai, io);
+       rsnd_ssi_hw_start(ssi, io);
 
-       rsnd_src_ssi_irq_enable(mod, rdai);
+       rsnd_src_ssi_irq_enable(mod);
 
        return 0;
 }
 
 static int rsnd_ssi_stop(struct rsnd_mod *mod,
-                        struct rsnd_dai *rdai)
+                        struct rsnd_priv *priv)
 {
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
 
-       rsnd_src_ssi_irq_disable(mod, rdai);
+       rsnd_src_ssi_irq_disable(mod);
 
        rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
 
-       rsnd_ssi_hw_stop(ssi, rdai);
+       rsnd_ssi_hw_stop(ssi);
 
-       rsnd_src_ssiu_stop(mod, rdai);
+       rsnd_src_ssiu_stop(mod);
 
        return 0;
 }
@@ -386,16 +381,17 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod,
 static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
 {
        struct rsnd_ssi *ssi = data;
-       struct rsnd_dai *rdai = ssi->rdai;
        struct rsnd_mod *mod = &ssi->mod;
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+       int is_dma = rsnd_ssi_is_dma_mode(mod);
        u32 status = rsnd_mod_read(mod, SSISR);
 
        if (!io)
                return IRQ_NONE;
 
        /* PIO only */
-       if (status & DIRQ) {
+       if (!is_dma && (status & DIRQ)) {
                struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
                u32 *buf = (u32 *)(runtime->dma_area +
                                   rsnd_dai_pointer_offset(io, 0));
@@ -405,7 +401,7 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
                 * directly as 32bit data
                 * see rsnd_ssi_init()
                 */
-               if (rsnd_dai_is_play(rdai, io))
+               if (rsnd_io_is_play(io))
                        rsnd_mod_write(mod, SSITDR, *buf);
                else
                        *buf = rsnd_mod_read(mod, SSIRDR);
@@ -415,14 +411,13 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
 
        /* PIO / DMA */
        if (status & (UIRQ | OIRQ)) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
                struct device *dev = rsnd_priv_to_dev(priv);
 
                /*
                 * restart SSI
                 */
-               rsnd_ssi_stop(mod, rdai);
-               rsnd_ssi_start(mod, rdai);
+               rsnd_ssi_stop(mod, priv);
+               rsnd_ssi_start(mod, priv);
 
                dev_dbg(dev, "%s[%d] restart\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
@@ -437,9 +432,8 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
  *             SSI PIO
  */
 static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        int ret;
@@ -468,9 +462,8 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
 };
 
 static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
-                         struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        int dma_id = ssi->info->dma_id;
@@ -503,14 +496,13 @@ rsnd_ssi_dma_probe_fail:
 }
 
 static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
-                              struct rsnd_dai *rdai)
+                              struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
        int irq = ssi->info->irq;
 
-       rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+       rsnd_dma_quit(priv, rsnd_mod_to_dma(mod));
 
        /* PIO will request IRQ again */
        devm_free_irq(dev, irq, ssi);
@@ -519,9 +511,8 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_fallback(struct rsnd_mod *mod,
-                            struct rsnd_dai *rdai)
+                            struct rsnd_priv *priv)
 {
-       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct device *dev = rsnd_priv_to_dev(priv);
 
        /*
@@ -540,25 +531,25 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod,
 }
 
 static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
-                             struct rsnd_dai *rdai)
+                             struct rsnd_priv *priv)
 {
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 
-       rsnd_ssi_start(mod, rdai);
-
        rsnd_dma_start(dma);
 
+       rsnd_ssi_start(mod, priv);
+
        return 0;
 }
 
 static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
-                            struct rsnd_dai *rdai)
+                            struct rsnd_priv *priv)
 {
        struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
 
-       rsnd_dma_stop(dma);
+       rsnd_ssi_stop(mod, priv);
 
-       rsnd_ssi_stop(mod, rdai);
+       rsnd_dma_stop(dma);
 
        return 0;
 }
@@ -734,7 +725,6 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                        return PTR_ERR(clk);
 
                ssi->info       = pinfo;
-               ssi->clk        = clk;
 
                ops = &rsnd_ssi_non_ops;
                if (pinfo->dma_id > 0)
@@ -742,7 +732,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
                else if (rsnd_ssi_pio_available(ssi))
                        ops = &rsnd_ssi_pio_ops;
 
-               rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i);
+               rsnd_mod_init(&ssi->mod, ops, clk, RSND_MOD_SSI, i);
 
                rsnd_ssi_parent_clk_setup(priv, ssi);
        }
index 32eb6da2d2bde2ac994aeda90ef673fbd6d6e426..82902f56e82fec8f8d9758e4b133167dca6e54ee 100644 (file)
@@ -589,7 +589,6 @@ static void siu_pcm_free(struct snd_pcm *pcm)
        tasklet_kill(&port_info->playback.tasklet);
 
        siu_free_port(port_info);
-       snd_pcm_lib_preallocate_free_for_all(pcm);
 
        dev_dbg(pcm->card->dev, "%s\n", __func__);
 }
index 2e10e9a383768a5ed5132fb182b8ef3753c39540..08d7259bbaabad727709281234905011e990f07d 100644 (file)
@@ -48,15 +48,18 @@ static void soc_ac97_device_release(struct device *dev)
 }
 
 /**
- * snd_soc_new_ac97_codec - initailise AC97 device
- * @codec: audio codec
+ * snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device
+ * @codec: The CODEC for which to create the AC'97 device
  *
- * Initialises AC97 codec resources for use by ad-hoc devices only.
+ * Allocated a new snd_ac97 device and intializes it, but does not yet register
+ * it. The caller is responsible to either call device_add(&ac97->dev) to
+ * register the device, or to call put_device(&ac97->dev) to free the device.
+ *
+ * Returns: A snd_ac97 device or a PTR_ERR in case of an error.
  */
-struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
+struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec)
 {
        struct snd_ac97 *ac97;
-       int ret;
 
        ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
        if (ac97 == NULL)
@@ -73,7 +76,28 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
                     codec->component.card->snd_card->number, 0,
                     codec->component.name);
 
-       ret = device_register(&ac97->dev);
+       device_initialize(&ac97->dev);
+
+       return ac97;
+}
+EXPORT_SYMBOL(snd_soc_alloc_ac97_codec);
+
+/**
+ * snd_soc_new_ac97_codec - initailise AC97 device
+ * @codec: audio codec
+ *
+ * Initialises AC97 codec resources for use by ad-hoc devices only.
+ */
+struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
+{
+       struct snd_ac97 *ac97;
+       int ret;
+
+       ac97 = snd_soc_alloc_ac97_codec(codec);
+       if (IS_ERR(ac97))
+               return ac97;
+
+       ret = device_add(&ac97->dev);
        if (ret) {
                put_device(&ac97->dev);
                return ERR_PTR(ret);
index 590a82f01d0bdc2cc2fa39b89c006a2ec8b2b589..025c38fbe3c03fea08db0b365e472902c5f110fc 100644 (file)
@@ -659,7 +659,8 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
                        rtd->dai_link->stream_name);
 
                ret = snd_pcm_new_internal(rtd->card->snd_card, new_name, num,
-                               1, 0, &be_pcm);
+                               rtd->dai_link->dpcm_playback,
+                               rtd->dai_link->dpcm_capture, &be_pcm);
                if (ret < 0) {
                        dev_err(rtd->card->dev, "ASoC: can't create compressed for %s\n",
                                rtd->dai_link->name);
@@ -668,8 +669,10 @@ int soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num)
 
                rtd->pcm = be_pcm;
                rtd->fe_compr = 1;
-               be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
-               be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
+               if (rtd->dai_link->dpcm_playback)
+                       be_pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->private_data = rtd;
+               else if (rtd->dai_link->dpcm_capture)
+                       be_pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream->private_data = rtd;
                memcpy(compr->ops, &soc_compr_dyn_ops, sizeof(soc_compr_dyn_ops));
        } else
                memcpy(compr->ops, &soc_compr_ops, sizeof(soc_compr_ops));
index 985052b3fbed375dee764a64b63852998532d5e2..d94434d6138ea3ddb6dbe03d20b444c20fa48d19 100644 (file)
@@ -191,6 +191,39 @@ static ssize_t pmdown_time_set(struct device *dev,
 
 static DEVICE_ATTR(pmdown_time, 0644, pmdown_time_show, pmdown_time_set);
 
+static struct attribute *soc_dev_attrs[] = {
+       &dev_attr_codec_reg.attr,
+       &dev_attr_pmdown_time.attr,
+       NULL
+};
+
+static umode_t soc_dev_attr_is_visible(struct kobject *kobj,
+                                      struct attribute *attr, int idx)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev);
+
+       if (attr == &dev_attr_pmdown_time.attr)
+               return attr->mode; /* always visible */
+       return rtd->codec ? attr->mode : 0; /* enabled only with codec */
+}
+
+static const struct attribute_group soc_dapm_dev_group = {
+       .attrs = soc_dapm_dev_attrs,
+       .is_visible = soc_dev_attr_is_visible,
+};
+
+static const struct attribute_group soc_dev_roup = {
+       .attrs = soc_dev_attrs,
+       .is_visible = soc_dev_attr_is_visible,
+};
+
+static const struct attribute_group *soc_dev_attr_groups[] = {
+       &soc_dapm_dev_group,
+       &soc_dev_roup,
+       NULL
+};
+
 #ifdef CONFIG_DEBUG_FS
 static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf,
                                   size_t count, loff_t *ppos)
@@ -949,8 +982,6 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order)
 
        /* unregister the rtd device */
        if (rtd->dev_registered) {
-               device_remove_file(rtd->dev, &dev_attr_pmdown_time);
-               device_remove_file(rtd->dev, &dev_attr_codec_reg);
                device_unregister(rtd->dev);
                rtd->dev_registered = 0;
        }
@@ -1120,6 +1151,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
        device_initialize(rtd->dev);
        rtd->dev->parent = rtd->card->dev;
        rtd->dev->release = rtd_release;
+       rtd->dev->groups = soc_dev_attr_groups;
        dev_set_name(rtd->dev, "%s", name);
        dev_set_drvdata(rtd->dev, rtd);
        mutex_init(&rtd->pcm_mutex);
@@ -1136,23 +1168,6 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd,
                return ret;
        }
        rtd->dev_registered = 1;
-
-       if (rtd->codec) {
-               /* add DAPM sysfs entries for this codec */
-               ret = snd_soc_dapm_sys_add(rtd->dev);
-               if (ret < 0)
-                       dev_err(rtd->dev,
-                               "ASoC: failed to add codec dapm sysfs entries: %d\n",
-                               ret);
-
-               /* add codec sysfs entries */
-               ret = device_create_file(rtd->dev, &dev_attr_codec_reg);
-               if (ret < 0)
-                       dev_err(rtd->dev,
-                               "ASoC: failed to add codec sysfs files: %d\n",
-                               ret);
-       }
-
        return 0;
 }
 
@@ -1308,11 +1323,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
        }
 #endif
 
-       ret = device_create_file(rtd->dev, &dev_attr_pmdown_time);
-       if (ret < 0)
-               dev_warn(rtd->dev, "ASoC: failed to add pmdown_time sysfs: %d\n",
-                       ret);
-
        if (cpu_dai->driver->compress_dai) {
                /*create compress_device"*/
                ret = soc_new_compress(rtd, num);
@@ -1427,11 +1437,76 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec)
        return 0;
 }
 
+/**
+ * snd_soc_runtime_set_dai_fmt() - Change DAI link format for a ASoC runtime
+ * @rtd: The runtime for which the DAI link format should be changed
+ * @dai_fmt: The new DAI link format
+ *
+ * This function updates the DAI link format for all DAIs connected to the DAI
+ * link for the specified runtime.
+ *
+ * Note: For setups with a static format set the dai_fmt field in the
+ * corresponding snd_dai_link struct instead of using this function.
+ *
+ * Returns 0 on success, otherwise a negative error code.
+ */
+int snd_soc_runtime_set_dai_fmt(struct snd_soc_pcm_runtime *rtd,
+       unsigned int dai_fmt)
+{
+       struct snd_soc_dai **codec_dais = rtd->codec_dais;
+       struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < rtd->num_codecs; i++) {
+               struct snd_soc_dai *codec_dai = codec_dais[i];
+
+               ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
+               if (ret != 0 && ret != -ENOTSUPP) {
+                       dev_warn(codec_dai->dev,
+                                "ASoC: Failed to set DAI format: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       /* Flip the polarity for the "CPU" end of a CODEC<->CODEC link */
+       if (cpu_dai->codec) {
+               unsigned int inv_dai_fmt;
+
+               inv_dai_fmt = dai_fmt & ~SND_SOC_DAIFMT_MASTER_MASK;
+               switch (dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+               case SND_SOC_DAIFMT_CBM_CFM:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
+                       break;
+               case SND_SOC_DAIFMT_CBM_CFS:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFM:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
+                       break;
+               case SND_SOC_DAIFMT_CBS_CFS:
+                       inv_dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
+                       break;
+               }
+
+               dai_fmt = inv_dai_fmt;
+       }
+
+       ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
+       if (ret != 0 && ret != -ENOTSUPP) {
+               dev_warn(cpu_dai->dev,
+                        "ASoC: Failed to set DAI format: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt);
+
 static int snd_soc_instantiate_card(struct snd_soc_card *card)
 {
        struct snd_soc_codec *codec;
-       struct snd_soc_dai_link *dai_link;
-       int ret, i, order, dai_fmt;
+       int ret, i, order;
 
        mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_INIT);
 
@@ -1542,60 +1617,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                                        card->num_dapm_routes);
 
        for (i = 0; i < card->num_links; i++) {
-               struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
-               dai_link = &card->dai_link[i];
-               dai_fmt = dai_link->dai_fmt;
-
-               if (dai_fmt) {
-                       struct snd_soc_dai **codec_dais = rtd->codec_dais;
-                       int j;
-
-                       for (j = 0; j < rtd->num_codecs; j++) {
-                               struct snd_soc_dai *codec_dai = codec_dais[j];
-
-                               ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
-                               if (ret != 0 && ret != -ENOTSUPP)
-                                       dev_warn(codec_dai->dev,
-                                                "ASoC: Failed to set DAI format: %d\n",
-                                                ret);
-                       }
-               }
-
-               /* If this is a regular CPU link there will be a platform */
-               if (dai_fmt &&
-                   (dai_link->platform_name || dai_link->platform_of_node)) {
-                       ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
-                                                 dai_fmt);
-                       if (ret != 0 && ret != -ENOTSUPP)
-                               dev_warn(card->rtd[i].cpu_dai->dev,
-                                        "ASoC: Failed to set DAI format: %d\n",
-                                        ret);
-               } else if (dai_fmt) {
-                       /* Flip the polarity for the "CPU" end */
-                       dai_fmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
-                       switch (dai_link->dai_fmt &
-                               SND_SOC_DAIFMT_MASTER_MASK) {
-                       case SND_SOC_DAIFMT_CBM_CFM:
-                               dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
-                               break;
-                       case SND_SOC_DAIFMT_CBM_CFS:
-                               dai_fmt |= SND_SOC_DAIFMT_CBS_CFM;
-                               break;
-                       case SND_SOC_DAIFMT_CBS_CFM:
-                               dai_fmt |= SND_SOC_DAIFMT_CBM_CFS;
-                               break;
-                       case SND_SOC_DAIFMT_CBS_CFS:
-                               dai_fmt |= SND_SOC_DAIFMT_CBM_CFM;
-                               break;
-                       }
-
-                       ret = snd_soc_dai_set_fmt(card->rtd[i].cpu_dai,
-                                                 dai_fmt);
-                       if (ret != 0 && ret != -ENOTSUPP)
-                               dev_warn(card->rtd[i].cpu_dai->dev,
-                                        "ASoC: Failed to set DAI format: %d\n",
-                                        ret);
-               }
+               if (card->dai_link[i].dai_fmt)
+                       snd_soc_runtime_set_dai_fmt(&card->rtd[i],
+                               card->dai_link[i].dai_fmt);
        }
 
        snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
@@ -1626,9 +1650,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
                }
        }
 
-       if (card->fully_routed)
-               snd_soc_dapm_auto_nc_pins(card);
-
        snd_soc_dapm_new_widgets(card);
 
        ret = snd_card_register(card->snd_card);
@@ -2119,15 +2140,27 @@ static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
 }
 
 /**
- * snd_soc_dai_set_tdm_slot - configure DAI TDM.
- * @dai: DAI
+ * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
+ * @dai: The DAI to configure
  * @tx_mask: bitmask representing active TX slots.
  * @rx_mask: bitmask representing active RX slots.
  * @slots: Number of slots in use.
  * @slot_width: Width in bits for each slot.
  *
- * Configures a DAI for TDM operation. Both mask and slots are codec and DAI
- * specific.
+ * This function configures the specified DAI for TDM operation. @slot contains
+ * the total number of slots of the TDM stream and @slot_with the width of each
+ * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
+ * active slots of the TDM stream for the specified DAI, i.e. which slots the
+ * DAI should write to or read from. If a bit is set the corresponding slot is
+ * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
+ * the first slot, bit 1 to the second slot and so on. The first active slot
+ * maps to the first channel of the DAI, the second active slot to the second
+ * channel and so on.
+ *
+ * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
+ * @rx_mask and @slot_width will be ignored.
+ *
+ * Returns 0 on success, a negative error code otherwise.
  */
 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
@@ -3230,7 +3263,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                                   const char *propname)
 {
        struct device_node *np = card->dev->of_node;
-       int num_routes, old_routes;
+       int num_routes;
        struct snd_soc_dapm_route *routes;
        int i, ret;
 
@@ -3248,9 +3281,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                return -EINVAL;
        }
 
-       old_routes = card->num_dapm_routes;
-       routes = devm_kzalloc(card->dev,
-                             (old_routes + num_routes) * sizeof(*routes),
+       routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes),
                              GFP_KERNEL);
        if (!routes) {
                dev_err(card->dev,
@@ -3258,11 +3289,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                return -EINVAL;
        }
 
-       memcpy(routes, card->dapm_routes, old_routes * sizeof(*routes));
-
        for (i = 0; i < num_routes; i++) {
                ret = of_property_read_string_index(np, propname,
-                       2 * i, &routes[old_routes + i].sink);
+                       2 * i, &routes[i].sink);
                if (ret) {
                        dev_err(card->dev,
                                "ASoC: Property '%s' index %d could not be read: %d\n",
@@ -3270,7 +3299,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                        return -EINVAL;
                }
                ret = of_property_read_string_index(np, propname,
-                       (2 * i) + 1, &routes[old_routes + i].source);
+                       (2 * i) + 1, &routes[i].source);
                if (ret) {
                        dev_err(card->dev,
                                "ASoC: Property '%s' index %d could not be read: %d\n",
@@ -3279,7 +3308,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
                }
        }
 
-       card->num_dapm_routes += num_routes;
+       card->num_dapm_routes = num_routes;
        card->dapm_routes = routes;
 
        return 0;
index c5136bb1f9821afe43bae8a2f9bece210e699952..b6f88202b8c99a41c3e941bb8a8a2603e45985a8 100644 (file)
@@ -517,8 +517,8 @@ static int soc_dapm_update_bits(struct snd_soc_dapm_context *dapm,
 {
        if (!dapm->component)
                return -EIO;
-       return snd_soc_component_update_bits_async(dapm->component, reg,
-               mask, value);
+       return snd_soc_component_update_bits(dapm->component, reg,
+                                            mask, value);
 }
 
 static int soc_dapm_test_bits(struct snd_soc_dapm_context *dapm,
@@ -2127,15 +2127,10 @@ static ssize_t dapm_widget_show(struct device *dev,
 
 static DEVICE_ATTR(dapm_widget, 0444, dapm_widget_show, NULL);
 
-int snd_soc_dapm_sys_add(struct device *dev)
-{
-       return device_create_file(dev, &dev_attr_dapm_widget);
-}
-
-static void snd_soc_dapm_sys_remove(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_dapm_widget);
-}
+struct attribute *soc_dapm_dev_attrs[] = {
+       &dev_attr_dapm_widget.attr,
+       NULL
+};
 
 static void dapm_free_path(struct snd_soc_dapm_path *path)
 {
@@ -2279,6 +2274,9 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
 
        switch (w->id) {
        case snd_soc_dapm_input:
+               /* On a fully routed card a input is never a source */
+               if (w->dapm->card->fully_routed)
+                       break;
                w->is_source = 1;
                list_for_each_entry(p, &w->sources, list_sink) {
                        if (p->source->id == snd_soc_dapm_micbias ||
@@ -2291,6 +2289,9 @@ static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
                }
                break;
        case snd_soc_dapm_output:
+               /* On a fully routed card a output is never a sink */
+               if (w->dapm->card->fully_routed)
+                       break;
                w->is_sink = 1;
                list_for_each_entry(p, &w->sinks, list_source) {
                        if (p->sink->id == snd_soc_dapm_spk ||
@@ -3085,16 +3086,24 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
 
        switch (w->id) {
        case snd_soc_dapm_mic:
-       case snd_soc_dapm_input:
                w->is_source = 1;
                w->power_check = dapm_generic_check_power;
                break;
+       case snd_soc_dapm_input:
+               if (!dapm->card->fully_routed)
+                       w->is_source = 1;
+               w->power_check = dapm_generic_check_power;
+               break;
        case snd_soc_dapm_spk:
        case snd_soc_dapm_hp:
-       case snd_soc_dapm_output:
                w->is_sink = 1;
                w->power_check = dapm_generic_check_power;
                break;
+       case snd_soc_dapm_output:
+               if (!dapm->card->fully_routed)
+                       w->is_sink = 1;
+               w->power_check = dapm_generic_check_power;
+               break;
        case snd_soc_dapm_vmid:
        case snd_soc_dapm_siggen:
                w->is_source = 1;
@@ -3130,8 +3139,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
        }
 
        w->dapm = dapm;
-       if (dapm->component)
-               w->codec = dapm->component->codec;
        INIT_LIST_HEAD(&w->sources);
        INIT_LIST_HEAD(&w->sinks);
        INIT_LIST_HEAD(&w->list);
@@ -3808,93 +3815,6 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
 }
 EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
 
-/**
- * dapm_is_external_path() - Checks if a path is a external path
- * @card: The card the path belongs to
- * @path: The path to check
- *
- * Returns true if the path is either between two different DAPM contexts or
- * between two external pins of the same DAPM context. Otherwise returns
- * false.
- */
-static bool dapm_is_external_path(struct snd_soc_card *card,
-       struct snd_soc_dapm_path *path)
-{
-       dev_dbg(card->dev,
-               "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
-               path->source->name, path->source->id, path->source->dapm,
-               path->sink->name, path->sink->id, path->sink->dapm);
-
-       /* Connection between two different DAPM contexts */
-       if (path->source->dapm != path->sink->dapm)
-               return true;
-
-       /* Loopback connection from external pin to external pin */
-       if (path->sink->id == snd_soc_dapm_input) {
-               switch (path->source->id) {
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_micbias:
-                       return true;
-               default:
-                       break;
-               }
-       }
-
-       return false;
-}
-
-static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
-                                             struct snd_soc_dapm_widget *w)
-{
-       struct snd_soc_dapm_path *p;
-
-       list_for_each_entry(p, &w->sources, list_sink) {
-               if (dapm_is_external_path(card, p))
-                       return true;
-       }
-
-       list_for_each_entry(p, &w->sinks, list_source) {
-               if (dapm_is_external_path(card, p))
-                       return true;
-       }
-
-       return false;
-}
-
-/**
- * snd_soc_dapm_auto_nc_pins - call snd_soc_dapm_nc_pin for unused pins
- * @card: The card whose pins should be processed
- *
- * Automatically call snd_soc_dapm_nc_pin() for any external pins in the card
- * which are unused. Pins are used if they are connected externally to a
- * component, whether that be to some other device, or a loop-back connection to
- * the component itself.
- */
-void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card)
-{
-       struct snd_soc_dapm_widget *w;
-
-       dev_dbg(card->dev, "ASoC: Auto NC: DAPMs: card:%p\n", &card->dapm);
-
-       list_for_each_entry(w, &card->widgets, list) {
-               switch (w->id) {
-               case snd_soc_dapm_input:
-               case snd_soc_dapm_output:
-               case snd_soc_dapm_micbias:
-                       dev_dbg(card->dev, "ASoC: Auto NC: Checking widget %s\n",
-                               w->name);
-                       if (!snd_soc_dapm_widget_in_card_paths(card, w)) {
-                               dev_dbg(card->dev,
-                                       "... Not in map; disabling\n");
-                               snd_soc_dapm_nc_pin(w->dapm, w->name);
-                       }
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
 /**
  * snd_soc_dapm_free - free dapm resources
  * @dapm: DAPM context
@@ -3903,7 +3823,6 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card)
  */
 void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm)
 {
-       snd_soc_dapm_sys_remove(dapm->dev);
        dapm_debugfs_cleanup(dapm);
        dapm_free_widgets(dapm);
        list_del(&dapm->list);
index 057e5ef7dcce6730bdc99bc8e5719ebe458669d0..a57921eeee81a772bd02da6acea391c3f74f7c7a 100644 (file)
@@ -60,7 +60,7 @@ static void devm_platform_release(struct device *dev, void *res)
 /**
  * devm_snd_soc_register_platform - resource managed platform registration
  * @dev: Device used to manage platform
- * @platform: platform to register
+ * @platform_drv: platform to register
  *
  * Register a platform driver with automatic unregistration when the device is
  * unregistered.
index b329b84bc5af77d50e1fd2803252d259cabf7602..4864392bfcba7c0189a37b04f495ec20c2022f9d 100644 (file)
@@ -200,11 +200,6 @@ static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
        return snd_dmaengine_pcm_open(substream, chan);
 }
 
-static void dmaengine_pcm_free(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static struct dma_chan *dmaengine_pcm_compat_request_channel(
        struct snd_soc_pcm_runtime *rtd,
        struct snd_pcm_substream *substream)
@@ -283,8 +278,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
                if (!pcm->chan[i]) {
                        dev_err(rtd->platform->dev,
                                "Missing dma channel for stream: %d\n", i);
-                       ret = -EINVAL;
-                       goto err_free;
+                       return -EINVAL;
                }
 
                ret = snd_pcm_lib_preallocate_pages(substream,
@@ -293,7 +287,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
                                prealloc_buffer_size,
                                max_buffer_size);
                if (ret)
-                       goto err_free;
+                       return ret;
 
                /*
                 * This will only return false if we know for sure that at least
@@ -307,10 +301,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
        }
 
        return 0;
-
-err_free:
-       dmaengine_pcm_free(rtd->pcm);
-       return ret;
 }
 
 static snd_pcm_uframes_t dmaengine_pcm_pointer(
@@ -341,7 +331,6 @@ static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
        },
        .ops            = &dmaengine_pcm_ops,
        .pcm_new        = dmaengine_pcm_new,
-       .pcm_free       = dmaengine_pcm_free,
 };
 
 static const char * const dmaengine_pcm_dma_channel_names[] = {
index eb87d96e2cf0a8807e34a9859918a5c672d17981..0ae0e2a9eed714d169635e3a4b6dbbe1451c9d18 100644 (file)
@@ -746,7 +746,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
                                                              codec_dai);
                        if (ret < 0) {
                                dev_err(codec_dai->dev,
-                                       "ASoC: DAI prepare error: %d\n", ret);
+                                       "ASoC: codec DAI prepare error: %d\n",
+                                       ret);
                                goto out;
                        }
                }
@@ -755,8 +756,8 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
        if (cpu_dai->driver->ops && cpu_dai->driver->ops->prepare) {
                ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
                if (ret < 0) {
-                       dev_err(cpu_dai->dev, "ASoC: DAI prepare error: %d\n",
-                               ret);
+                       dev_err(cpu_dai->dev,
+                               "ASoC: cpu DAI prepare error: %d\n", ret);
                        goto out;
                }
        }
index 31198cf7f88d93829c2ccb7c7c5118583250f0b0..a6768f832c6fe87e4679e0df7f47e51e81e3b8a4 100644 (file)
@@ -128,3 +128,13 @@ config SND_SOC_TEGRA_MAX98090
        help
          Say Y or M here if you want to add support for SoC audio on Tegra
          boards using the MAX98090 codec, such as Venice2.
+
+config SND_SOC_TEGRA_RT5677
+       tristate "SoC Audio support for Tegra boards using a RT5677 codec"
+       depends on SND_SOC_TEGRA && I2C && GPIOLIB
+       select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC
+       select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC
+       select SND_SOC_RT5677
+       help
+         Say Y or M here if you want to add support for SoC audio on Tegra
+         boards using the RT5677 codec, such as Ryu.
index 5ae588cd96c4c39ff8060f98a6f1248f9e4855d9..9171655ad843213c1eea2028cf8fccd74d73887e 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_SND_SOC_TEGRA30_I2S) += snd-soc-tegra30-i2s.o
 
 # Tegra machine Support
 snd-soc-tegra-rt5640-objs := tegra_rt5640.o
+snd-soc-tegra-rt5677-objs := tegra_rt5677.o
 snd-soc-tegra-wm8753-objs := tegra_wm8753.o
 snd-soc-tegra-wm8903-objs := tegra_wm8903.o
 snd-soc-tegra-wm9712-objs := tegra_wm9712.o
@@ -27,6 +28,7 @@ snd-soc-tegra-alc5632-objs := tegra_alc5632.o
 snd-soc-tegra-max98090-objs := tegra_max98090.o
 
 obj-$(CONFIG_SND_SOC_TEGRA_RT5640) += snd-soc-tegra-rt5640.o
+obj-$(CONFIG_SND_SOC_TEGRA_RT5677) += snd-soc-tegra-rt5677.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8753) += snd-soc-tegra-wm8753.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM8903) += snd-soc-tegra-wm8903.o
 obj-$(CONFIG_SND_SOC_TEGRA_WM9712) += snd-soc-tegra-wm9712.o
diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c
new file mode 100644 (file)
index 0000000..e4cf978
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+* tegra_rt5677.c - Tegra machine ASoC driver for boards using RT5677 codec.
+ *
+ * Copyright (c) 2014, The Chromium OS Authors.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code copyright/by:
+ *
+ * Copyright (C) 2010-2012 - NVIDIA, Inc.
+ * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
+ * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd.
+ * Copyright 2007 Wolfson Microelectronics PLC.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/rt5677.h"
+
+#include "tegra_asoc_utils.h"
+
+#define DRV_NAME "tegra-snd-rt5677"
+
+struct tegra_rt5677 {
+       struct tegra_asoc_utils_data util_data;
+       int gpio_hp_det;
+       int gpio_hp_en;
+       int gpio_mic_present;
+       int gpio_dmic_clk_en;
+};
+
+static int tegra_rt5677_asoc_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_card *card = rtd->card;
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+       int srate, mclk, err;
+
+       srate = params_rate(params);
+       mclk = 256 * srate;
+
+       err = tegra_asoc_utils_set_rate(&machine->util_data, srate, mclk);
+       if (err < 0) {
+               dev_err(card->dev, "Can't configure clocks\n");
+               return err;
+       }
+
+       err = snd_soc_dai_set_sysclk(codec_dai, RT5677_SCLK_S_MCLK, mclk,
+                                       SND_SOC_CLOCK_IN);
+       if (err < 0) {
+               dev_err(card->dev, "codec_dai clock not set\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w,
+                       struct snd_kcontrol *k, int event)
+{
+       struct snd_soc_dapm_context *dapm = w->dapm;
+       struct snd_soc_card *card = dapm->card;
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+       if (!gpio_is_valid(machine->gpio_hp_en))
+               return 0;
+
+       gpio_set_value_cansleep(machine->gpio_hp_en,
+               SND_SOC_DAPM_EVENT_ON(event));
+
+       return 0;
+}
+
+static struct snd_soc_ops tegra_rt5677_ops = {
+       .hw_params = tegra_rt5677_asoc_hw_params,
+};
+
+static struct snd_soc_jack tegra_rt5677_hp_jack;
+
+static struct snd_soc_jack_pin tegra_rt5677_hp_jack_pins = {
+       .pin = "Headphone",
+       .mask = SND_JACK_HEADPHONE,
+};
+static struct snd_soc_jack_gpio tegra_rt5677_hp_jack_gpio = {
+       .name = "Headphone detection",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+};
+
+static struct snd_soc_jack tegra_rt5677_mic_jack;
+
+static struct snd_soc_jack_pin tegra_rt5677_mic_jack_pins = {
+       .pin = "Headset Mic",
+       .mask = SND_JACK_MICROPHONE,
+};
+
+static struct snd_soc_jack_gpio tegra_rt5677_mic_jack_gpio = {
+       .name = "Headset Mic detection",
+       .report = SND_JACK_MICROPHONE,
+       .debounce_time = 150,
+       .invert = 1
+};
+
+static const struct snd_soc_dapm_widget tegra_rt5677_dapm_widgets[] = {
+       SND_SOC_DAPM_SPK("Speaker", NULL),
+       SND_SOC_DAPM_HP("Headphone", tegra_rt5677_event_hp),
+       SND_SOC_DAPM_MIC("Headset Mic", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic 1", NULL),
+       SND_SOC_DAPM_MIC("Internal Mic 2", NULL),
+};
+
+static const struct snd_kcontrol_new tegra_rt5677_controls[] = {
+       SOC_DAPM_PIN_SWITCH("Speaker"),
+       SOC_DAPM_PIN_SWITCH("Headphone"),
+       SOC_DAPM_PIN_SWITCH("Headset Mic"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic 1"),
+       SOC_DAPM_PIN_SWITCH("Internal Mic 2"),
+};
+
+static int tegra_rt5677_asoc_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_dai *codec_dai = rtd->codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       struct snd_soc_dapm_context *dapm = &codec->dapm;
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(rtd->card);
+
+       snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE,
+                       &tegra_rt5677_hp_jack);
+       snd_soc_jack_add_pins(&tegra_rt5677_hp_jack, 1,
+                       &tegra_rt5677_hp_jack_pins);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               tegra_rt5677_hp_jack_gpio.gpio = machine->gpio_hp_det;
+               snd_soc_jack_add_gpios(&tegra_rt5677_hp_jack, 1,
+                               &tegra_rt5677_hp_jack_gpio);
+       }
+
+
+       snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE,
+                       &tegra_rt5677_mic_jack);
+       snd_soc_jack_add_pins(&tegra_rt5677_mic_jack, 1,
+                       &tegra_rt5677_mic_jack_pins);
+
+       if (gpio_is_valid(machine->gpio_mic_present)) {
+               tegra_rt5677_mic_jack_gpio.gpio = machine->gpio_mic_present;
+               snd_soc_jack_add_gpios(&tegra_rt5677_mic_jack, 1,
+                               &tegra_rt5677_mic_jack_gpio);
+       }
+
+       snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1");
+
+       return 0;
+}
+
+static int tegra_rt5677_card_remove(struct snd_soc_card *card)
+{
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+       if (gpio_is_valid(machine->gpio_hp_det)) {
+               snd_soc_jack_free_gpios(&tegra_rt5677_hp_jack, 1,
+                               &tegra_rt5677_hp_jack_gpio);
+       }
+
+       if (gpio_is_valid(machine->gpio_mic_present)) {
+               snd_soc_jack_free_gpios(&tegra_rt5677_mic_jack, 1,
+                               &tegra_rt5677_mic_jack_gpio);
+       }
+
+       return 0;
+}
+
+static struct snd_soc_dai_link tegra_rt5677_dai = {
+       .name = "RT5677",
+       .stream_name = "RT5677 PCM",
+       .codec_dai_name = "rt5677-aif1",
+       .init = tegra_rt5677_asoc_init,
+       .ops = &tegra_rt5677_ops,
+       .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+                       SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card snd_soc_tegra_rt5677 = {
+       .name = "tegra-rt5677",
+       .owner = THIS_MODULE,
+       .remove = tegra_rt5677_card_remove,
+       .dai_link = &tegra_rt5677_dai,
+       .num_links = 1,
+       .controls = tegra_rt5677_controls,
+       .num_controls = ARRAY_SIZE(tegra_rt5677_controls),
+       .dapm_widgets = tegra_rt5677_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(tegra_rt5677_dapm_widgets),
+       .fully_routed = true,
+};
+
+static int tegra_rt5677_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct snd_soc_card *card = &snd_soc_tegra_rt5677;
+       struct tegra_rt5677 *machine;
+       int ret;
+
+       machine = devm_kzalloc(&pdev->dev,
+                       sizeof(struct tegra_rt5677), GFP_KERNEL);
+       if (!machine)
+               return -ENOMEM;
+
+       card->dev = &pdev->dev;
+       platform_set_drvdata(pdev, card);
+       snd_soc_card_set_drvdata(card, machine);
+
+       machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+       if (machine->gpio_hp_det == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       machine->gpio_mic_present = of_get_named_gpio(np,
+                       "nvidia,mic-present-gpios", 0);
+       if (machine->gpio_mic_present == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
+       machine->gpio_hp_en = of_get_named_gpio(np, "nvidia,hp-en-gpios", 0);
+       if (machine->gpio_hp_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_hp_en)) {
+               ret = devm_gpio_request_one(&pdev->dev, machine->gpio_hp_en,
+                               GPIOF_OUT_INIT_LOW, "hp_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get hp_en gpio\n");
+                       return ret;
+               }
+       }
+
+       machine->gpio_dmic_clk_en = of_get_named_gpio(np,
+               "nvidia,dmic-clk-en-gpios", 0);
+       if (machine->gpio_dmic_clk_en == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(machine->gpio_dmic_clk_en)) {
+               ret = devm_gpio_request_one(&pdev->dev,
+                               machine->gpio_dmic_clk_en,
+                               GPIOF_OUT_INIT_HIGH, "dmic_clk_en");
+               if (ret) {
+                       dev_err(card->dev, "cannot get dmic_clk_en gpio\n");
+                       return ret;
+               }
+       }
+
+       ret = snd_soc_of_parse_card_name(card, "nvidia,model");
+       if (ret)
+               goto err;
+
+       ret = snd_soc_of_parse_audio_routing(card, "nvidia,audio-routing");
+       if (ret)
+               goto err;
+
+       tegra_rt5677_dai.codec_of_node = of_parse_phandle(np,
+                       "nvidia,audio-codec", 0);
+       if (!tegra_rt5677_dai.codec_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,audio-codec' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       tegra_rt5677_dai.cpu_of_node = of_parse_phandle(np,
+                       "nvidia,i2s-controller", 0);
+       if (!tegra_rt5677_dai.cpu_of_node) {
+               dev_err(&pdev->dev,
+                       "Property 'nvidia,i2s-controller' missing or invalid\n");
+               ret = -EINVAL;
+               goto err;
+       }
+       tegra_rt5677_dai.platform_of_node = tegra_rt5677_dai.cpu_of_node;
+
+       ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev);
+       if (ret)
+               goto err;
+
+       ret = snd_soc_register_card(card);
+       if (ret) {
+               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n",
+                       ret);
+               goto err_fini_utils;
+       }
+
+       return 0;
+
+err_fini_utils:
+       tegra_asoc_utils_fini(&machine->util_data);
+err:
+       return ret;
+}
+
+static int tegra_rt5677_remove(struct platform_device *pdev)
+{
+       struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct tegra_rt5677 *machine = snd_soc_card_get_drvdata(card);
+
+       snd_soc_unregister_card(card);
+
+       tegra_asoc_utils_fini(&machine->util_data);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_rt5677_of_match[] = {
+       { .compatible = "nvidia,tegra-audio-rt5677", },
+       {},
+};
+
+static struct platform_driver tegra_rt5677_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+               .of_match_table = tegra_rt5677_of_match,
+       },
+       .probe = tegra_rt5677_probe,
+       .remove = tegra_rt5677_remove,
+};
+module_platform_driver(tegra_rt5677_driver);
+
+MODULE_AUTHOR("Anatol Pomozov <anatol@google.com>");
+MODULE_DESCRIPTION("Tegra+RT5677 machine ASoC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, tegra_rt5677_of_match);
index 070e44e251ceef9ea128edf8c39ab08c780b2ed3..88eacfd83da6780b3d2419ab2173fa3d7e255916 100644 (file)
@@ -282,11 +282,6 @@ static struct snd_pcm_ops txx9aclc_pcm_ops = {
        .pointer        = txx9aclc_pcm_pointer,
 };
 
-static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm)
-{
-       snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
 static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
        struct snd_card *card = rtd->card->snd_card;
@@ -412,7 +407,6 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = {
        .remove         = txx9aclc_pcm_remove,
        .ops            = &txx9aclc_pcm_ops,
        .pcm_new        = txx9aclc_pcm_new,
-       .pcm_free       = txx9aclc_pcm_free_dma_buffers,
 };
 
 static int txx9aclc_soc_platform_probe(struct platform_device *pdev)
index be4f1ac7cd5ec74afe25f4b1126751790183afef..aa65370db82aa52fb480871eb06bd5dfed667d3b 100644 (file)
@@ -290,21 +290,9 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream,
                        SND_SOC_DAIFMT_GATED;
        }
 
-       ret = snd_soc_dai_set_fmt(codec_dai, fmt);
-       if (ret < 0) {
-               dev_err(dev,
-                       "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
-                       __func__, ret);
-               return ret;
-       }
-
-       ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
-       if (ret < 0) {
-               dev_err(dev,
-                       "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n",
-                       __func__, ret);
+       ret = snd_soc_runtime_set_dai_fmt(rtd, fmt);
+       if (ret)
                return ret;
-       }
 
        /* Setup TDM-slots */
 
index 272844746135763faa6425aae3fb8dc3bfc9ec50..327f8642ca80e66de2d0c880034cbd530f046dd1 100644 (file)
@@ -816,7 +816,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev)
                return -EINVAL;
        }
 
-       if (cdev->n_streams < 2) {
+       if (cdev->n_streams < 1) {
                dev_err(dev, "bogus number of streams: %d\n", cdev->n_streams);
                return -EINVAL;
        }
index 41650d5b93b70e5a9a36abbb7ffae4579075d8ab..3e2ef61c627b831bfec65724cc7166db051f5099 100644 (file)
@@ -913,6 +913,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval,
        case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */
        case USB_ID(0x046d, 0x0808):
        case USB_ID(0x046d, 0x0809):
+       case USB_ID(0x046d, 0x0819): /* Logitech Webcam C210 */
        case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */
        case USB_ID(0x046d, 0x081d): /* HD Webcam c510 */
        case USB_ID(0x046d, 0x0825): /* HD Webcam c270 */
index 6eedba1f773227d5df93bae06d7f3a0fcc1bd648..653d1bad77de2331ba18771f99a01dddcee0175c 100644 (file)
@@ -22,6 +22,8 @@
 #error only <linux/bitops.h> can be included directly
 #endif
 
+#include <asm-generic/bitops/hweight.h>
+
 #include <asm-generic/bitops/atomic.h>
 
 #endif /* __TOOLS_ASM_GENERIC_BITOPS_H */
diff --git a/tools/include/asm-generic/bitops/arch_hweight.h b/tools/include/asm-generic/bitops/arch_hweight.h
new file mode 100644 (file)
index 0000000..318bb2b
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/asm-generic/bitops/arch_hweight.h"
diff --git a/tools/include/asm-generic/bitops/const_hweight.h b/tools/include/asm-generic/bitops/const_hweight.h
new file mode 100644 (file)
index 0000000..0afd644
--- /dev/null
@@ -0,0 +1 @@
+#include "../../../../include/asm-generic/bitops/const_hweight.h"
diff --git a/tools/include/asm-generic/bitops/hweight.h b/tools/include/asm-generic/bitops/hweight.h
new file mode 100644 (file)
index 0000000..290120c
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_
+#define _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_
+
+#include <asm-generic/bitops/arch_hweight.h>
+#include <asm-generic/bitops/const_hweight.h>
+
+#endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ */
index 26005a15e7e29d34332b88e68a49fe223953913b..5ad9ee1dd7f6aed579a5e631e309438a80bb472f 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef _TOOLS_LINUX_BITOPS_H_
 #define _TOOLS_LINUX_BITOPS_H_
 
+#include <asm/types.h>
 #include <linux/kernel.h>
 #include <linux/compiler.h>
-#include <asm/hweight.h>
 
 #ifndef __WORDSIZE
 #define __WORDSIZE (__SIZEOF_LONG__ * 8)
 #define BITS_TO_U32(nr)                DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
 #define BITS_TO_BYTES(nr)      DIV_ROUND_UP(nr, BITS_PER_BYTE)
 
+extern unsigned int __sw_hweight8(unsigned int w);
+extern unsigned int __sw_hweight16(unsigned int w);
+extern unsigned int __sw_hweight32(unsigned int w);
+extern unsigned long __sw_hweight64(__u64 w);
+
 /*
  * Include this here because some architectures need generic_ffs/fls in
  * scope
index a74fba6d774353d33fac7f04b71abdd241e0218e..86ea2d7b88451c219dacad848e60564fb1a64ecf 100644 (file)
@@ -67,7 +67,7 @@ int debugfs_valid_mountpoint(const char *debugfs)
 
        if (statfs(debugfs, &st_fs) < 0)
                return -ENOENT;
-       else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
+       else if ((long)st_fs.f_type != (long)DEBUGFS_MAGIC)
                return -ENOENT;
 
        return 0;
index 65d9be3f988747ae300db30d3b62cf0e8213dd69..128ef6332a6bd89c0ddbeef283c4dfccbf5f8417 100644 (file)
@@ -79,7 +79,7 @@ static int fs__valid_mount(const char *fs, long magic)
 
        if (statfs(fs, &st_fs) < 0)
                return -ENOENT;
-       else if (st_fs.f_type != magic)
+       else if ((long)st_fs.f_type != magic)
                return -ENOENT;
 
        return 0;
index 6f803609e498246d277d35829b18c7924a136eca..0b0112c80f22b390875799909ab567b42c66009e 100644 (file)
@@ -317,7 +317,7 @@ int pthread_mutex_destroy(pthread_mutex_t *mutex)
         *
         * TODO: Hook into free() and add that check there as well.
         */
-       debug_check_no_locks_freed(mutex, mutex + sizeof(*mutex));
+       debug_check_no_locks_freed(mutex, sizeof(*mutex));
        __del_lock(__get_lock(mutex));
        return ll_pthread_mutex_destroy(mutex);
 }
@@ -341,7 +341,7 @@ int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
 {
        try_init_preload();
 
-       debug_check_no_locks_freed(rwlock, rwlock + sizeof(*rwlock));
+       debug_check_no_locks_freed(rwlock, sizeof(*rwlock));
        __del_lock(__get_lock(rwlock));
        return ll_pthread_rwlock_destroy(rwlock);
 }
index 83e2887f91a39200612290bd0b2b2fbd824e660a..fbbfdc39271dac69bd96aa932d6e62318dbce143 100644 (file)
@@ -6,12 +6,15 @@ tools/lib/symbol/kallsyms.c
 tools/lib/symbol/kallsyms.h
 tools/lib/util/find_next_bit.c
 tools/include/asm/bug.h
+tools/include/asm-generic/bitops/arch_hweight.h
 tools/include/asm-generic/bitops/atomic.h
+tools/include/asm-generic/bitops/const_hweight.h
 tools/include/asm-generic/bitops/__ffs.h
 tools/include/asm-generic/bitops/__fls.h
 tools/include/asm-generic/bitops/find.h
 tools/include/asm-generic/bitops/fls64.h
 tools/include/asm-generic/bitops/fls.h
+tools/include/asm-generic/bitops/hweight.h
 tools/include/asm-generic/bitops.h
 tools/include/linux/bitops.h
 tools/include/linux/compiler.h
@@ -19,6 +22,8 @@ tools/include/linux/export.h
 tools/include/linux/hash.h
 tools/include/linux/log2.h
 tools/include/linux/types.h
+include/asm-generic/bitops/arch_hweight.h
+include/asm-generic/bitops/const_hweight.h
 include/asm-generic/bitops/fls64.h
 include/asm-generic/bitops/__fls.h
 include/asm-generic/bitops/fls.h
@@ -29,6 +34,7 @@ include/linux/list.h
 include/linux/hash.h
 include/linux/stringify.h
 lib/find_next_bit.c
+lib/hweight.c
 lib/rbtree.c
 include/linux/swab.h
 arch/*/include/asm/unistd*.h
index 67a03a825b3c94bb894f0f557dac3bb520943e65..aa6a50447c32b63fd3f55a5ada5059610d610ec1 100644 (file)
@@ -232,12 +232,15 @@ LIB_H += ../include/linux/hash.h
 LIB_H += ../../include/linux/stringify.h
 LIB_H += util/include/linux/bitmap.h
 LIB_H += ../include/linux/bitops.h
+LIB_H += ../include/asm-generic/bitops/arch_hweight.h
 LIB_H += ../include/asm-generic/bitops/atomic.h
+LIB_H += ../include/asm-generic/bitops/const_hweight.h
 LIB_H += ../include/asm-generic/bitops/find.h
 LIB_H += ../include/asm-generic/bitops/fls64.h
 LIB_H += ../include/asm-generic/bitops/fls.h
 LIB_H += ../include/asm-generic/bitops/__ffs.h
 LIB_H += ../include/asm-generic/bitops/__fls.h
+LIB_H += ../include/asm-generic/bitops/hweight.h
 LIB_H += ../include/asm-generic/bitops.h
 LIB_H += ../include/linux/compiler.h
 LIB_H += ../include/linux/log2.h
@@ -255,7 +258,6 @@ LIB_H += util/include/linux/linkage.h
 LIB_H += util/include/asm/asm-offsets.h
 LIB_H += ../include/asm/bug.h
 LIB_H += util/include/asm/byteorder.h
-LIB_H += util/include/asm/hweight.h
 LIB_H += util/include/asm/swab.h
 LIB_H += util/include/asm/system.h
 LIB_H += util/include/asm/uaccess.h
@@ -462,10 +464,12 @@ BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
 # Benchmark modules
 BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
 BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
-ifeq ($(RAW_ARCH),x86_64)
+ifeq ($(ARCH), x86)
+ifeq ($(IS_64_BIT), 1)
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
 endif
+endif
 BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
 BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o
 BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o
@@ -743,6 +747,9 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
+$(OUTPUT)util/hweight.o: ../../lib/hweight.c $(OUTPUT)PERF-CFLAGS
+       $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
+
 $(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(CFLAGS) -Wno-unused-parameter -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
index 3bb50eac5542fc62c4482c92f4478806e731a9f7..0c370f81e00280c6428ddfe0975584edcb9d02a7 100644 (file)
@@ -103,7 +103,7 @@ static Dwarf_Frame *get_eh_frame(Dwfl_Module *mod, Dwarf_Addr pc)
                return NULL;
        }
 
-       result = dwarf_cfi_addrframe(cfi, pc, &frame);
+       result = dwarf_cfi_addrframe(cfi, pc-bias, &frame);
        if (result) {
                pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
                return NULL;
@@ -128,7 +128,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
                return NULL;
        }
 
-       result = dwarf_cfi_addrframe(cfi, pc, &frame);
+       result = dwarf_cfi_addrframe(cfi, pc-bias, &frame);
        if (result) {
                pr_debug("%s(): %s\n", __func__, dwfl_errmsg(-1));
                return NULL;
@@ -145,7 +145,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
  *             yet used)
  *     -1 in case of errors
  */
-static int check_return_addr(struct dso *dso, Dwarf_Addr pc)
+static int check_return_addr(struct dso *dso, u64 map_start, Dwarf_Addr pc)
 {
        int             rc = -1;
        Dwfl            *dwfl;
@@ -155,6 +155,7 @@ static int check_return_addr(struct dso *dso, Dwarf_Addr pc)
        Dwarf_Addr      start = pc;
        Dwarf_Addr      end = pc;
        bool            signalp;
+       const char      *exec_file = dso->long_name;
 
        dwfl = dso->dwfl;
 
@@ -165,8 +166,10 @@ static int check_return_addr(struct dso *dso, Dwarf_Addr pc)
                        return -1;
                }
 
-               if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) {
-                       pr_debug("dwfl_report_offline() failed %s\n",
+               mod = dwfl_report_elf(dwfl, exec_file, exec_file, -1,
+                                               map_start, false);
+               if (!mod) {
+                       pr_debug("dwfl_report_elf() failed %s\n",
                                                dwarf_errmsg(-1));
                        /*
                         * We normally cache the DWARF debug info and never
@@ -256,10 +259,10 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
                return skip_slot;
        }
 
-       rc = check_return_addr(dso, ip);
+       rc = check_return_addr(dso, al.map->start, ip);
 
-       pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n",
-                               dso->long_name, chain->nr, ip, rc);
+       pr_debug("[DSO %s, sym %s, ip 0x%" PRIx64 "] rc %d\n",
+                               dso->long_name, al.sym->name, ip, rc);
 
        if (rc == 0) {
                /*
index 07a8d7646a1549c61699f7311285238ef5ef93cf..005cc283790cfb7cf4db014362cb5d56f2a89ca2 100644 (file)
 #include <stdlib.h>
 #include <signal.h>
 #include <sys/wait.h>
-#include <linux/unistd.h>
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/syscall.h>
 
 #include <pthread.h>
 
index e7417fe97a9775eae8712d5bb58be2db0d1d7363..747f86103599826b6555563d25c8be25ae8f3d36 100644 (file)
@@ -232,7 +232,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
                if (nr_samples > 0) {
                        total_nr_samples += nr_samples;
                        hists__collapse_resort(hists, NULL);
-                       hists__output_resort(hists);
+                       hists__output_resort(hists, NULL);
 
                        if (symbol_conf.event_group &&
                            !perf_evsel__is_group_leader(pos))
index 1ce425d101a99691121b62a2a0c879c4f362fdf5..1fd96c13f1998a4048cbc5ab3eef1df35a5f80b8 100644 (file)
@@ -545,6 +545,42 @@ hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
        return __hist_entry__cmp_compute(p_left, p_right, c);
 }
 
+static int64_t
+hist_entry__cmp_nop(struct hist_entry *left __maybe_unused,
+                   struct hist_entry *right __maybe_unused)
+{
+       return 0;
+}
+
+static int64_t
+hist_entry__cmp_baseline(struct hist_entry *left, struct hist_entry *right)
+{
+       if (sort_compute)
+               return 0;
+
+       if (left->stat.period == right->stat.period)
+               return 0;
+       return left->stat.period > right->stat.period ? 1 : -1;
+}
+
+static int64_t
+hist_entry__cmp_delta(struct hist_entry *left, struct hist_entry *right)
+{
+       return hist_entry__cmp_compute(right, left, COMPUTE_DELTA);
+}
+
+static int64_t
+hist_entry__cmp_ratio(struct hist_entry *left, struct hist_entry *right)
+{
+       return hist_entry__cmp_compute(right, left, COMPUTE_RATIO);
+}
+
+static int64_t
+hist_entry__cmp_wdiff(struct hist_entry *left, struct hist_entry *right)
+{
+       return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF);
+}
+
 static void insert_hist_entry_by_compute(struct rb_root *root,
                                         struct hist_entry *he,
                                         int c)
@@ -605,7 +641,7 @@ static void hists__process(struct hists *hists)
                hists__precompute(hists);
                hists__compute_resort(hists);
        } else {
-               hists__output_resort(hists);
+               hists__output_resort(hists, NULL);
        }
 
        hists__fprintf(hists, true, 0, 0, 0, stdout);
@@ -1038,27 +1074,35 @@ static void data__hpp_register(struct data__file *d, int idx)
        fmt->header = hpp__header;
        fmt->width  = hpp__width;
        fmt->entry  = hpp__entry_global;
+       fmt->cmp    = hist_entry__cmp_nop;
+       fmt->collapse = hist_entry__cmp_nop;
 
        /* TODO more colors */
        switch (idx) {
        case PERF_HPP_DIFF__BASELINE:
                fmt->color = hpp__color_baseline;
+               fmt->sort  = hist_entry__cmp_baseline;
                break;
        case PERF_HPP_DIFF__DELTA:
                fmt->color = hpp__color_delta;
+               fmt->sort  = hist_entry__cmp_delta;
                break;
        case PERF_HPP_DIFF__RATIO:
                fmt->color = hpp__color_ratio;
+               fmt->sort  = hist_entry__cmp_ratio;
                break;
        case PERF_HPP_DIFF__WEIGHTED_DIFF:
                fmt->color = hpp__color_wdiff;
+               fmt->sort  = hist_entry__cmp_wdiff;
                break;
        default:
+               fmt->sort  = hist_entry__cmp_nop;
                break;
        }
 
        init_header(d, dfmt);
        perf_hpp__column_register(fmt);
+       perf_hpp__register_sort_field(fmt);
 }
 
 static void ui_init(void)
index 011195e38f2173947550100e62927e908b429d30..198f3c3aff952358766626f5bfea9ce81a996b28 100644 (file)
@@ -19,7 +19,9 @@
 int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        int i;
-       const struct option list_options[] = {
+       bool raw_dump = false;
+       struct option list_options[] = {
+               OPT_BOOLEAN(0, "raw-dump", &raw_dump, "Dump raw events"),
                OPT_END()
        };
        const char * const list_usage[] = {
@@ -27,11 +29,18 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
                NULL
        };
 
+       set_option_flag(list_options, 0, "raw-dump", PARSE_OPT_HIDDEN);
+
        argc = parse_options(argc, argv, list_options, list_usage,
                             PARSE_OPT_STOP_AT_NON_OPTION);
 
        setup_pager();
 
+       if (raw_dump) {
+               print_events(NULL, true);
+               return 0;
+       }
+
        if (argc == 0) {
                print_events(NULL, false);
                return 0;
@@ -53,8 +62,6 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
                        print_hwcache_events(NULL, false);
                else if (strcmp(argv[i], "pmu") == 0)
                        print_pmu_events(NULL, false);
-               else if (strcmp(argv[i], "--raw-dump") == 0)
-                       print_events(NULL, true);
                else {
                        char *sep = strchr(argv[i], ':'), *s;
                        int sep_idx;
index 39367609c707bc0332d4fdbd4a05cf49f4cb78d5..072ae8ad67fc1d258354b621a3ae7b2833deba0c 100644 (file)
@@ -457,6 +457,19 @@ static void report__collapse_hists(struct report *rep)
        ui_progress__finish();
 }
 
+static void report__output_resort(struct report *rep)
+{
+       struct ui_progress prog;
+       struct perf_evsel *pos;
+
+       ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
+
+       evlist__for_each(rep->session->evlist, pos)
+               hists__output_resort(evsel__hists(pos), &prog);
+
+       ui_progress__finish();
+}
+
 static int __cmd_report(struct report *rep)
 {
        int ret;
@@ -505,13 +518,20 @@ static int __cmd_report(struct report *rep)
        if (session_done())
                return 0;
 
+       /*
+        * recalculate number of entries after collapsing since it
+        * might be changed during the collapse phase.
+        */
+       rep->nr_entries = 0;
+       evlist__for_each(session->evlist, pos)
+               rep->nr_entries += evsel__hists(pos)->nr_entries;
+
        if (rep->nr_entries == 0) {
                ui__error("The %s file has no samples!\n", file->path);
                return 0;
        }
 
-       evlist__for_each(session->evlist, pos)
-               hists__output_resort(evsel__hists(pos));
+       report__output_resort(rep);
 
        return report__browse_hists(rep);
 }
index 0aa7747ff1390e0995a875a6c185697901cb9632..616f0fcb47010abf68ac7e4a9e256fa559af4499 100644 (file)
@@ -66,7 +66,6 @@
 #include <sys/utsname.h>
 #include <sys/mman.h>
 
-#include <linux/unistd.h>
 #include <linux/types.h>
 
 static volatile int done;
@@ -285,7 +284,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
        }
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        hists__output_recalc_col_len(hists, top->print_entries - printed);
        putchar('\n');
@@ -554,7 +553,7 @@ static void perf_top__sort_new_samples(void *arg)
        }
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 }
 
 static void *display_thread_tui(void *arg)
index 5d4b039fe1edc6ebf6f6dafec597e125383d0c4f..648e31ff4021c2e11520ab8b00e6f89213d324a9 100644 (file)
@@ -20,7 +20,7 @@ NO_PERF_REGS := 1
 
 # Additional ARCH settings for x86
 ifeq ($(ARCH),x86)
-  ifeq (${IS_X86_64}, 1)
+  ifeq (${IS_64_BIT}, 1)
     CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
     ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
     LIBUNWIND_LIBS = -lunwind -lunwind-x86_64
index 851cd0172a7694a0e21fd18d07c79031d5f9b253..ff95a68741d1ccdb54e54d929f2292e88963a5d1 100644 (file)
@@ -1,7 +1,7 @@
 
 uname_M := $(shell uname -m 2>/dev/null || echo not)
 
-ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+RAW_ARCH := $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                   -e s/arm.*/arm/ -e s/sa110/arm/ \
                                   -e s/s390x/s390/ -e s/parisc64/parisc/ \
                                   -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \
@@ -9,23 +9,23 @@ ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
                                   -e s/tile.*/tile/ )
 
 # Additional ARCH settings for x86
-ifeq ($(ARCH),i386)
-  override ARCH := x86
+ifeq ($(RAW_ARCH),i386)
+  ARCH ?= x86
 endif
 
-ifeq ($(ARCH),x86_64)
-  override ARCH := x86
-  IS_X86_64 := 0
-  ifeq (, $(findstring m32,$(CFLAGS)))
-    IS_X86_64 := $(shell echo __x86_64__ | ${CC} -E -x c - | tail -n 1)
-    RAW_ARCH := x86_64
+ifeq ($(RAW_ARCH),x86_64)
+  ARCH ?= x86
+
+  ifneq (, $(findstring m32,$(CFLAGS)))
+    RAW_ARCH := x86_32
   endif
 endif
 
-ifeq (${IS_X86_64}, 1)
+ARCH ?= $(RAW_ARCH)
+
+LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+ifeq ($(LP64), 1)
   IS_64_BIT := 1
-else ifeq ($(ARCH),x86)
-  IS_64_BIT := 0
 else
-  IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+  IS_64_BIT := 0
 endif
index a3b13d7dc1d43f3caf301b4d9f941c60d88ed37c..6ef68165c9db628d23bbe85b48945ac2581ec979 100644 (file)
@@ -6,7 +6,6 @@
 #include <sys/syscall.h>
 #include <linux/types.h>
 #include <linux/perf_event.h>
-#include <asm/unistd.h>
 
 #if defined(__i386__)
 #define mb()           asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
index 790ceba6ad3f4a4102a1affa81a637ef774d7d43..28431d1bbcf5768de83f93165f8bf9599ad0f087 100644 (file)
@@ -5,7 +5,10 @@
  *     ANY CHANGES MADE HERE WILL BE LOST! 
  *
  */
-
+#include <stdbool.h>
+#ifndef HAS_BOOL
+# define HAS_BOOL 1
+#endif
 #line 1 "Context.xs"
 /*
  * Context.xs.  XS interfaces for perf script.
index ab28cca2cb97ad436dd7c419ee4ee7fa37ecb0b9..0bf06bec68c7e9786668990ad399b578326726c5 100644 (file)
@@ -11,6 +11,9 @@
 #include "thread.h"
 #include "callchain.h"
 
+/* For bsearch. We try to unwind functions in shared object. */
+#include <stdlib.h>
+
 static int mmap_handler(struct perf_tool *tool __maybe_unused,
                        union perf_event *event,
                        struct perf_sample *sample __maybe_unused,
@@ -28,7 +31,7 @@ static int init_live_machine(struct machine *machine)
                                                  mmap_handler, machine, true);
 }
 
-#define MAX_STACK 6
+#define MAX_STACK 8
 
 static int unwind_entry(struct unwind_entry *entry, void *arg)
 {
@@ -37,6 +40,8 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
        static const char *funcs[MAX_STACK] = {
                "test__arch_unwind_sample",
                "unwind_thread",
+               "compare",
+               "bsearch",
                "krava_3",
                "krava_2",
                "krava_1",
@@ -88,10 +93,37 @@ static int unwind_thread(struct thread *thread)
        return err;
 }
 
+static int global_unwind_retval = -INT_MAX;
+
+__attribute__ ((noinline))
+static int compare(void *p1, void *p2)
+{
+       /* Any possible value should be 'thread' */
+       struct thread *thread = *(struct thread **)p1;
+
+       if (global_unwind_retval == -INT_MAX)
+               global_unwind_retval = unwind_thread(thread);
+
+       return p1 - p2;
+}
+
 __attribute__ ((noinline))
 static int krava_3(struct thread *thread)
 {
-       return unwind_thread(thread);
+       struct thread *array[2] = {thread, thread};
+       void *fp = &bsearch;
+       /*
+        * make _bsearch a volatile function pointer to
+        * prevent potential optimization, which may expand
+        * bsearch and call compare directly from this function,
+        * instead of libc shared object.
+        */
+       void *(*volatile _bsearch)(void *, void *, size_t,
+                       size_t, int (*)(void *, void *));
+
+       _bsearch = fp;
+       _bsearch(array, &thread, 2, sizeof(struct thread **), compare);
+       return global_unwind_retval;
 }
 
 __attribute__ ((noinline))
index 614d5c4978ab6509559eff9f275dc594310020f2..8d110dec393ee1a42f78cb1b440ea9d19f825e1c 100644 (file)
@@ -187,7 +187,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
         * function since TEST_ASSERT_VAL() returns in case of failure.
         */
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        if (verbose > 2) {
                pr_info("use callchain: %d, cumulate callchain: %d\n",
@@ -454,12 +454,12 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
         *   30.00%    10.00%     perf  perf           [.] cmd_record
         *   20.00%     0.00%     bash  libc           [.] malloc
         *   10.00%    10.00%     bash  [kernel]       [k] page_fault
-        *   10.00%    10.00%     perf  [kernel]       [k] schedule
-        *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
+        *   10.00%    10.00%     bash  bash           [.] xmalloc
         *   10.00%    10.00%     perf  [kernel]       [k] page_fault
-        *   10.00%    10.00%     perf  libc           [.] free
         *   10.00%    10.00%     perf  libc           [.] malloc
-        *   10.00%    10.00%     bash  bash           [.] xmalloc
+        *   10.00%    10.00%     perf  [kernel]       [k] schedule
+        *   10.00%    10.00%     perf  libc           [.] free
+        *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
         */
        struct result expected[] = {
                { 7000, 2000, "perf", "perf",     "main" },
@@ -468,12 +468,12 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
                { 3000, 1000, "perf", "perf",     "cmd_record" },
                { 2000,    0, "bash", "libc",     "malloc" },
                { 1000, 1000, "bash", "[kernel]", "page_fault" },
-               { 1000, 1000, "perf", "[kernel]", "schedule" },
-               { 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
+               { 1000, 1000, "bash", "bash",     "xmalloc" },
                { 1000, 1000, "perf", "[kernel]", "page_fault" },
+               { 1000, 1000, "perf", "[kernel]", "schedule" },
                { 1000, 1000, "perf", "libc",     "free" },
                { 1000, 1000, "perf", "libc",     "malloc" },
-               { 1000, 1000, "bash", "bash",     "xmalloc" },
+               { 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
        };
 
        symbol_conf.use_callchain = false;
@@ -537,10 +537,13 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
         *                  malloc
         *                  main
         *
-        *   10.00%    10.00%     perf  [kernel]       [k] schedule
+        *   10.00%    10.00%     bash  bash           [.] xmalloc
         *              |
-        *              --- schedule
-        *                  run_command
+        *              --- xmalloc
+        *                  malloc
+        *                  xmalloc     <--- NOTE: there's a cycle
+        *                  malloc
+        *                  xmalloc
         *                  main
         *
         *   10.00%     0.00%     perf  [kernel]       [k] sys_perf_event_open
@@ -556,6 +559,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
         *                  run_command
         *                  main
         *
+        *   10.00%    10.00%     perf  [kernel]       [k] schedule
+        *              |
+        *              --- schedule
+        *                  run_command
+        *                  main
+        *
         *   10.00%    10.00%     perf  libc           [.] free
         *              |
         *              --- free
@@ -570,15 +579,6 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
         *                  run_command
         *                  main
         *
-        *   10.00%    10.00%     bash  bash           [.] xmalloc
-        *              |
-        *              --- xmalloc
-        *                  malloc
-        *                  xmalloc     <--- NOTE: there's a cycle
-        *                  malloc
-        *                  xmalloc
-        *                  main
-        *
         */
        struct result expected[] = {
                { 7000, 2000, "perf", "perf",     "main" },
@@ -587,12 +587,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
                { 3000, 1000, "perf", "perf",     "cmd_record" },
                { 2000,    0, "bash", "libc",     "malloc" },
                { 1000, 1000, "bash", "[kernel]", "page_fault" },
-               { 1000, 1000, "perf", "[kernel]", "schedule" },
+               { 1000, 1000, "bash", "bash",     "xmalloc" },
                { 1000,    0, "perf", "[kernel]", "sys_perf_event_open" },
                { 1000, 1000, "perf", "[kernel]", "page_fault" },
+               { 1000, 1000, "perf", "[kernel]", "schedule" },
                { 1000, 1000, "perf", "libc",     "free" },
                { 1000, 1000, "perf", "libc",     "malloc" },
-               { 1000, 1000, "bash", "bash",     "xmalloc" },
        };
        struct callchain_result expected_callchain[] = {
                {
@@ -622,9 +622,12 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
                                { "bash",     "main" }, },
                },
                {
-                       3, {    { "[kernel]", "schedule" },
-                               { "perf",     "run_command" },
-                               { "perf",     "main" }, },
+                       6, {    { "bash",     "xmalloc" },
+                               { "libc",     "malloc" },
+                               { "bash",     "xmalloc" },
+                               { "libc",     "malloc" },
+                               { "bash",     "xmalloc" },
+                               { "bash",     "main" }, },
                },
                {
                        3, {    { "[kernel]", "sys_perf_event_open" },
@@ -637,6 +640,11 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
                                { "perf",     "run_command" },
                                { "perf",     "main" }, },
                },
+               {
+                       3, {    { "[kernel]", "schedule" },
+                               { "perf",     "run_command" },
+                               { "perf",     "main" }, },
+               },
                {
                        4, {    { "libc",     "free" },
                                { "perf",     "cmd_record" },
@@ -649,14 +657,6 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
                                { "perf",     "run_command" },
                                { "perf",     "main" }, },
                },
-               {
-                       6, {    { "bash",     "xmalloc" },
-                               { "libc",     "malloc" },
-                               { "bash",     "xmalloc" },
-                               { "libc",     "malloc" },
-                               { "bash",     "xmalloc" },
-                               { "bash",     "main" }, },
-               },
        };
 
        symbol_conf.use_callchain = true;
index 74f257a812653177f9d334d7a25df8359d8ef3d4..59e53db7914c0ad6100ab2e616cdf21e39efea46 100644 (file)
@@ -138,7 +138,7 @@ int test__hists_filter(void)
                struct hists *hists = evsel__hists(evsel);
 
                hists__collapse_resort(hists, NULL);
-               hists__output_resort(hists);
+               hists__output_resort(hists, NULL);
 
                if (verbose > 2) {
                        pr_info("Normal histogram\n");
index a748f2be1222e3d44791eebacaf8c53174a617bf..f5547610da0200b70c0bdc1a006adaee925eba73 100644 (file)
@@ -152,7 +152,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
                goto out;
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        if (verbose > 2) {
                pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -252,7 +252,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
                goto out;
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        if (verbose > 2) {
                pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -306,7 +306,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
                goto out;
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        if (verbose > 2) {
                pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -384,7 +384,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
                goto out;
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        if (verbose > 2) {
                pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -487,7 +487,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
                goto out;
 
        hists__collapse_resort(hists, NULL);
-       hists__output_resort(hists);
+       hists__output_resort(hists, NULL);
 
        if (verbose > 2) {
                pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
index e6bb04b5b09b863013e4d361120269d59f6207c6..788506eef5671da5e64016063569b79d4e060d97 100644 (file)
@@ -550,7 +550,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
        bool need_percent;
 
        node = rb_first(root);
-       need_percent = !!rb_next(node);
+       need_percent = node && rb_next(node);
 
        while (node) {
                struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
index dc0d095f318c7da2868352d5a4c048a5dde40251..482adae3cc44a50889bb2278b323a3b6871197c6 100644 (file)
@@ -204,6 +204,9 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
                if (ret)
                        return ret;
 
+               if (a->thread != b->thread || !symbol_conf.use_callchain)
+                       return 0;
+
                ret = b->callchain->max_depth - a->callchain->max_depth;
        }
        return ret;
index 2f612562978cdc13c7e89b6dbddd24c9f928d626..3c38f25b1695cdd289808d0d9f5ea858f06fc5db 100644 (file)
@@ -1,5 +1,8 @@
 #include <signal.h>
 #include <stdbool.h>
+#ifdef HAVE_BACKTRACE_SUPPORT
+#include <execinfo.h>
+#endif
 
 #include "../../util/cache.h"
 #include "../../util/debug.h"
@@ -88,6 +91,25 @@ int ui__getch(int delay_secs)
        return SLkp_getkey();
 }
 
+#ifdef HAVE_BACKTRACE_SUPPORT
+static void ui__signal_backtrace(int sig)
+{
+       void *stackdump[32];
+       size_t size;
+
+       ui__exit(false);
+       psignal(sig, "perf");
+
+       printf("-------- backtrace --------\n");
+       size = backtrace(stackdump, ARRAY_SIZE(stackdump));
+       backtrace_symbols_fd(stackdump, size, STDOUT_FILENO);
+
+       exit(0);
+}
+#else
+# define ui__signal_backtrace  ui__signal
+#endif
+
 static void ui__signal(int sig)
 {
        ui__exit(false);
@@ -122,8 +144,8 @@ int ui__init(void)
        ui_browser__init();
        tui_progress__init();
 
-       signal(SIGSEGV, ui__signal);
-       signal(SIGFPE, ui__signal);
+       signal(SIGSEGV, ui__signal_backtrace);
+       signal(SIGFPE, ui__signal_backtrace);
        signal(SIGINT, ui__signal);
        signal(SIGQUIT, ui__signal);
        signal(SIGTERM, ui__signal);
index 79999ceaf2be08e5f4880e853d467bf59874340c..01bc4e23a2cf58f1724c462706fee0e70234d2e0 100644 (file)
@@ -177,14 +177,17 @@ static int lock__parse(struct ins_operands *ops)
                goto out_free_ops;
 
        ops->locked.ins = ins__find(name);
+       free(name);
+
        if (ops->locked.ins == NULL)
                goto out_free_ops;
 
        if (!ops->locked.ins->ops)
                return 0;
 
-       if (ops->locked.ins->ops->parse)
-               ops->locked.ins->ops->parse(ops->locked.ops);
+       if (ops->locked.ins->ops->parse &&
+           ops->locked.ins->ops->parse(ops->locked.ops) < 0)
+               goto out_free_ops;
 
        return 0;
 
@@ -208,6 +211,13 @@ static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
 
 static void lock__delete(struct ins_operands *ops)
 {
+       struct ins *ins = ops->locked.ins;
+
+       if (ins && ins->ops->free)
+               ins->ops->free(ops->locked.ops);
+       else
+               ins__delete(ops->locked.ops);
+
        zfree(&ops->locked.ops);
        zfree(&ops->target.raw);
        zfree(&ops->target.name);
@@ -531,8 +541,8 @@ static void disasm_line__init_ins(struct disasm_line *dl)
        if (!dl->ins->ops)
                return;
 
-       if (dl->ins->ops->parse)
-               dl->ins->ops->parse(&dl->ops);
+       if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops) < 0)
+               dl->ins = NULL;
 }
 
 static int disasm_line__parse(char *line, char **namep, char **rawp)
index 0784a9420528603efa9450a8c72c78ebf271298a..cadbdc90a5cbf319385cb67aa5a88c06cdf107dc 100644 (file)
@@ -116,11 +116,6 @@ struct annotation {
        struct annotated_source *src;
 };
 
-struct sannotation {
-       struct annotation annotation;
-       struct symbol     symbol;
-};
-
 static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx)
 {
        return (((void *)&notes->src->histograms) +
@@ -129,8 +124,7 @@ static inline struct sym_hist *annotation__histogram(struct annotation *notes, i
 
 static inline struct annotation *symbol__annotation(struct symbol *sym)
 {
-       struct sannotation *a = container_of(sym, struct sannotation, symbol);
-       return &a->annotation;
+       return (void *)sym - symbol_conf.priv_size;
 }
 
 int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx);
index 5cf9e1b5989de40cb677b1bd744d684cd3bfc871..d04d770d90f6e29bc17d4d5d1299e76278b5ee1c 100644 (file)
@@ -71,7 +71,9 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
 extern char *perf_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 
+#ifndef __UCLIBC__
 /* Matches the libc/libbsd function attribute so we declare this unconditionally: */
 extern size_t strlcpy(char *dest, const char *src, size_t size);
+#endif
 
 #endif /* __PERF_CACHE_H */
index 64b377e591e457746138173cfa59533f887e3d56..14e7a123d43b3f4ab4e04a5aba7448bd5d1106cd 100644 (file)
@@ -841,3 +841,33 @@ char *callchain_list__sym_name(struct callchain_list *cl,
 
        return bf;
 }
+
+static void free_callchain_node(struct callchain_node *node)
+{
+       struct callchain_list *list, *tmp;
+       struct callchain_node *child;
+       struct rb_node *n;
+
+       list_for_each_entry_safe(list, tmp, &node->val, list) {
+               list_del(&list->list);
+               free(list);
+       }
+
+       n = rb_first(&node->rb_root_in);
+       while (n) {
+               child = container_of(n, struct callchain_node, rb_node_in);
+               n = rb_next(n);
+               rb_erase(&child->rb_node_in, &node->rb_root_in);
+
+               free_callchain_node(child);
+               free(child);
+       }
+}
+
+void free_callchain(struct callchain_root *root)
+{
+       if (!symbol_conf.use_callchain)
+               return;
+
+       free_callchain_node(&root->node);
+}
index dbc08cf5f970a2f25e9451ca5e259a38f5cdbfe1..c0ec1acc38e404aa599b5b6635d004ac2f0e204f 100644 (file)
@@ -198,4 +198,6 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
 char *callchain_list__sym_name(struct callchain_list *cl,
                               char *bf, size_t bfsize, bool show_dso);
 
+void free_callchain(struct callchain_root *root);
+
 #endif /* __PERF_CALLCHAIN_H */
index cbab1fb77b1d6c4efb8565144256e6f1c5a6d540..2e507b5025a3ed6e3f3df1e385aa3c8f13637389 100644 (file)
@@ -1445,7 +1445,7 @@ int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused,
        case ENOENT:
                scnprintf(buf, size, "%s",
                          "Error:\tUnable to find debugfs\n"
-                         "Hint:\tWas your kernel was compiled with debugfs support?\n"
+                         "Hint:\tWas your kernel compiled with debugfs support?\n"
                          "Hint:\tIs the debugfs filesystem mounted?\n"
                          "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
                break;
index 6e88b9e395df67abb0458eea80878112acab0b0a..182395546ddca63d919886f4b49896fbdd46e3e2 100644 (file)
@@ -6,6 +6,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "annotate.h"
+#include "ui/progress.h"
 #include <math.h>
 
 static bool hists__filter_entry_by_dso(struct hists *hists,
@@ -303,7 +304,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
        size_t callchain_size = 0;
        struct hist_entry *he;
 
-       if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain)
+       if (symbol_conf.use_callchain)
                callchain_size = sizeof(struct callchain_root);
 
        he = zalloc(sizeof(*he) + callchain_size);
@@ -736,7 +737,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
        iter->he = he;
        he_cache[iter->curr++] = he;
 
-       callchain_append(he->callchain, &callchain_cursor, sample->period);
+       hist_entry__append_callchain(he, sample);
 
        /*
         * We need to re-initialize the cursor since callchain_append()
@@ -809,7 +810,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
        iter->he = he;
        he_cache[iter->curr++] = he;
 
-       callchain_append(he->callchain, &cursor, sample->period);
+       if (symbol_conf.use_callchain)
+               callchain_append(he->callchain, &cursor, sample->period);
        return 0;
 }
 
@@ -945,6 +947,7 @@ void hist_entry__free(struct hist_entry *he)
        zfree(&he->mem_info);
        zfree(&he->stat_acc);
        free_srcline(he->srcline);
+       free_callchain(he->callchain);
        free(he);
 }
 
@@ -987,6 +990,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
                else
                        p = &(*p)->rb_right;
        }
+       hists->nr_entries++;
 
        rb_link_node(&he->rb_node_in, parent, p);
        rb_insert_color(&he->rb_node_in, root);
@@ -1024,7 +1028,10 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
        if (!sort__need_collapse)
                return;
 
+       hists->nr_entries = 0;
+
        root = hists__get_rotate_entries_in(hists);
+
        next = rb_first(root);
 
        while (next) {
@@ -1119,7 +1126,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
        rb_insert_color(&he->rb_node, entries);
 }
 
-void hists__output_resort(struct hists *hists)
+void hists__output_resort(struct hists *hists, struct ui_progress *prog)
 {
        struct rb_root *root;
        struct rb_node *next;
@@ -1148,6 +1155,9 @@ void hists__output_resort(struct hists *hists)
 
                if (!n->filtered)
                        hists__calc_col_len(hists, n);
+
+               if (prog)
+                       ui_progress__update(prog, 1);
        }
 }
 
index d0ef9a19a7445caaf7bdc1d21b42ea2d1087a2a9..46bd50344f853f8f55f43bc23cd95f8459e53cab 100644 (file)
@@ -121,7 +121,7 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
                              struct hists *hists);
 void hist_entry__free(struct hist_entry *);
 
-void hists__output_resort(struct hists *hists);
+void hists__output_resort(struct hists *hists, struct ui_progress *prog);
 void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
 
 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
diff --git a/tools/perf/util/hweight.c b/tools/perf/util/hweight.c
deleted file mode 100644 (file)
index 5c1d0d0..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <linux/bitops.h>
-
-/**
- * hweightN - returns the hamming weight of a N-bit word
- * @x: the word to weigh
- *
- * The Hamming Weight of a number is the total number of bits set in it.
- */
-
-unsigned int hweight32(unsigned int w)
-{
-       unsigned int res = w - ((w >> 1) & 0x55555555);
-       res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
-       res = (res + (res >> 4)) & 0x0F0F0F0F;
-       res = res + (res >> 8);
-       return (res + (res >> 16)) & 0x000000FF;
-}
-
-unsigned long hweight64(__u64 w)
-{
-#if BITS_PER_LONG == 32
-       return hweight32((unsigned int)(w >> 32)) + hweight32((unsigned int)w);
-#elif BITS_PER_LONG == 64
-       __u64 res = w - ((w >> 1) & 0x5555555555555555ul);
-       res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul);
-       res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful;
-       res = res + (res >> 8);
-       res = res + (res >> 16);
-       return (res + (res >> 32)) & 0x00000000000000FFul;
-#endif
-}
diff --git a/tools/perf/util/include/asm/hweight.h b/tools/perf/util/include/asm/hweight.h
deleted file mode 100644 (file)
index 36cf26d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef PERF_HWEIGHT_H
-#define PERF_HWEIGHT_H
-
-#include <linux/types.h>
-unsigned int hweight32(unsigned int w);
-unsigned long hweight64(__u64 w);
-
-#endif /* PERF_HWEIGHT_H */
index 94de3e48b4909a03a7e7037f779074e5bf31ff8a..1bca3a9f2b16bc91670f731e05564680d2f12a10 100644 (file)
@@ -389,7 +389,6 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
        if (th != NULL) {
                rb_link_node(&th->rb_node, parent, p);
                rb_insert_color(&th->rb_node, &machine->threads);
-               machine->last_match = th;
 
                /*
                 * We have to initialize map_groups separately
@@ -400,9 +399,12 @@ static struct thread *__machine__findnew_thread(struct machine *machine,
                 * leader and that would screwed the rb tree.
                 */
                if (thread__init_map_groups(th, machine)) {
+                       rb_erase(&th->rb_node, &machine->threads);
                        thread__delete(th);
                        return NULL;
                }
+
+               machine->last_match = th;
        }
 
        return th;
index 6951a9d42339ee089c67dd068622f41c64f4670b..0e42438b1e593c0e6369186d84cc1ccad76a0093 100644 (file)
@@ -116,6 +116,22 @@ struct thread;
 #define map__for_each_symbol(map, pos, n)      \
        dso__for_each_symbol(map->dso, pos, n, map->type)
 
+/* map__for_each_symbol_with_name - iterate over the symbols in the given map
+ *                                  that have the given name
+ *
+ * @map: the 'struct map *' in which symbols itereated
+ * @sym_name: the symbol name
+ * @pos: the 'struct symbol *' to use as a loop cursor
+ * @filter: to use when loading the DSO
+ */
+#define __map__for_each_symbol_by_name(map, sym_name, pos, filter)     \
+       for (pos = map__find_symbol_by_name(map, sym_name, filter);     \
+            pos && strcmp(pos->name, sym_name) == 0;           \
+            pos = symbol__next_by_name(pos))
+
+#define map__for_each_symbol_by_name(map, sym_name, pos)               \
+       __map__for_each_symbol_by_name(map, sym_name, (pos), NULL)
+
 typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 
 void map__init(struct map *map, enum map_type type,
index 28eb1417cb2a3fc5d3acebc2280cf37ac79ad778..919937eb0be2b643e93bfe7fc983e7131074deeb 100644 (file)
@@ -446,7 +446,7 @@ static int post_process_probe_trace_events(struct probe_trace_event *tevs,
        }
 
        for (i = 0; i < ntevs; i++) {
-               if (tevs[i].point.address) {
+               if (tevs[i].point.address && !tevs[i].point.retprobe) {
                        tmp = strdup(reloc_sym->name);
                        if (!tmp)
                                return -ENOMEM;
@@ -495,9 +495,11 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
        }
 
        if (ntevs == 0) {       /* No error but failed to find probe point. */
-               pr_warning("Probe point '%s' not found.\n",
+               pr_warning("Probe point '%s' not found in debuginfo.\n",
                           synthesize_perf_probe_point(&pev->point));
-               return -ENOENT;
+               if (need_dwarf)
+                       return -ENOENT;
+               return 0;
        }
        /* Error path : ntevs < 0 */
        pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
@@ -2050,9 +2052,11 @@ static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
        pr_debug("Writing event: %s\n", buf);
        if (!probe_event_dry_run) {
                ret = write(fd, buf, strlen(buf));
-               if (ret <= 0)
+               if (ret <= 0) {
+                       ret = -errno;
                        pr_warning("Failed to write event: %s\n",
                                   strerror_r(errno, sbuf, sizeof(sbuf)));
+               }
        }
        free(buf);
        return ret;
@@ -2189,18 +2193,17 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
        return ret;
 }
 
-static char *looking_function_name;
-static int num_matched_functions;
-
-static int probe_function_filter(struct map *map __maybe_unused,
-                                     struct symbol *sym)
+static int find_probe_functions(struct map *map, char *name)
 {
-       if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
-           strcmp(looking_function_name, sym->name) == 0) {
-               num_matched_functions++;
-               return 0;
+       int found = 0;
+       struct symbol *sym;
+
+       map__for_each_symbol_by_name(map, name, sym) {
+               if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL)
+                       found++;
        }
-       return 1;
+
+       return found;
 }
 
 #define strdup_or_goto(str, label)     \
@@ -2218,10 +2221,10 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
        struct kmap *kmap = NULL;
        struct ref_reloc_sym *reloc_sym = NULL;
        struct symbol *sym;
-       struct rb_node *nd;
        struct probe_trace_event *tev;
        struct perf_probe_point *pp = &pev->point;
        struct probe_trace_point *tp;
+       int num_matched_functions;
        int ret, i;
 
        /* Init maps of given executable or kernel */
@@ -2238,10 +2241,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
         * Load matched symbols: Since the different local symbols may have
         * same name but different addresses, this lists all the symbols.
         */
-       num_matched_functions = 0;
-       looking_function_name = pp->function;
-       ret = map__load(map, probe_function_filter);
-       if (ret || num_matched_functions == 0) {
+       num_matched_functions = find_probe_functions(map, pp->function);
+       if (num_matched_functions == 0) {
                pr_err("Failed to find symbol %s in %s\n", pp->function,
                        target ? : "kernel");
                ret = -ENOENT;
@@ -2253,7 +2254,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
                goto out;
        }
 
-       if (!pev->uprobes) {
+       if (!pev->uprobes && !pp->retprobe) {
                kmap = map__kmap(map);
                reloc_sym = kmap->ref_reloc_sym;
                if (!reloc_sym) {
@@ -2271,7 +2272,8 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
        }
 
        ret = 0;
-       map__for_each_symbol(map, sym, nd) {
+
+       map__for_each_symbol_by_name(map, pp->function, sym) {
                tev = (*tevs) + ret;
                tp = &tev->point;
                if (ret == num_matched_functions) {
index c7918f83b300086649f522bc5f663d9a5a88a5dc..b5247d777f0e9348d1b77e3f33813c5b7713bce4 100644 (file)
@@ -989,8 +989,24 @@ static int debuginfo__find_probes(struct debuginfo *dbg,
        int ret = 0;
 
 #if _ELFUTILS_PREREQ(0, 142)
+       Elf *elf;
+       GElf_Ehdr ehdr;
+       GElf_Shdr shdr;
+
        /* Get the call frame information from this dwarf */
-       pf->cfi = dwarf_getcfi_elf(dwarf_getelf(dbg->dbg));
+       elf = dwarf_getelf(dbg->dbg);
+       if (elf == NULL)
+               return -EINVAL;
+
+       if (gelf_getehdr(elf, &ehdr) == NULL)
+               return -EINVAL;
+
+       if (elf_section_by_name(elf, &ehdr, &shdr, ".eh_frame", NULL) &&
+           shdr.sh_type == SHT_PROGBITS) {
+               pf->cfi = dwarf_getcfi_elf(elf);
+       } else {
+               pf->cfi = dwarf_getcfi(dbg->dbg);
+       }
 #endif
 
        off = 0;
index 16a475a7d492177623062143434488116cdf2a38..6c6a6953fa93fa5b4fe92229df7613bbe996bec9 100644 (file)
@@ -10,7 +10,7 @@ util/ctype.c
 util/evlist.c
 util/evsel.c
 util/cpumap.c
-util/hweight.c
+../../lib/hweight.c
 util/thread_map.c
 util/util.c
 util/xyarray.c
index c24c5b83156cd92ec5ba5c457153e43706b81424..a194702a0a2f5af700a3177832823502e4d383d7 100644 (file)
@@ -396,6 +396,7 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
                                            const char *name)
 {
        struct rb_node *n;
+       struct symbol_name_rb_node *s;
 
        if (symbols == NULL)
                return NULL;
@@ -403,7 +404,6 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
        n = symbols->rb_node;
 
        while (n) {
-               struct symbol_name_rb_node *s;
                int cmp;
 
                s = rb_entry(n, struct symbol_name_rb_node, rb_node);
@@ -414,10 +414,24 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols,
                else if (cmp > 0)
                        n = n->rb_right;
                else
-                       return &s->sym;
+                       break;
        }
 
-       return NULL;
+       if (n == NULL)
+               return NULL;
+
+       /* return first symbol that has same name (if any) */
+       for (n = rb_prev(n); n; n = rb_prev(n)) {
+               struct symbol_name_rb_node *tmp;
+
+               tmp = rb_entry(n, struct symbol_name_rb_node, rb_node);
+               if (strcmp(tmp->sym.name, s->sym.name))
+                       break;
+
+               s = tmp;
+       }
+
+       return &s->sym;
 }
 
 struct symbol *dso__find_symbol(struct dso *dso,
@@ -436,6 +450,17 @@ struct symbol *dso__next_symbol(struct symbol *sym)
        return symbols__next(sym);
 }
 
+struct symbol *symbol__next_by_name(struct symbol *sym)
+{
+       struct symbol_name_rb_node *s = container_of(sym, struct symbol_name_rb_node, sym);
+       struct rb_node *n = rb_next(&s->rb_node);
+
+       return n ? &rb_entry(n, struct symbol_name_rb_node, rb_node)->sym : NULL;
+}
+
+ /*
+  * Teturns first symbol that matched with @name.
+  */
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
                                        const char *name)
 {
index 9d602e9c6f590f73eb9413f53bbbceeada64b20d..1650dcb3a67bc3fddff40c93c6fdf6a1122d185a 100644 (file)
@@ -231,6 +231,7 @@ struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
                                u64 addr);
 struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
                                        const char *name);
+struct symbol *symbol__next_by_name(struct symbol *sym);
 
 struct symbol *dso__first_symbol(struct dso *dso, enum map_type type);
 struct symbol *dso__next_symbol(struct symbol *sym);
index 371219a6daf1cd8209687115bca9a67f7ffc3209..6edf535f65c23428b4982fb651ba3df997d55dfb 100644 (file)
@@ -185,6 +185,28 @@ static u64 elf_section_offset(int fd, const char *name)
        return offset;
 }
 
+#ifndef NO_LIBUNWIND_DEBUG_FRAME
+static int elf_is_exec(int fd, const char *name)
+{
+       Elf *elf;
+       GElf_Ehdr ehdr;
+       int retval = 0;
+
+       elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
+       if (elf == NULL)
+               return 0;
+       if (gelf_getehdr(elf, &ehdr) == NULL)
+               goto out;
+
+       retval = (ehdr.e_type == ET_EXEC);
+
+out:
+       elf_end(elf);
+       pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval);
+       return retval;
+}
+#endif
+
 struct table_entry {
        u32 start_ip_offset;
        u32 fde_offset;
@@ -322,8 +344,12 @@ find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
 #ifndef NO_LIBUNWIND_DEBUG_FRAME
        /* Check the .debug_frame section for unwinding info */
        if (!read_unwind_spec_debug_frame(map->dso, ui->machine, &segbase)) {
+               int fd = dso__data_fd(map->dso, ui->machine);
+               int is_exec = elf_is_exec(fd, map->dso->name);
+               unw_word_t base = is_exec ? 0 : map->start;
+
                memset(&di, 0, sizeof(di));
-               if (dwarf_find_debug_frame(0, &di, ip, 0, map->dso->name,
+               if (dwarf_find_debug_frame(0, &di, ip, base, map->dso->name,
                                           map->start, map->end))
                        return dwarf_search_unwind_table(as, ip, &di, pi,
                                                         need_unwind_info, arg);
index 7cdcf88659c77d75196b3e078b89b657bf53a26a..9ea91437898598bf31982f6073ec483e3d51f687 100644 (file)
@@ -199,7 +199,7 @@ int main(int argc, const char *argv[])
        }
 
        get_cpu_info(0, &cpupower_cpu_info);
-       run_as_root = !getuid();
+       run_as_root = !geteuid();
        if (run_as_root) {
                ret = uname(&uts);
                if (!ret && !strcmp(uts.machine, "x86_64") &&
index 09afe5d87f2bbe34387e1257cfcc67bd5d16d4dc..4e8fe2c7b05475ca8e6d015dd20228c5a53b957f 100644 (file)
@@ -361,7 +361,7 @@ unsigned int sysfs_get_idlestate_count(unsigned int cpu)
 
        snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
        if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
-               return -ENODEV;
+               return 0;
 
        snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
        if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
index 33a5c06d95caa038f682c411ad26df0788d16f5b..e238c9559caf9a7757d2d389e0bda57cd73229a8 100644 (file)
@@ -62,7 +62,7 @@ static int _check_execveat_fail(int fd, const char *path, int flags,
 }
 
 static int check_execveat_invoked_rc(int fd, const char *path, int flags,
-                                    int expected_rc)
+                                    int expected_rc, int expected_rc2)
 {
        int status;
        int rc;
@@ -98,9 +98,10 @@ static int check_execveat_invoked_rc(int fd, const char *path, int flags,
                        child, status);
                return 1;
        }
-       if (WEXITSTATUS(status) != expected_rc) {
-               printf("[FAIL] (child %d exited with %d not %d)\n",
-                       child, WEXITSTATUS(status), expected_rc);
+       if ((WEXITSTATUS(status) != expected_rc) &&
+           (WEXITSTATUS(status) != expected_rc2)) {
+               printf("[FAIL] (child %d exited with %d not %d nor %d)\n",
+                       child, WEXITSTATUS(status), expected_rc, expected_rc2);
                return 1;
        }
        printf("[OK]\n");
@@ -109,7 +110,7 @@ static int check_execveat_invoked_rc(int fd, const char *path, int flags,
 
 static int check_execveat(int fd, const char *path, int flags)
 {
-       return check_execveat_invoked_rc(fd, path, flags, 99);
+       return check_execveat_invoked_rc(fd, path, flags, 99, 99);
 }
 
 static char *concat(const char *left, const char *right)
@@ -179,11 +180,11 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script)
         */
        fd = open(longpath, O_RDONLY);
        if (fd > 0) {
-               printf("Invoke copy of '%s' via filename of length %lu:\n",
+               printf("Invoke copy of '%s' via filename of length %zu:\n",
                        src, strlen(longpath));
                fail += check_execveat(fd, "", AT_EMPTY_PATH);
        } else {
-               printf("Failed to open length %lu filename, errno=%d (%s)\n",
+               printf("Failed to open length %zu filename, errno=%d (%s)\n",
                        strlen(longpath), errno, strerror(errno));
                fail++;
        }
@@ -192,9 +193,15 @@ static int check_execveat_pathmax(int dot_dfd, const char *src, int is_script)
         * Execute as a long pathname relative to ".".  If this is a script,
         * the interpreter will launch but fail to open the script because its
         * name ("/dev/fd/5/xxx....") is bigger than PATH_MAX.
+        *
+        * The failure code is usually 127 (POSIX: "If a command is not found,
+        * the exit status shall be 127."), but some systems give 126 (POSIX:
+        * "If the command name is found, but it is not an executable utility,
+        * the exit status shall be 126."), so allow either.
         */
        if (is_script)
-               fail += check_execveat_invoked_rc(dot_dfd, longpath, 0, 127);
+               fail += check_execveat_invoked_rc(dot_dfd, longpath, 0,
+                                                 127, 126);
        else
                fail += check_execveat(dot_dfd, longpath, 0);
 
index 94dae65eea4183b43bf3e52bf9bf22dc9c0d4471..8519e9ee97e3d3e4a344e798cabf5b38edfff602 100644 (file)
@@ -536,10 +536,9 @@ int main(int argc, char *argv[])
 {
        struct mq_attr attr;
        char *option, *next_option;
-       int i, cpu;
+       int i, cpu, rc;
        struct sigaction sa;
        poptContext popt_context;
-       char rc;
        void *retval;
 
        main_thread = pthread_self();
index 4c4b1f631ecf61f6e3048d746c23be39ea4f2ef9..077828c889f1377886b98c93349919d55ccb57a2 100644 (file)
@@ -7,7 +7,7 @@ BINARIES += transhuge-stress
 
 all: $(BINARIES)
 %: %.c
-       $(CC) $(CFLAGS) -o $@ $^
+       $(CC) $(CFLAGS) -o $@ $^ -lrt
 
 run_tests: all
        @/bin/sh ./run_vmtests || (echo "vmtests: [FAIL]"; exit 1)
index f5283438ee05e165b50b693c2d864f248d82a90d..1cc6e2e199827093093e6c48eab72c6531136a13 100644 (file)
@@ -671,6 +671,7 @@ static void update_memslots(struct kvm_memslots *slots,
 
        WARN_ON(mslots[i].id != id);
        if (!new->npages) {
+               WARN_ON(!mslots[i].npages);
                new->base_gfn = 0;
                if (mslots[i].npages)
                        slots->used_slots--;
@@ -687,12 +688,25 @@ static void update_memslots(struct kvm_memslots *slots,
                slots->id_to_index[mslots[i].id] = i;
                i++;
        }
-       while (i > 0 &&
-              new->base_gfn > mslots[i - 1].base_gfn) {
-               mslots[i] = mslots[i - 1];
-               slots->id_to_index[mslots[i].id] = i;
-               i--;
-       }
+
+       /*
+        * The ">=" is needed when creating a slot with base_gfn == 0,
+        * so that it moves before all those with base_gfn == npages == 0.
+        *
+        * On the other hand, if new->npages is zero, the above loop has
+        * already left i pointing to the beginning of the empty part of
+        * mslots, and the ">=" would move the hole backwards in this
+        * case---which is wrong.  So skip the loop when deleting a slot.
+        */
+       if (new->npages) {
+               while (i > 0 &&
+                      new->base_gfn >= mslots[i - 1].base_gfn) {
+                       mslots[i] = mslots[i - 1];
+                       slots->id_to_index[mslots[i].id] = i;
+                       i--;
+               }
+       } else
+               WARN_ON_ONCE(i != slots->used_slots);
 
        mslots[i] = *new;
        slots->id_to_index[mslots[i].id] = i;